Yet another workaround Thai \n problem (same as txtlib)

Bug: skia:10881

Change-Id: If451b662646e66e5d699ca0cca3795f5e078b84e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/332257
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Julia Lavrova <jlavrova@google.com>
diff --git a/modules/skparagraph/samples/SampleParagraph.cpp b/modules/skparagraph/samples/SampleParagraph.cpp
index 5d95400..ebb8870 100644
--- a/modules/skparagraph/samples/SampleParagraph.cpp
+++ b/modules/skparagraph/samples/SampleParagraph.cpp
@@ -3122,6 +3122,36 @@
     using INHERITED = Sample;
 };
 
+class ParagraphView51 : public ParagraphView_Base {
+protected:
+    SkString name() override { return SkString("Paragraph51"); }
+
+    void onDrawContent(SkCanvas* canvas) override {
+        canvas->clear(SK_ColorWHITE);
+
+        auto fontCollection = sk_make_sp<FontCollection>();
+        fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
+        fontCollection->enableFontFallback();
+
+        ParagraphStyle paragraph_style;
+        TextStyle text_style;
+        text_style.setColor(SK_ColorBLACK);
+        text_style.setFontFamilies({SkString("Roboto")});
+        text_style.setFontSize(16);
+        ParagraphBuilderImpl builder(paragraph_style, fontCollection);
+        builder.pushStyle(text_style);
+        builder.addText(u"\u0e41\u0e2a\u0e19\u0e2a\u0e31\nabc");
+        builder.pop();
+        auto paragraph = builder.Build();
+        paragraph->layout(1000);
+        paragraph->paint(canvas, 0, 0);
+    }
+
+private:
+    using INHERITED = Sample;
+};
+
+
 }  // namespace
 
 //////////////////////////////////////////////////////////////////////////////
@@ -3173,3 +3203,4 @@
 DEF_SAMPLE(return new ParagraphView48();)
 DEF_SAMPLE(return new ParagraphView49();)
 DEF_SAMPLE(return new ParagraphView50();)
+DEF_SAMPLE(return new ParagraphView51();)
diff --git a/modules/skparagraph/test.html b/modules/skparagraph/test.html
index 31616cf..b488ee0 100644
--- a/modules/skparagraph/test.html
+++ b/modules/skparagraph/test.html
@@ -27,8 +27,8 @@
   </div>
 -->
 <div style="width:10mm; height: 100mm;"></div>
-  <div style="text-align: left; background-color: lightgray; color: darkblue;font-family: Roboto; font-size: 30mm; " >
-    >Sͬ͑̀͐̈͒̈́̋̎ͮͩ̽̓ͬ̂̆̔͗́̓ͣͧ͊ͫ͛̉͌̐̑ͪ͗̚͝҉̴͉͢k̡̊̓ͫͭͩ͂͊ͨͪͬ̑ͫ̍̌̄͛̌̂̑̂̋̊̔ͫ͛̽̑ͨ̍ͭ̓̀ͪͪ̉͐͗̌̓̃̚͟͝҉̢͏̫̞̙͇͖̮͕̗̟͕͇͚̻͈̣̻̪͉̰̲̣̫ͅͅP̴̅̍͒̿͗͗̇ͩ̃͆͌̀̽͏̧̡͕͖̝̖̼̺̰̣̬͔͖͔̼͙̞̦̫͓̘͜a̸̴̸̴̢̢̨̨̫͍͓̥̼̭̼̻̤̯̙̤̻̠͚̍̌͋̂ͦͨ̽̇͌͌͆̀̽̎͒̄ͪ̐ͦ̈ͫ͐͗̓̚̚͜ͅr͐͐ͤͫ̐ͥ͂̈́̿́ͮ̃͗̓̏ͫ̀̿͏̸̵̧́͘̕͟͝͠͞͠҉̷̧͚͢͟a̓̽̎̄͗̔͛̄̐͊͛ͫ͂͌̂̂̈̈̓̔̅̅̄͊̉́ͪ̑̄͆ͬ̍͆ͭ͋̐ͬ͏̷̵̨̢̩̹̖͓̥̳̰͔̱̬͖̙͓̙͇̀̀̕͜͟͟͢͟͜͠͡g̨̅̇ͦ͋̂ͦͨͭ̓͐͆̏̂͛̉ͧ̑ͫ̐̒͛ͫ̍̒͛́̚҉̷̨̛̛̀͜͢͞҉̩̘̲͍͎̯̹̝̭̗̱͇͉̲̱͔̯̠̹̥̻͉̲̜̤̰̪̗̺̖̺r̷͌̓̇̅ͭ̀̐̃̃ͭ͑͗̉̈̇̈́ͥ̓ͣ́ͤ͂ͤ͂̏͌̆̚҉̴̸̧̢̢̛̫͉̦̥̤̙͈͉͈͉͓̙̗̟̳̜͈̗̺̟̠̠͖͓̖̪͕̠̕̕͝ͅả̸̴̡̡̧͠͞͡͞҉̛̕͟͏̷̘̪̱͈̲͉̞̠̞̪̫͎̲̬̖̀̀͟͝͞͞͠p̛͂̈͐̚͠҉̵̸̡̢̢̩̹͙̯͖̙̙̮̥̙͚̠͔̥̭̮̞̣̪̬̥̠̖̝̥̪͎́̀̕͜͡͡ͅͅh̵̷̵̡̛ͤ̂͌̐̓̐̋̋͊̒̆̽́̀̀̀͢͠͞͞҉̷̸̢̕҉͚̯͖̫̜̞̟̠̱͉̝̲̹̼͉̟͉̩̮͔̤͖̞̭̙̹̬ͅ<
+  <div style="text-align: left; background-color: lightgray; color: darkblue;font-family: Roboto; font-size: 130mm; " >
+แสธสั
   </div>
 
 </body>
