Fix ZWJ, ZWNJ issues 45/264845/10
authorBowon Ryu <bowon.ryu@samsung.com>
Fri, 1 Oct 2021 04:20:55 +0000 (13:20 +0900)
committerBowon Ryu <bowon.ryu@samsung.com>
Wed, 13 Oct 2021 09:44:51 +0000 (18:44 +0900)
Current font load logic classifies ZWJ, ZWNJ as COMMON script.
This interrupts them from being combined into one emoji in the EMOJI + ZWJ + EMOJI case.

This patch treats ZWJ, ZWNJ as EMOJI script in this case,
so that they can be loaded with the same color emoji font.

Please refer the example below.
The expected result is to be combined into one emoji character due to ZWJ.
But the actual result is 3 characters rendered.

// example
TextLabel label = TextLabel::New("&#x1f469;&#x200d;&#x1f52c;");

Change-Id: Ic8e921ffcb63c27638afe781527b5c6b90aa92b1
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/internal/text/multi-language-support-impl.cpp

index 5495c9da7a520b1aef2edb4fd77d173162845855..c9453e153f6a005b5abdeef4358cee6f5d40b77a 100644 (file)
@@ -836,6 +836,13 @@ int UtcDaliToolkitTextLabelEmojisP(void)
   application.SendNotification();
   application.Render();
 
+  // EMOJI + ZWJ + EMOJI case for coverage.
+  const std::string emojiWithZWJ = "&#x1f469;&#x200d;&#x1f52c;";
+  label.SetProperty( TextLabel::Property::TEXT, emojiWithZWJ );
+
+  application.SendNotification();
+  application.Render();
+
   END_TEST;
 }
 
index a0e6ae5ebb27799b90c47c8d5d6069eb4b334584..82470f8de4c0ff027b359f0e4001ec6cae6688d8 100644 (file)
@@ -228,7 +228,8 @@ void MultilanguageSupport::SetScripts(const Vector<Character>& text,
       // Check if whether is right to left markup and Keeps true if the previous value was true.
       currentScriptRun.isRightToLeft = currentScriptRun.isRightToLeft || TextAbstraction::IsRightToLeftMark(character);
 
-      if(TextAbstraction::EMOJI == currentScriptRun.script)
+      // ZWJ, ZWNJ between emojis should be treated as EMOJI.
+      if(TextAbstraction::EMOJI == currentScriptRun.script && !(TextAbstraction::IsZeroWidthJoiner(character) || TextAbstraction::IsZeroWidthNonJoiner(character)))
       {
         // Emojis doesn't mix well with characters common to all scripts. Insert the emoji run.
         scripts.Insert(scripts.Begin() + scriptIndex, currentScriptRun);
@@ -444,7 +445,8 @@ void MultilanguageSupport::ValidateFonts(const Vector<Character>&
   Vector<ScriptRun>::ConstIterator scriptRunEndIt          = scripts.End();
   bool                             isNewParagraphCharacter = false;
 
-  bool isPreviousEmojiScript = false;
+  bool   isPreviousEmojiScript = false;
+  FontId previousEmojiFontId   = 0u;
 
   CharacterIndex lastCharacter = startIndex + numberOfCharacters;
   for(Length index = startIndex; index < lastCharacter; ++index)
@@ -535,6 +537,16 @@ void MultilanguageSupport::ValidateFonts(const Vector<Character>&
       currentFontRun.isBoldRequired                  = false;
     }
 
+    // ZWJ, ZWNJ between emojis should use the previous emoji font.
+    if(isEmojiScript && (TextAbstraction::IsZeroWidthJoiner(character) || TextAbstraction::IsZeroWidthNonJoiner(character)))
+    {
+      if(0u != previousEmojiFontId)
+      {
+        fontId      = previousEmojiFontId;
+        isValidFont = true;
+      }
+    }
+
     // If the given font is not valid, it means either:
     // - there is no cached font for the current script yet or,
     // - the user has set a different font than the default one for the current script or,
@@ -647,6 +659,15 @@ void MultilanguageSupport::ValidateFonts(const Vector<Character>&
       }   // !isValidFont (2)
     }     // !isValidFont (1)
 
+    // Store the font id when the first character is an emoji.
+    if(isEmojiScript && !isPreviousEmojiScript)
+    {
+      if(0u != fontId)
+      {
+        previousEmojiFontId = fontId;
+      }
+    }
+
 #ifdef DEBUG_ENABLED
     {
       Dali::TextAbstraction::FontDescription description;