From: Adeel Kazmi Date: Thu, 18 Nov 2021 18:32:21 +0000 (+0000) Subject: Merge "(Text Controller) Moved some input properties into a different class & some... X-Git-Tag: dali_2.1.0~12 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=4800a84a19c2fd33aea3174eae8e55297ee3a9af;hp=eb86a7e2a223a3876fa8be052872df527aad777f Merge "(Text Controller) Moved some input properties into a different class & some functionality into impl" into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp index 64a8473..701977d 100755 --- a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp @@ -460,6 +460,47 @@ void ConfigureTextEditor( ControllerPtr controller ) controller->SetMatchLayoutDirection(DevelText::MatchLayoutDirection::CONTENTS); } + +Vector CreateSingleFontDescription( + const CharacterRun& characterRun, + const std::string fontFamilyName, + const FontWeight weight, + const FontWidth width, + const FontSlant slant, + const PointSize26Dot6 size, + const bool familyDefined, + const bool weightDefined, + const bool widthDefined, + const bool slantDefined, + const bool sizeDefined) +{ + + FontDescriptionRun fontDescriptionRun = + { + characterRun, + nullptr, + 0u, + weight, + width, + slant, + size, + familyDefined, + weightDefined, + widthDefined, + slantDefined, + sizeDefined + }; + + fontDescriptionRun.familyLength = fontFamilyName.size(); + fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; + memcpy( fontDescriptionRun.familyName, fontFamilyName.c_str(), fontDescriptionRun.familyLength ); + + Vector fontDescriptionRuns; + fontDescriptionRuns.PushBack(fontDescriptionRun); + + return fontDescriptionRuns; +} + } // namespace Text } // namespace Toolkit diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h index ccfbe98..0b9f592 100644 --- a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h @@ -93,6 +93,37 @@ void ConfigureTextField( ControllerPtr controller ); */ void ConfigureTextEditor( ControllerPtr controller ); + +/** + * @brief Creates one FontDescriptionRun then add it to FontDescription list. + * + * @param[in] characterRun The initial character index and the number of characters of the run. + * @param[in] fontFamilyName The font's family name. + * @param[in] weight The font's weight. + * @param[in] width The font's width. + * @param[in] slant The font's slant. + * @param[in] size Whether the font's family is defined. + * @param[in] familyDefined Whether the font's weight is defined. + * @param[in] weightDefined Whether the font's width is defined. + * @param[in] widthDefined Whether the ellipsis layout option is enabled. + * @param[in] slantDefined Whether the font's slant is defined. + * @param[in] sizeDefined Whether the font's size is defined. + +* @return vector contains one FontDescriptionRun. + */ +Vector CreateSingleFontDescription( + const CharacterRun& characterRun, + const std::string fontFamilyName, + const FontWeight weight, + const FontWidth width, + const FontSlant slant, + const PointSize26Dot6 size, + const bool familyDefined, + const bool weightDefined, + const bool widthDefined, + const bool slantDefined, + const bool sizeDefined); + } // namespace Text } // namespace Toolkit diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp index 872e85e..bab8800 100755 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp @@ -118,6 +118,21 @@ namespace const GlyphIndex firstMiddleIndexOfGlyphs = model->GetFirstMiddleIndexOfElidedGlyphs(); + //Test total height of lines is fit inside Controller's size + Length heightOfLines = 0; + for(Length lineIndex=0u; lineIndex < numberOfLines; lineIndex++) + { + const LineRun& tempLine = *( model->GetLines() + lineIndex); + heightOfLines+= (tempLine.ascender - tempLine.descender); + } + + if(heightOfLines > data.size.height) + { + std::cout << "The heightOfLines should be less than height of controller."; + std::cout << " The heightOfLines is "<< heightOfLines << "and the height of controller is "<< data.size.height <GetFirstMiddleIndexOfElidedGlyphs(); const GlyphIndex secondMiddleIndexOfGlyphs = textModel->GetSecondMiddleIndexOfElidedGlyphs(); + //Test total height of lines is fit inside Controller's size + Length heightOfLines = 0; + for(Length lineIndex=0u; lineIndex < numberOfLines; lineIndex++) + { + const LineRun& tempLine = *( textModel->GetLines() + lineIndex); + heightOfLines+= (tempLine.ascender - tempLine.descender); + } + + if(heightOfLines > data.size.height) + { + std::cout << "The heightOfLines should be less than height of controller."; + std::cout << " The heightOfLines is "<< heightOfLines << "and the height of controller is "<< data.size.height < fontDescriptions; ///< Fonts which is used for text. }; @@ -140,7 +141,7 @@ bool ShapeInfoTest( const ShapeInfoData& data ) layoutSize, textModel, metrics, - false, + data.markupProcessorEnabled, LineWrap::WORD, false, Toolkit::DevelText::EllipsisPosition::END ); @@ -337,6 +338,34 @@ void LoadSoftwareStylingFonts() fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-BoldItalic.ttf" ); } +void LoadEmojiFonts() +{ + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.ClearCache(); + fontClient.SetDpi( 96u, 96u ); + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + + TextAbstraction::FontDescription fontDescriptionText; + fontDescriptionText.path = ""; + fontDescriptionText.family = "DejaVuSans"; + fontDescriptionText.width = TextAbstraction::FontWidth::NONE; + fontDescriptionText.weight = TextAbstraction::FontWeight::NORMAL; + fontDescriptionText.slant = TextAbstraction::FontSlant::NONE; + fontClient.GetFontId(fontDescriptionText, TextAbstraction::FontClient::DEFAULT_POINT_SIZE); + + TextAbstraction::FontDescription fontDescriptionEmoji; + fontDescriptionEmoji.path = ""; + fontDescriptionEmoji.family = "NotoColorEmoji"; + fontDescriptionEmoji.width = TextAbstraction::FontWidth::NONE; + fontDescriptionEmoji.weight = TextAbstraction::FontWeight::NORMAL; + fontDescriptionEmoji.slant = TextAbstraction::FontSlant::NONE; + fontClient.GetFontId(fontDescriptionEmoji, TextAbstraction::FontClient::DEFAULT_POINT_SIZE); +} + } // namespace ////////////////////////////////////////////////////////// @@ -671,7 +700,8 @@ int UtcDaliTextShape(void) nullptr, nullptr, 0u, - nullptr + nullptr, + false, }, { "Latin script", @@ -684,6 +714,7 @@ int UtcDaliTextShape(void) charactersPerGlyph02, 0u, nullptr, + false, fontDescriptions01 }, { @@ -697,6 +728,7 @@ int UtcDaliTextShape(void) charactersPerGlyph03, 2u, newParagraphGlyphs03, + false, fontDescriptions02 }, { @@ -710,6 +742,7 @@ int UtcDaliTextShape(void) charactersPerGlyph04, 0u, nullptr, + false, fontDescriptions03 }, { @@ -723,7 +756,8 @@ int UtcDaliTextShape(void) charactersPerGlyph05, 1u, newParagraphGlyphs05, - fontDescriptions04 + false, + fontDescriptions04, }, { "Latin script with some paragraphs. Update mid paragraph.", @@ -736,6 +770,7 @@ int UtcDaliTextShape(void) charactersPerGlyph05, 1u, newParagraphGlyphs06, + false, fontDescriptions05 }, { @@ -749,6 +784,7 @@ int UtcDaliTextShape(void) charactersPerGlyph05, 1u, newParagraphGlyphs07, + false, fontDescriptions06 }, }; @@ -927,6 +963,7 @@ int UtcDaliTextSoftwareStyling(void) charactersPerGlyph, 0u, nullptr, + false, fontDescriptions01 }, { @@ -940,6 +977,7 @@ int UtcDaliTextSoftwareStyling(void) charactersPerGlyph, 0u, nullptr, + false, fontDescriptions02 } }; @@ -960,3 +998,142 @@ int UtcDaliTextSoftwareStyling(void) tet_result(TET_PASS); END_TEST; } + + +int UtcDaliTextShapeEmojiSequences(void) +{ + + ToolkitTestApplication application; + + tet_infoline(" UtcDaliTextShapeEmojiSequences"); + + const std::string colorFontFamily( "NotoColorEmoji" ); + const std::string textFontFamily( "DejaVuSans" ); + + LoadEmojiFonts(); + + //Common attributes for font Descriptions + CharacterRun characterRun = {0u, 2u}; + FontWeight weight = TextAbstraction::FontWeight::NORMAL; + FontWidth width = TextAbstraction::FontWidth::NORMAL; + FontSlant slant = TextAbstraction::FontSlant::ITALIC; + PointSize26Dot6 size = TextAbstraction::FontClient::DEFAULT_POINT_SIZE; + + bool familyDefined = true; + bool weightDefined = false; + bool widthDefined = false; + bool slantDefined = false; + bool sizeDefined = false; + + + // variation selector 16 (Emoji) + struct GlyphInfoData glyphsVS16[] = + { + { 2u, 74u, 0.f, 0.f, 0.f, 0.f, 39.0f, 0.f, false, false }, + }; + CharacterIndex characterIndicesVS16[] = { 0u, 1u}; + Length charactersPerGlyphVS16[] = { 2u }; + + + + // variation selector 15 (Text) + struct GlyphInfoData glyphsVS15[] = + { + { 1u, 3842u, 0.f, 0.f, 0.f, 0.f, 14.0f, 0.f, false, false }, + { 1u, 8203u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, false, false }, + }; + CharacterIndex characterIndicesVS15[] = { 0u, 0u}; + Length charactersPerGlyphVS15[] = { 0u, 2u }; + + //Font Descriptions + Vector fontDescriptionsColorVS16 = + CreateSingleFontDescription (characterRun, colorFontFamily, weight, width, + slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined); + + Vector fontDescriptionsColorVS15 = + CreateSingleFontDescription (characterRun, colorFontFamily, weight, width, + slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined); + + Vector fontDescriptionsTextVS16 = + CreateSingleFontDescription (characterRun, textFontFamily, weight, width, + slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined); + + Vector fontDescriptionsTextVS15 = + CreateSingleFontDescription (characterRun, textFontFamily, weight, width, + slant, size, familyDefined, weightDefined, widthDefined, slantDefined, sizeDefined); + + + struct ShapeInfoData data[] = + { + { + "EMOJI Sequence: Color Font with VS16", + "☪️", + 0u, + 2u, + 1u, + glyphsVS16, + characterIndicesVS16, + charactersPerGlyphVS16, + 0u, + nullptr, + true, + fontDescriptionsColorVS16 + }, + { + "EMOJI Sequence: Color Font with VS15", + "☪︎", + 0u, + 2u, + 2u, + glyphsVS15, + characterIndicesVS15, + charactersPerGlyphVS15, + 0u, + nullptr, + true, + fontDescriptionsColorVS15 + }, + { + "EMOJI Sequence: Text Font with VS16", + "☪️", + 0u, + 2u, + 1u, + glyphsVS16, + characterIndicesVS16, + charactersPerGlyphVS16, + 0u, + nullptr, + true, + fontDescriptionsTextVS16 + }, + { + "EMOJI Sequence: Text Font with VS15", + "☪︎", + 0u, + 2u, + 2u, + glyphsVS15, + characterIndicesVS15, + charactersPerGlyphVS15, + 0u, + nullptr, + true, + fontDescriptionsTextVS15 + }, + }; + + const unsigned int numberOfTests = 4u; + + for( unsigned int index = 0u; index < numberOfTests; ++index ) + { + tet_infoline( data[index].description.c_str()); + if( !ShapeInfoTest( data[index] ) ) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index c9453e1..be0e5b1 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -843,6 +843,37 @@ int UtcDaliToolkitTextLabelEmojisP(void) application.SendNotification(); application.Render(); + // EMOJI Sequences case for coverage. + std::string emojiSequences = + "Text VS15 ☪︎\n" //text presentation sequence and selector + "Color VS16 ☪️\n" //emoji presentation sequence and selector + "Default ☪ \n" //default presentation + "FamilyManWomanGirlBoy 👨‍👩‍👧‍👦\n" // emoji multi zwj sequence + "WomanScientist 👩‍🔬\n" // emoji zwj sequence + "WomanScientistLightSkinTone👩🏻‍🔬 \n" //emoji modifier sequence: skin tone & JWZ + "LeftRightArrowText↔︎\n" //text presentation sequence and selector + "LeftRightArrowEmoji↔️\n" //emoji presentation sequence and selector + "SouthKoreaFlag🇰🇷\n" //emoji flag sequence + "JordanFlag🇯🇴\n" // emoji flag sequence + "EnglandFlag🏴󠁧󠁢󠁥󠁮󠁧󠁿\n" //emoji tag sequence like England flag + "Runner 🏃‍➡️ \n" + "VictoryHandMediumLightSkinTone:✌️🏼\n" //emoji modifier sequence: skin tone + "RainbowFlag:🏳️‍🌈 \n" //emoji zwj sequence: Rainbow Flag + "keycap# #️⃣ \n" // fully-qualified emoji keycap sequence + "keycap#_text #⃣ \n" // unqualified emoji keycap sequence + "keycap3 3️⃣ \n" // fully-qualified emoji keycap sequence + "keycap3_text 3⃣ \n" // unqualified emoji keycap sequence + "two adjacent glyphs ☪️️️☪️\n" //This line should be rendered as two adjacent glyphs + "Digit 8️ 8︎ 8\n" // should be rendered according to selector + "Surfing Medium Skin Female: 🏄🏼‍♀️"; // Person Surfing + Medium Skin Tone +? Zero Width Joiner + Female Sign + + label.SetProperty( TextLabel::Property::TEXT, emojiSequences ); + label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true ); + label.SetProperty( TextLabel::Property::MULTI_LINE, true); + label.SetProperty( TextLabel::Property::ELLIPSIS, false); + + application.SendNotification(); + application.Render(); END_TEST; } diff --git a/dali-toolkit/devel-api/controls/accessible-impl.cpp b/dali-toolkit/devel-api/controls/accessible-impl.cpp index bd4a649..9f6f4f9 100644 --- a/dali-toolkit/devel-api/controls/accessible-impl.cpp +++ b/dali-toolkit/devel-api/controls/accessible-impl.cpp @@ -363,7 +363,6 @@ void AccessibleImpl::ScrollToSelf() parent->ScrollToChild(child->Self()); } - child = parent; parent = dynamic_cast(parent->GetParent()); } } diff --git a/dali-toolkit/devel-api/controls/accessible-impl.h b/dali-toolkit/devel-api/controls/accessible-impl.h index 18b77f5..8bd0714 100644 --- a/dali-toolkit/devel-api/controls/accessible-impl.h +++ b/dali-toolkit/devel-api/controls/accessible-impl.h @@ -236,7 +236,7 @@ public: virtual Dali::Accessibility::States CalculateStates(); /** - * @brief Makes sure that a given child of this container (e.g. ItemView) is visible + * @brief Makes sure that a given child (descendant) of this container (e.g. ItemView) is visible * @return false if scrolling is not supported or child is already visible */ virtual bool ScrollToChild(Actor child); diff --git a/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp b/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp index 7331f3e..7033e6d 100644 --- a/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp +++ b/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp @@ -27,7 +27,7 @@ void CommonTextUtils::RenderText( Text::RendererPtr renderer, Text::ControllerPtr controller, Text::DecoratorPtr decorator, - float alignmentOffset, + float& alignmentOffset, Actor& renderableActor, Actor& backgroundActor, Toolkit::Control& stencil, diff --git a/dali-toolkit/internal/controls/text-controls/common-text-utils.h b/dali-toolkit/internal/controls/text-controls/common-text-utils.h index f2eaba7..f9069a2 100644 --- a/dali-toolkit/internal/controls/text-controls/common-text-utils.h +++ b/dali-toolkit/internal/controls/text-controls/common-text-utils.h @@ -37,7 +37,7 @@ public: * @param[in] renderer pointer to the text renderer * @param[in] controller pointer to the text controller * @param[in] decorator pointer to the text decorator - * @param[in] alignmentOffset Alignment offset + * @param[in,out] alignmentOffset Alignment offset * @param[in,out] renderableActor Actor for rendering text * @param[in,out] backgroundActor Actor for rendering background * @param[in,out] stencil Clipping actor @@ -49,7 +49,7 @@ public: Text::RendererPtr renderer, Text::ControllerPtr controller, Text::DecoratorPtr decorator, - float alignmentOffset, + float& alignmentOffset, Actor& renderableActor, Actor& backgroundActor, Toolkit::Control& stencil, diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 7a0b010..591915d 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -203,6 +203,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/transition-effects/cube-transition-wave-effect-impl.cpp ${toolkit_src_dir}/text/xhtml-entities.cpp ${toolkit_src_dir}/drag-drop-detector/drag-and-drop-detector-impl.cpp + ${toolkit_src_dir}/text/emoji-helper.cpp ) SET( SOURCES ${SOURCES} diff --git a/dali-toolkit/internal/text/emoji-helper.cpp b/dali-toolkit/internal/text/emoji-helper.cpp new file mode 100644 index 0000000..eec4ee4 --- /dev/null +++ b/dali-toolkit/internal/text/emoji-helper.cpp @@ -0,0 +1,224 @@ + +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Text +{ +bool IsTextPresentationSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character) +{ + return (IsSymbolOrEmojiOrTextScript(currentRunScript) && TextAbstraction::IsTextPresentationSelector(character)); +} + +bool IsEmojiPresentationSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character) +{ + return ((IsSymbolOrEmojiScript(currentRunScript) || IsEmojiColorScript(currentRunScript)) && + TextAbstraction::IsEmojiPresentationSelector(character)); +} + +bool IsEmojiSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character, + const TextAbstraction::Script& characterScript) +{ + return (IsOneOfEmojiScripts(currentRunScript) && + (IsOneOfEmojiScripts(characterScript) || + TextAbstraction::IsZeroWidthJoiner(character) || + TextAbstraction::IsZeroWidthNonJoiner(character) || + TextAbstraction::IsEmojiItem(character) || + TextAbstraction::IsMiscellaneousSymbolsAndArrowsEmoji(character) || + TextAbstraction::IsDingbatsEmoji(character))); +} + +bool IsNewSequence(const Character* const textBuffer, + const TextAbstraction::Script& currentRunScript, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + TextAbstraction::Script& currentCharacterScript) +{ + // Until now we have two cases : VariationSelector & Keycap + // In-case there are more cases then should be added in this function + + return IsNewKeycapSequence(textBuffer, currentCharacterIndex, lastCharacterIndex, currentCharacterScript) || + IsNewVariationSelectorSequence(textBuffer, currentRunScript, currentCharacterIndex, lastCharacterIndex, currentCharacterScript); +} + +// + +bool IsNewKeycapSequence(const Character* const textBuffer, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + TextAbstraction::Script& currentCharacterScript) +{ + // Ref: https://www.unicode.org/Public/emoji/14.0/emoji-sequences.txt Search on "Emoji_Keycap_Sequence" + // Ref: https://www.unicode.org/Public/emoji/14.0/emoji-test.txt Search on "subgroup: keycap" + + // Default initialization does not keycap sequence + bool isNewKeycapSequence = false; + + if(currentCharacterIndex < lastCharacterIndex) + { + Character currentCharacter = *(textBuffer + currentCharacterIndex); + if(IsStartForKeycapSequence(currentCharacter)) + { + if(!isNewKeycapSequence && currentCharacterIndex + 2 <= lastCharacterIndex) + { + Character characterOne = *(textBuffer + currentCharacterIndex + 1); + Character characterTwo = *(textBuffer + currentCharacterIndex + 2); + + if(TextAbstraction::IsEmojiPresentationSelector(characterOne) && + TextAbstraction::IsCombiningEnclosingKeycap(characterTwo)) + { + isNewKeycapSequence = true; + currentCharacterScript = TextAbstraction::EMOJI_COLOR; + } + } // if(!isNewKeycapSequence && currentCharacterIndex + 2 <= lastCharacterIndex) + } // if(IsStartForKeycapSequence(currentCharacter)) + } // if(currentCharacterIndex < lastCharacterIndex) + + return isNewKeycapSequence; +} + +bool IsNewVariationSelectorSequence(const Character* const textBuffer, + const TextAbstraction::Script& currentRunScript, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + TextAbstraction::Script& currentCharacterScript) +{ + // Ref: Emoji and Text Presentation Selectors: https://www.unicode.org/reports/tr51/#Emoji_Variation_Selectors + // Ref: Emoji Variation Sequences for UTS #51: https://www.unicode.org/Public/14.0.0/ucd/emoji/emoji-variation-sequences.txt + + // Default initialization does not VariationSelector sequence + bool isNewVariationSelectorSequence = false; + + if(currentCharacterIndex < lastCharacterIndex) + { + Character currentCharacter = *(textBuffer + currentCharacterIndex); + if(TextAbstraction::IsEmojiVariationSequences(currentCharacter)) + { + if(!isNewVariationSelectorSequence && currentCharacterIndex + 1 <= lastCharacterIndex) + { + Character characterVS = *(textBuffer + currentCharacterIndex + 1); + + if(TextAbstraction::IsEmojiPresentationSelector(characterVS)) + { + isNewVariationSelectorSequence = currentRunScript != TextAbstraction::EMOJI_COLOR; + currentCharacterScript = TextAbstraction::EMOJI_COLOR; + } + else if(TextAbstraction::IsTextPresentationSelector(characterVS)) + { + isNewVariationSelectorSequence = currentRunScript != TextAbstraction::EMOJI_TEXT; + currentCharacterScript = TextAbstraction::EMOJI_TEXT; + } + + } // if(!isNewVariationSelectorSequence && currentCharacterIndex + 1 <= lastCharacterIndex) + } // if(TextAbstraction::IsEmojiVariationSequences(currentCharacter)) + } // if(currentCharacterIndex < lastCharacterIndex) + + return isNewVariationSelectorSequence; +} + +bool IsStartForKeycapSequence(const TextAbstraction::Character& character) +{ + return (TextAbstraction::IsASCIIDigits(character) || + TextAbstraction::CHAR_NUMBER_SIGN == character || + TextAbstraction::CHAR_ASTERISK == character); +} + +bool IsScriptChangedToFollowSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character, + TextAbstraction::Script& currentCharacterScript) +{ + bool isUpdated = false; + + // Keycap cases + if(TextAbstraction::IsCombiningEnclosingKeycap(character)) + { + if(TextAbstraction::EMOJI == currentRunScript) + { + // Keycap and unqualified + // Emoji request a default presentation for an emoji character. + isUpdated = (currentCharacterScript != TextAbstraction::EMOJI); + currentCharacterScript = TextAbstraction::EMOJI; + } + else if(TextAbstraction::EMOJI_COLOR == currentRunScript) + { + // Keycap and fully-qualified + // Emoji request an emoji presentation for an emoji character. + isUpdated = (currentCharacterScript != TextAbstraction::EMOJI_COLOR); + currentCharacterScript = TextAbstraction::EMOJI_COLOR; + } + } + // Emoji(Text) Presentation cases + else if(IsTextPresentationSequence(currentRunScript, character)) + { + // Emoji request a text presentation for an emoji character. + isUpdated = (currentCharacterScript != TextAbstraction::EMOJI_TEXT); + currentCharacterScript = TextAbstraction::EMOJI_TEXT; + } + // Emoji(Color) Presentation cases + else if(IsEmojiPresentationSequence(currentRunScript, character)) + { + // Emoji request an emoji presentation for an emoji character. + isUpdated = (currentCharacterScript != TextAbstraction::EMOJI_COLOR); + currentCharacterScript = TextAbstraction::EMOJI_COLOR; + } + // Default Emoji + else if(IsEmojiScript(currentRunScript) && IsEmojiScript(currentCharacterScript)) + { + // Emoji request an emoji presentation for an emoji character. + isUpdated = (currentCharacterScript != TextAbstraction::EMOJI); + currentCharacterScript = TextAbstraction::EMOJI; + } + // Emoji sequences + else if(IsEmojiSequence(currentRunScript, character, currentCharacterScript)) + { + // Emoji request an emoji presentation for an emoji character. + isUpdated = (currentCharacterScript != TextAbstraction::EMOJI_COLOR); + currentCharacterScript = TextAbstraction::EMOJI_COLOR; + } + + return isUpdated; +} + +Character GetVariationSelectorByScript(const TextAbstraction::Script& script) +{ + Character character = 0u; + if(TextAbstraction::EMOJI_COLOR == script) + { + character = TextAbstraction::CHAR_VARIATION_SELECTOR_16; + } + else if(TextAbstraction::EMOJI_TEXT == script) + { + character = TextAbstraction::CHAR_VARIATION_SELECTOR_15; + } + + return character; +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali \ No newline at end of file diff --git a/dali-toolkit/internal/text/emoji-helper.h b/dali-toolkit/internal/text/emoji-helper.h new file mode 100644 index 0000000..95efd9f --- /dev/null +++ b/dali-toolkit/internal/text/emoji-helper.h @@ -0,0 +1,170 @@ +#ifndef DALI_TOOLKIT_TEXT_EMOJI_HELPER_H +#define DALI_TOOLKIT_TEXT_EMOJI_HELPER_H + +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include + +// EXTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Text +{ +/** + * @brief Whether the sequence is a variation sequence consisting of an emoji character followed by a text presentation selector. + * + * @param[in] currentRunScript The script of current run. + * @param[in] character The next character. + * + * @return @e true if the sequence is text presentation sequence. + */ +bool IsTextPresentationSequence(const TextAbstraction::Script& currentRunScript, const TextAbstraction::Character& character); + +/** + * @brief Whether the sequence is a variation sequence consisting of an emoji character followed by a emoji presentation selector. + * + * @param[in] currentRunScript The script of current run. + * @param[in] character The next character. + * + * @return @e true if the sequence is emoji presentation sequence. + */ +bool IsEmojiPresentationSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character); + +/** + * @brief Whether the sequence is an emoji sequence. + * + * @param[in] currentRunScript The script of current run. + * @param[in] character The next character. + * @param[in] characterScript The script of the next character. + * + * @return @e true if the sequence is an emoji sequence. + */ +bool IsEmojiSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character, + const TextAbstraction::Script& characterScript); + +/** + * @brief Whether the sequence is a keycap sequence and set script according to the case. + * + * @param[in] textBuffer The text. + * @param[in] currentCharacterIndex The index of current character. + * @param[in] lastCharacterIndex The index of last character. + * @param[out] currentCharacterScript The current character script to update it in-case it's the Keycap sequence. + * + * @return @e true if @p currentRunScript is ASCII_DIGITS and @p character is COMBINING_ENCLOSING_KEYCAP + */ +bool IsNewKeycapSequence(const Character* const textBuffer, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + TextAbstraction::Script& currentCharacterScript); + +/** + * @brief Whether the sequence is a variation selector sequence and set script according to the case. + * + * @param[in] textBuffer The text. + * @param[in] currentRunScript The script of current run. + * @param[in] currentCharacterIndex The index of current character. + * @param[in] lastCharacterIndex The index of last character. + * @param[out] currentCharacterScript The current character script to update it in-case it's the VariationSelector sequence. + * + * @return @e true if @p currentRunScript is ASCII_DIGITS and @p character is COMBINING_ENCLOSING_KEYCAP + */ +bool IsNewVariationSelectorSequence(const Character* const textBuffer, + const TextAbstraction::Script& currentRunScript, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + TextAbstraction::Script& currentCharacterScript); + +/** + * @brief Whether the case is a new sequence and set script according to the case. + * + * @param[in] textBuffer The text. + * @param[in] currentRunScript The script of current run. + * @param[in] currentCharacterIndex The index of current character. + * @param[in] lastCharacterIndex The index of last character. + * @param[out] currentCharacterScript The current character script to update according to sequence. + * + * @return @e true the case is a new sequence + */ +bool IsNewSequence(const Character* const textBuffer, + const TextAbstraction::Script& currentRunScript, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + TextAbstraction::Script& currentCharacterScript); + +/** + * @brief Whether the character is ASCII digits | # Number Sign | * Asterisk. + * + * @param[in] character The character. + * + * @return @e true if the character is ASCII digits | # Number Sign | * Asterisk. + */ +bool IsStartForKeycapSequence(const TextAbstraction::Character& character); + +/** + * @brief Check sequence case and update script of character if needed. + * + * @param[in] currentRunScript The script of current run. + * @param[in] character The next character. + * @param[out] script The current character script to update according to sequence. + * + * @return @e true if the script is changed + */ +bool IsScriptChangedToFollowSequence(const TextAbstraction::Script& currentRunScript, + const TextAbstraction::Character& character, + TextAbstraction::Script& script); + +/** + * @brief Check sequence case and update script of character if needed. + * + * @param[in] currentRunScript The script of current run. + * @param[in] character The next character. + * @param[out] script The current character script to update according to sequence. + * + * @return @e true if the script is changed + */ +bool HandleEmojiSequence(const Character* const textBuffer, + const Length& currentCharacterIndex, + const Length& lastCharacterIndex, + const TextAbstraction::Script& currentRunScript, + TextAbstraction::Script& currentCharacterScript); + +/** + * @brief Determine the Variation Selector according to script. + * + * @param[in] script The script. + * + * @return CHAR_VARIATION_SELECTOR_15 in-case EMOJI_TEXT or CHAR_VARIATION_SELECTOR_16 in-case EMOJI_COLOR or 0 otherwise + */ +Character GetVariationSelectorByScript(const TextAbstraction::Script& script); + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_EMOJI_HELPER_H \ No newline at end of file diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index 695d950..7610b67 100644 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -1867,7 +1867,6 @@ struct Engine::Impl linesBuffer[lineIndex].ellipsis = false; } numberOfLines--; - lineIndex++; } linesBuffer[0u].ellipsis = true; } diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp index 82470f8..dbd110b 100644 --- a/dali-toolkit/internal/text/multi-language-support-impl.cpp +++ b/dali-toolkit/internal/text/multi-language-support-impl.cpp @@ -24,6 +24,7 @@ #include // INTERNAL INCLUDES +#include #include namespace Dali @@ -97,11 +98,11 @@ MultilanguageSupport::MultilanguageSupport() { // Initializes the default font cache to zero (invalid font). // Reserves space to cache the default fonts and access them with the script as an index. - mDefaultFontPerScriptCache.Resize(TextAbstraction::UNKNOWN + 1, NULL); + mDefaultFontPerScriptCache.Resize(TextAbstraction::GetNumberOfScripts(), NULL); // Initializes the valid fonts cache to NULL (no valid fonts). // Reserves space to cache the valid fonts and access them with the script as an index. - mValidFontsPerScriptCache.Resize(TextAbstraction::UNKNOWN + 1, NULL); + mValidFontsPerScriptCache.Resize(TextAbstraction::GetNumberOfScripts(), NULL); } MultilanguageSupport::~MultilanguageSupport() @@ -205,6 +206,7 @@ void MultilanguageSupport::SetScripts(const Vector& text, // Traverse all characters and set the scripts. const Length lastCharacter = startIndex + numberOfCharacters; + for(Length index = startIndex; index < lastCharacter; ++index) { Character character = *(textBuffer + index); @@ -222,26 +224,40 @@ void MultilanguageSupport::SetScripts(const Vector& text, // Skip those characters valid for many scripts like white spaces or '\n'. bool endOfText = index == lastCharacter; + + //Handle all Emoji Sequence cases + if(IsNewSequence(textBuffer, currentScriptRun.script, index, lastCharacter, script)) + { + AddCurrentScriptAndCreatNewScript(script, + false, + false, + currentScriptRun, + numberOfAllScriptCharacters, + scripts, + scriptIndex); + } + else if(IsScriptChangedToFollowSequence(currentScriptRun.script, character, script)) + { + currentScriptRun.script = script; + } + else if(IsOneOfEmojiScripts(currentScriptRun.script) && (TextAbstraction::COMMON == script)) + { + // Emojis doesn't mix well with characters common to all scripts. Insert the emoji run. + AddCurrentScriptAndCreatNewScript(TextAbstraction::UNKNOWN, + false, + false, + currentScriptRun, + numberOfAllScriptCharacters, + scripts, + scriptIndex); + } + while(!endOfText && (TextAbstraction::COMMON == script)) { // Check if whether is right to left markup and Keeps true if the previous value was true. currentScriptRun.isRightToLeft = currentScriptRun.isRightToLeft || TextAbstraction::IsRightToLeftMark(character); - // 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); - ++scriptIndex; - - // Initialize the new one. - currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters; - currentScriptRun.characterRun.numberOfCharacters = 0u; - currentScriptRun.script = TextAbstraction::UNKNOWN; - numberOfAllScriptCharacters = 0u; - } - // Count all these characters to be added into a script. ++numberOfAllScriptCharacters; @@ -253,20 +269,13 @@ void MultilanguageSupport::SetScripts(const Vector& text, // the same direction than the first script of the paragraph. isFirstScriptToBeSet = true; - // Characters common to all scripts at the end of the paragraph are added to the last script. - currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; - - // Store the script run. - scripts.Insert(scripts.Begin() + scriptIndex, currentScriptRun); - ++scriptIndex; - - // Initialize the new one. - currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters; - currentScriptRun.characterRun.numberOfCharacters = 0u; - currentScriptRun.script = TextAbstraction::UNKNOWN; - numberOfAllScriptCharacters = 0u; - // Initialize whether is right to left direction - currentScriptRun.isRightToLeft = false; + AddCurrentScriptAndCreatNewScript(TextAbstraction::UNKNOWN, + false, + false, + currentScriptRun, + numberOfAllScriptCharacters, + scripts, + scriptIndex); } // Get the next character. @@ -276,6 +285,22 @@ void MultilanguageSupport::SetScripts(const Vector& text, { character = *(textBuffer + index); script = TextAbstraction::GetCharacterScript(character); + + //Handle all Emoji Sequence cases + if(IsNewSequence(textBuffer, currentScriptRun.script, index, lastCharacter, script)) + { + AddCurrentScriptAndCreatNewScript(script, + false, + false, + currentScriptRun, + numberOfAllScriptCharacters, + scripts, + scriptIndex); + } + else if(IsScriptChangedToFollowSequence(currentScriptRun.script, character, script)) + { + currentScriptRun.script = script; + } } } // end while( !endOfText && ( TextAbstraction::COMMON == script ) ) @@ -290,7 +315,10 @@ void MultilanguageSupport::SetScripts(const Vector& text, if(isFirstScriptToBeSet && (TextAbstraction::UNKNOWN != script) && (TextAbstraction::COMMON != script) && - (TextAbstraction::EMOJI != script)) + (TextAbstraction::EMOJI != script) && + (TextAbstraction::EMOJI_TEXT != script) && + (TextAbstraction::EMOJI_COLOR != script) && + (!TextAbstraction::IsSymbolScript(script))) { // Sets the direction of the first valid script. isParagraphRTL = currentScriptRun.isRightToLeft || TextAbstraction::IsRightToLeftScript(script); @@ -319,26 +347,21 @@ void MultilanguageSupport::SetScripts(const Vector& text, numberOfAllScriptCharacters = 0u; } else if((TextAbstraction::UNKNOWN == currentScriptRun.script) && - (TextAbstraction::EMOJI == script)) + (TextAbstraction::IsSymbolOrEmojiOrTextScript(script))) { currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; numberOfAllScriptCharacters = 0u; } - if(0u != currentScriptRun.characterRun.numberOfCharacters) - { - // Store the script run. - scripts.Insert(scripts.Begin() + scriptIndex, currentScriptRun); - ++scriptIndex; - } - - // Initialize the new one. - currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters; - currentScriptRun.characterRun.numberOfCharacters = numberOfAllScriptCharacters + 1u; // Adds the white spaces which are at the begining of the script. - currentScriptRun.script = script; - numberOfAllScriptCharacters = 0u; - // Check if whether is right to left script. - currentScriptRun.isRightToLeft = TextAbstraction::IsRightToLeftScript(currentScriptRun.script); + // Adds the white spaces which are at the begining of the script. + numberOfAllScriptCharacters++; + AddCurrentScriptAndCreatNewScript(script, + TextAbstraction::IsRightToLeftScript(script), + true, + currentScriptRun, + numberOfAllScriptCharacters, + scripts, + scriptIndex); } else { @@ -445,8 +468,8 @@ void MultilanguageSupport::ValidateFonts(const Vector& Vector::ConstIterator scriptRunEndIt = scripts.End(); bool isNewParagraphCharacter = false; - bool isPreviousEmojiScript = false; - FontId previousEmojiFontId = 0u; + FontId previousEmojiFontId = 0u; + TextAbstraction::Script previousScript = TextAbstraction::UNKNOWN; CharacterIndex lastCharacter = startIndex + numberOfCharacters; for(Length index = startIndex; index < lastCharacter; ++index) @@ -518,28 +541,11 @@ void MultilanguageSupport::ValidateFonts(const Vector& } bool isCommonScript = false; - bool isEmojiScript = TextAbstraction::EMOJI == script; - - if(isEmojiScript && !isPreviousEmojiScript) - { - if(0u != currentFontRun.characterRun.numberOfCharacters) - { - // Store the font run. - fonts.Insert(fonts.Begin() + fontIndex, currentFontRun); - ++fontIndex; - } - - // Initialize the new one. - currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters; - currentFontRun.characterRun.numberOfCharacters = 0u; - currentFontRun.fontId = fontId; - currentFontRun.isItalicRequired = false; - currentFontRun.isBoldRequired = false; - } + bool isEmojiScript = TextAbstraction::IsEmojiScript(script) || TextAbstraction::IsEmojiColorScript(script) || TextAbstraction::IsEmojiTextScript(script); - // ZWJ, ZWNJ between emojis should use the previous emoji font. - if(isEmojiScript && (TextAbstraction::IsZeroWidthJoiner(character) || TextAbstraction::IsZeroWidthNonJoiner(character))) + if(isEmojiScript && (previousScript == script)) { + // Emoji sequence should use the previous emoji font. if(0u != previousEmojiFontId) { fontId = previousEmojiFontId; @@ -567,7 +573,7 @@ void MultilanguageSupport::ValidateFonts(const Vector& // // Many fonts support 'white spaces' so probably the font set by the user or the platform's default // supports the 'white space'. However, that font may not support the DEVANAGARI script. - isCommonScript = TextAbstraction::IsCommonScript(character); + isCommonScript = TextAbstraction::IsCommonScript(character) || TextAbstraction::IsEmojiPresentationSelector(character); // Check in the valid fonts cache. ValidateFontsPerScript* validateFontsPerScript = *(validFontsPerScriptCacheBuffer + script); @@ -659,14 +665,55 @@ void MultilanguageSupport::ValidateFonts(const Vector& } // !isValidFont (2) } // !isValidFont (1) + if(isEmojiScript && (previousScript != script)) + { + //New Emoji sequence should select font according to the variation selector (VS15 or VS16). + if(0u != currentFontRun.characterRun.numberOfCharacters) + { + // Store the font run. + fonts.Insert(fonts.Begin() + fontIndex, currentFontRun); + ++fontIndex; + } + + // Initialize the new one. + currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters; + currentFontRun.characterRun.numberOfCharacters = 0u; + currentFontRun.fontId = fontId; + currentFontRun.isItalicRequired = false; + currentFontRun.isBoldRequired = false; + + if(TextAbstraction::IsEmojiColorScript(script) || TextAbstraction::IsEmojiTextScript(script)) + { + bool isModifiedByVariationSelector = false; + GlyphIndex glyphIndexChar = fontClient.GetGlyphIndex(fontId, character); + GlyphIndex glyphIndexCharByVS = fontClient.GetGlyphIndex(fontId, character, Text::GetVariationSelectorByScript(script)); + + isModifiedByVariationSelector = glyphIndexChar != glyphIndexCharByVS; + + if(isModifiedByVariationSelector) + { + FontId requestedFontId = fontClient.FindDefaultFont(character, currentFontPointSize, IsEmojiColorScript(script)); + if(0u != requestedFontId) + { + currentFontRun.fontId = fontId = requestedFontId; + isValidFont = true; + } + } + } + } + // Store the font id when the first character is an emoji. - if(isEmojiScript && !isPreviousEmojiScript) + if(isEmojiScript) { - if(0u != fontId) + if(0u != fontId && previousScript != script) { previousEmojiFontId = fontId; } } + else + { + previousEmojiFontId = 0u; + } #ifdef DEBUG_ENABLED { @@ -715,7 +762,7 @@ void MultilanguageSupport::ValidateFonts(const Vector& // Whether the current character is a new paragraph character. isNewParagraphCharacter = TextAbstraction::IsNewParagraph(character); - isPreviousEmojiScript = isEmojiScript; + previousScript = script; } // end traverse characters. if(0u != currentFontRun.characterRun.numberOfCharacters) @@ -746,6 +793,34 @@ void MultilanguageSupport::ValidateFonts(const Vector& DALI_LOG_INFO(gLogFilter, Debug::General, "<--MultilanguageSupport::ValidateFonts\n"); } +void MultilanguageSupport::AddCurrentScriptAndCreatNewScript(const Script requestedScript, + const bool isRightToLeft, + const bool addScriptCharactersToNewScript, + ScriptRun& currentScriptRun, + Length& numberOfAllScriptCharacters, + Vector& scripts, + ScriptRunIndex& scriptIndex) +{ + // Add the pending characters to the current script + currentScriptRun.characterRun.numberOfCharacters += (addScriptCharactersToNewScript ? 0u : numberOfAllScriptCharacters); + + // In-case the current script is empty then no need to add it for scripts + if(0u != currentScriptRun.characterRun.numberOfCharacters) + { + // Store the script run. + scripts.Insert(scripts.Begin() + scriptIndex, currentScriptRun); + ++scriptIndex; + } + + // Initialize the new one by the requested script + currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters; + currentScriptRun.characterRun.numberOfCharacters = (addScriptCharactersToNewScript ? numberOfAllScriptCharacters : 0u); + currentScriptRun.script = requestedScript; + numberOfAllScriptCharacters = 0u; + // Initialize whether is right to left direction + currentScriptRun.isRightToLeft = isRightToLeft; +} + } // namespace Internal } // namespace Text diff --git a/dali-toolkit/internal/text/multi-language-support-impl.h b/dali-toolkit/internal/text/multi-language-support-impl.h index de44e19..cda767a 100644 --- a/dali-toolkit/internal/text/multi-language-support-impl.h +++ b/dali-toolkit/internal/text/multi-language-support-impl.h @@ -160,6 +160,28 @@ public: private: Vector mDefaultFontPerScriptCache; ///< Caches default fonts for a script. Vector mValidFontsPerScriptCache; ///< Caches valid fonts for a script. + + //Methods + + /** + * @brief Add the current script to scripts and create new script. + * + * @param[in] requestedScript The script of the new script run. + * @param[in] isRightToLeft The direction of the new script run. + * @param[in] addScriptCharactersToNewScript Whether to add the pending characters to the new script run or to the current script run. + * @param[inout] currentScriptRun The current character script run and it will be updated it to the new script run. + * @param[inout] numberOfAllScriptCharacters The pending characters. + * @param[inout] scripts The list of scripts. + * @param[inout] scriptIndex The current index of scripts. + * + */ + void AddCurrentScriptAndCreatNewScript(const Script requestedScript, + const bool isRightToLeft, + const bool addScriptCharactersToNewScript, + ScriptRun& currentScriptRun, + Length& numberOfAllScriptCharacters, + Vector& scripts, + ScriptRunIndex& scriptIndex); }; } // namespace Internal diff --git a/dali-toolkit/internal/text/rendering/view-model.cpp b/dali-toolkit/internal/text/rendering/view-model.cpp index 35c0a87..2187487 100644 --- a/dali-toolkit/internal/text/rendering/view-model.cpp +++ b/dali-toolkit/internal/text/rendering/view-model.cpp @@ -449,7 +449,7 @@ void ViewModel::ElideGlyphs() // Need to reshape the glyph as the font may be different in size. const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId)); - if(!firstPenSet) + if(!firstPenSet || EqualsZero(glyphToRemove.advance)) { const Vector2& position = *(elidedPositionsBuffer + indexOfEllipsis); diff --git a/dali-toolkit/public-api/dali-toolkit-version.cpp b/dali-toolkit/public-api/dali-toolkit-version.cpp index 520ffcf..396764e 100644 --- a/dali-toolkit/public-api/dali-toolkit-version.cpp +++ b/dali-toolkit/public-api/dali-toolkit-version.cpp @@ -29,7 +29,7 @@ namespace Toolkit { const unsigned int TOOLKIT_MAJOR_VERSION = 2; const unsigned int TOOLKIT_MINOR_VERSION = 0; -const unsigned int TOOLKIT_MICRO_VERSION = 51; +const unsigned int TOOLKIT_MICRO_VERSION = 53; const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__; #ifdef DEBUG_ENABLED diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index ad23b75..c9d2a96 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -1,6 +1,6 @@ Name: dali2-toolkit Summary: Dali 3D engine Toolkit -Version: 2.0.51 +Version: 2.0.53 Release: 1 Group: System/Libraries License: Apache-2.0 and BSD-3-Clause and MIT