diff --git a/modules/skshaper/src/SkUnicode_icu.cpp b/modules/skshaper/src/SkUnicode_icu.cpp
index 806900d..7636fdd 100644
--- a/modules/skshaper/src/SkUnicode_icu.cpp
+++ b/modules/skshaper/src/SkUnicode_icu.cpp
@@ -305,7 +305,7 @@
     }
 
     static bool extractPositions
-        (const char utf8[], int utf8Units, BreakType type, std::function<void(int, int)> add) {
+        (const char utf8[], int utf8Units, BreakType type, std::function<void(int, int)> setBreak) {
 
         UErrorCode status = U_ZERO_ERROR;
         UText sUtf8UText = UTEXT_INITIALIZER;
@@ -331,9 +331,27 @@
         auto iter = iterator.get();
         int32_t pos = ubrk_first(iter);
         while (pos != UBRK_DONE) {
-            add(pos, ubrk_getRuleStatus(iter));
+            auto status = type == SkUnicode::BreakType::kLines
+                              ? UBRK_LINE_SOFT
+                              : ubrk_getRuleStatus(iter);
+            setBreak(pos, status);
             pos = ubrk_next(iter);
         }
+
+        if (type == SkUnicode::BreakType::kLines) {
+            // This is a workaround for https://bugs.chromium.org/p/skia/issues/detail?id=10715
+            // (ICU line break iterator does not work correctly on Thai text with new lines)
+            // So, we only use the iterator to collect soft line breaks and
+            // scan the text for all hard line breaks ourselves
+            const char* end = utf8 + utf8Units;
+            const char* ch = utf8;
+            while (ch < end) {
+                auto unichar = utf8_next(&ch, end);
+                if (isHardLineBreak(unichar)) {
+                    setBreak(ch - utf8, UBRK_LINE_HARD);
+                }
+            }
+        }
         return true;
     }
 
@@ -409,6 +427,11 @@
         return u_isWhitespace(utf8);
     }
 
+    static bool isHardLineBreak(SkUnichar utf8) {
+        auto property = u_getIntPropertyValue(utf8, UCHAR_LINE_BREAK);
+        return property == U_LB_LINE_FEED || property == U_LB_MANDATORY_BREAK;
+    }
+
     SkString convertUtf16ToUtf8(const std::u16string& utf16) override {
         std::unique_ptr<char[]> utf8;
         auto utf8Units = SkUnicode_icu::utf16ToUtf8((uint16_t*)utf16.data(), utf16.size(), &utf8);
@@ -432,7 +455,7 @@
 
         return extractPositions(utf8, utf8Units, BreakType::kLines,
             [results](int pos, int status) {
-                    results->emplace_back(pos,status == UBRK_LINE_HARD
+                    results->emplace_back(pos, status == UBRK_LINE_HARD
                                                         ? LineBreakType::kHardLineBreak
                                                         : LineBreakType::kSoftLineBreak);
         });