From: Bowon Ryu Date: Thu, 13 Feb 2025 11:48:08 +0000 (+0900) Subject: [Tizen] Fix text clustering issue X-Git-Tag: accepted/tizen/9.0/unified/20250220.165938~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3d6427c72b51a69acd07758289a8141b64bc4561;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git [Tizen] Fix text clustering issue Prevent ligature breaks in unicode combinations containing combining diacritical marks. Change-Id: I26618ba35b955b4434f87dff5c8b3b28e7a4ee1e Signed-off-by: Bowon Ryu --- diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp index b4ca2efe13..d83c506e90 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp @@ -2733,6 +2733,37 @@ int utcDaliTextEditorEvent06(void) DALI_TEST_EQUALS("Hello\nworld\nHello world", editor.GetProperty(TextEditor::Property::TEXT), TEST_LOCATION); + editor.SetProperty(TextEditor::Property::TEXT, "ảffiff"); + editor.SetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION, 0); + application.SendNotification(); + application.Render(); + + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(editor.GetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION).Get(), 7, TEST_LOCATION); + + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS(editor.GetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION).Get(), 0, TEST_LOCATION); + + application.ProcessEvent(GenerateKey("", "", "", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE)); + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS("ffiff", editor.GetProperty(TextEditor::Property::TEXT), TEST_LOCATION); + + // For coverage editor.SetProperty(TextEditor::Property::TEXT, "الاخيرالسطر1\nالاخيرالسطر2\nالاخيرالسطر3\nالاخيرالسطر4"); application.SendNotification(); diff --git a/dali-toolkit/internal/text/controller/text-controller-impl.cpp b/dali-toolkit/internal/text/controller/text-controller-impl.cpp index 5e7a5b3d9f..2ddb46267b 100644 --- a/dali-toolkit/internal/text/controller/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/controller/text-controller-impl.cpp @@ -1376,8 +1376,26 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) c const Script script = mModel->mLogicalModel->GetScript(index); if(HasLigatureMustBreak(script)) { - // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ, ... - numberOfCharacters = 1u; + if(numberOfCharacters == 2u) + { + const Character* const textBuffer = mModel->mLogicalModel->mText.Begin(); + Character character = *(textBuffer + index); + + CharacterIndex nextIndex = index + 1u; + bool isCurrentCombining = TextAbstraction::IsCombiningDiacriticalMarks(character); + bool isNextValid = nextIndex < mModel->mLogicalModel->mText.Count(); + bool isNextCombining = isNextValid && TextAbstraction::IsCombiningDiacriticalMarks(*(textBuffer + nextIndex)); + + if(!isCurrentCombining && !isNextCombining) + { + numberOfCharacters = 1u; + } + } + else + { + // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ, ... + numberOfCharacters = 1u; + } } } else diff --git a/dali-toolkit/internal/text/controller/text-controller-text-updater.cpp b/dali-toolkit/internal/text/controller/text-controller-text-updater.cpp index 5a906a5e1c..0cb702a6ca 100644 --- a/dali-toolkit/internal/text/controller/text-controller-text-updater.cpp +++ b/dali-toolkit/internal/text/controller/text-controller-text-updater.cpp @@ -553,6 +553,16 @@ bool Controller::TextUpdater::RemoveText( numberOfCharacters = actualNumberOfCharacters; } + if(HasLigatureMustBreak(script) && cursorOffset == 0) // delete key. + { + GlyphIndex glyphIndex = *(visualModel->mCharactersToGlyph.Begin() + cursorIndex); + Length actualNumberOfCharacters = *(visualModel->mCharactersPerGlyph.Begin() + glyphIndex); + if(actualNumberOfCharacters == 2u && TextAbstraction::IsCombiningDiacriticalMarks(*(currentText.Begin() + cursorIndex + 1u))) + { + numberOfCharacters = 2u; + } + } + if((cursorIndex + numberOfCharacters) > currentText.Count()) { numberOfCharacters = currentText.Count() - cursorIndex; diff --git a/dali-toolkit/internal/text/cursor-helper-functions.cpp b/dali-toolkit/internal/text/cursor-helper-functions.cpp index 5dfebde9e6..38354d1504 100644 --- a/dali-toolkit/internal/text/cursor-helper-functions.cpp +++ b/dali-toolkit/internal/text/cursor-helper-functions.cpp @@ -359,9 +359,17 @@ CharacterIndex GetClosestCursorIndex(VisualModelPtr visualModel, } // Get the script of the character. - const Script script = logicalModel->GetScript(characterLogicalOrderIndex); + const Script script = logicalModel->GetScript(characterLogicalOrderIndex); + const bool hasLigatureMustBreak = HasLigatureMustBreak(script); + bool isCombiningDiacriticalSequence = false; - const bool isInterglyphIndex = (numberOfCharacters > numberOfGlyphs) && HasLigatureMustBreak(script); + if(hasLigatureMustBreak && numberOfCharacters == 2u) + { + // Second character is combining diacritical mark. + isCombiningDiacriticalSequence = TextAbstraction::IsCombiningDiacriticalMarks(*(logicalModel->mText.Begin() + characterLogicalOrderIndex)) ? true : false; + } + + const bool isInterglyphIndex = (numberOfCharacters > numberOfGlyphs) && (hasLigatureMustBreak && !isCombiningDiacriticalSequence); const Length numberOfBlocks = isInterglyphIndex ? numberOfCharacters : 1u; const float glyphAdvance = glyphMetrics.advance / static_cast(numberOfBlocks);