Support character-spacing tag in markup 89/271789/11
authorssabah <s.sabah@samsung.com>
Mon, 28 Feb 2022 21:45:57 +0000 (00:45 +0300)
committerssabah <s.sabah@samsung.com>
Sun, 27 Mar 2022 10:29:12 +0000 (13:29 +0300)
How to apply it in TextEditor:

    textEditor.SetProperty(Dali::Toolkit::TextEditor::Property::TEXT,
                           "Hello <char-spacing value='-3.0f'>Hello </char-spacing>"
                           "<char-spacing value='3.0f'>Hello </char-spacing>"
                           "<char-spacing value='-6.0f'>Hello </char-spacing>"
                           "<char-spacing value='6.0f'>Hello </char-spacing>"
                           "<char-spacing value='0.0f'>Hello </char-spacing>");
    textEditor.SetProperty(Dali::Toolkit::TextEditor::Property::ENABLE_MARKUP, true);

Change-Id: Ic24b6cd7e0b88fba175fdc008345956a8fa7980f

38 files changed:
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/text/character-spacing-character-run.h [new file with mode: 0644]
dali-toolkit/internal/text/character-spacing-glyph-run.h [new file with mode: 0644]
dali-toolkit/internal/text/cursor-helper-functions.cpp
dali-toolkit/internal/text/glyph-metrics-helper.cpp
dali-toolkit/internal/text/layouts/layout-engine-helper-functions.cpp
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/markup-processor-character-spacing.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-character-spacing.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/markup-processor.h
dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/text-controller-background-actor.cpp
dali-toolkit/internal/text/text-controller-impl-model-updater.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller-text-updater.cpp
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-selection-handle-controller.cpp
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h

index e22071a..e8bbb21 100644 (file)
@@ -116,7 +116,8 @@ void CreateTextModel(const std::string&                text,
                                       logicalModel->mUnderlinedCharacterRuns,
                                       logicalModel->mBackgroundColorRuns,
                                       logicalModel->mStrikethroughCharacterRuns,
                                       logicalModel->mUnderlinedCharacterRuns,
                                       logicalModel->mBackgroundColorRuns,
                                       logicalModel->mStrikethroughCharacterRuns,
-                                      logicalModel->mBoundedParagraphRuns);
+                                      logicalModel->mBoundedParagraphRuns,
+                                      logicalModel->mCharacterSpacingCharacterRuns);
 
   Length         textSize = 0u;
   const uint8_t* utf8     = NULL;
 
   Length         textSize = 0u;
   const uint8_t* utf8     = NULL;
index 7817c02..36117f7 100644 (file)
@@ -178,15 +178,16 @@ bool XHTMLEntityToUTF8Test(const XHTMLEntityToUTF8Data& data)
 {
   std::cout << "  testing " << data.description << std::endl;
 
 {
   std::cout << "  testing " << data.description << std::endl;
 
-  Vector<ColorRun>                  colorRuns;
-  Vector<FontDescriptionRun>        fontRuns;
-  Vector<EmbeddedItem>              items;
-  Vector<Anchor>                    anchors;
-  Vector<UnderlinedCharacterRun>    underlinedCharacterRuns;
-  Vector<ColorRun>                  backgroundColorRuns;
-  Vector<StrikethroughCharacterRun> strikethroughCharacterRuns;
-  Vector<BoundedParagraphRun>       boundedParagraphRuns;
-  MarkupProcessData                 markupProcessData(colorRuns, fontRuns, items, anchors, underlinedCharacterRuns, backgroundColorRuns, strikethroughCharacterRuns, boundedParagraphRuns);
+  Vector<ColorRun>                     colorRuns;
+  Vector<FontDescriptionRun>           fontRuns;
+  Vector<EmbeddedItem>                 items;
+  Vector<Anchor>                       anchors;
+  Vector<UnderlinedCharacterRun>       underlinedCharacterRuns;
+  Vector<ColorRun>                     backgroundColorRuns;
+  Vector<StrikethroughCharacterRun>    strikethroughCharacterRuns;
+  Vector<BoundedParagraphRun>          boundedParagraphRuns;
+  Vector<CharacterSpacingCharacterRun> characterSpacingCharacterRuns;
+  MarkupProcessData                    markupProcessData(colorRuns, fontRuns, items, anchors, underlinedCharacterRuns, backgroundColorRuns, strikethroughCharacterRuns, boundedParagraphRuns, characterSpacingCharacterRuns);
   ProcessMarkupString(data.xHTMLEntityString, markupProcessData);
 
   for(Vector<EmbeddedItem>::Iterator it    = items.Begin(),
   ProcessMarkupString(data.xHTMLEntityString, markupProcessData);
 
   for(Vector<EmbeddedItem>::Iterator it    = items.Begin(),
index d19326f..5f7328f 100644 (file)
@@ -1327,3 +1327,58 @@ int UtcDaliTextEditorMarkupParagraphTagAlignAttribute(void)
 
   END_TEST;
 }
 
   END_TEST;
 }
+
+int UtcDaliTextEditorMarkupCharacterSpacingTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupCharacterSpacingTag ");
+
+  const Length EXPECTED_NUMBER_OF_GLYPHS = 21u;
+
+  const float expandedCharSpacing  = 10.0f;
+  const float condensedCharSpacing = -5.0f;
+
+  TextEditor textEditor = TextEditor::New();
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, "ABC EF\n<char-spacing value='-5.0f'>ABC EF\n</char-spacing><char-spacing value='10.0f'>ABC EF\n</char-spacing>");
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.GetScene().Add(textEditor);
+
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextEditor& textEditorImpl = GetImpl(textEditor);
+  Text::ViewInterface&           view           = textEditorImpl.GetTextController()->GetView();
+
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+  DALI_TEST_EQUALS(numberOfGlyphs, EXPECTED_NUMBER_OF_GLYPHS, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+  Vector<GlyphInfo> glyphs;
+  glyphs.Resize(numberOfGlyphs);
+
+  Vector<Vector2> positions;
+  positions.Resize(numberOfGlyphs);
+
+  float alignmentOffset = 0u;
+  numberOfGlyphs        = view.GetGlyphs(glyphs.Begin(),
+                                  positions.Begin(),
+                                  alignmentOffset,
+                                  0u,
+                                  numberOfGlyphs);
+
+  const Length numberOfGlyphsOneLine = 7u;
+  for(Length i = 0; i < numberOfGlyphsOneLine - 1u; i++)
+  {
+    float diffLineNoCharSpacing = positions[i + 1].x - positions[i].x;
+
+    float diffLineCondensedCharSpacing = positions[numberOfGlyphsOneLine + i + 1].x - positions[numberOfGlyphsOneLine + i].x;
+    DALI_TEST_EQUALS(diffLineCondensedCharSpacing, diffLineNoCharSpacing + condensedCharSpacing, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+    float diffLineExpandedCharSpacing = positions[2u * numberOfGlyphsOneLine + i + 1].x - positions[2u * numberOfGlyphsOneLine + i].x;
+    DALI_TEST_EQUALS(diffLineExpandedCharSpacing, diffLineNoCharSpacing + expandedCharSpacing, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
\ No newline at end of file
index 02aa540..f8210dc 100644 (file)
@@ -1235,4 +1235,59 @@ int UtcDaliTextFieldMarkupStrikethroughNoEndTag(void)
   DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
 
   END_TEST;
   DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
 
   END_TEST;
+}
+
+int UtcDaliTextFieldMarkupCharacterSpacingTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupCharacterSpacingTag ");
+
+  const Length EXPECTED_NUMBER_OF_GLYPHS = 21u;
+
+  const float expandedCharSpacing  = 10.0f;
+  const float condensedCharSpacing = -5.0f;
+
+  TextField textField = TextField::New();
+
+  textField.SetProperty(TextField::Property::TEXT, "ABC EF\n<char-spacing value='-5.0f'>ABC EF\n</char-spacing><char-spacing value='10.0f'>ABC EF\n</char-spacing>");
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.GetScene().Add(textField);
+
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextField& textFieldImpl = GetImpl(textField);
+  Text::ViewInterface&          view          = textFieldImpl.GetTextController()->GetView();
+
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+  DALI_TEST_EQUALS(numberOfGlyphs, EXPECTED_NUMBER_OF_GLYPHS, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+  Vector<GlyphInfo> glyphs;
+  glyphs.Resize(numberOfGlyphs);
+
+  Vector<Vector2> positions;
+  positions.Resize(numberOfGlyphs);
+
+  float alignmentOffset = 0u;
+  numberOfGlyphs        = view.GetGlyphs(glyphs.Begin(),
+                                  positions.Begin(),
+                                  alignmentOffset,
+                                  0u,
+                                  numberOfGlyphs);
+
+  const Length numberOfGlyphsOneLine = 7u;
+  for(Length i = 0; i < numberOfGlyphsOneLine - 1u; i++)
+  {
+    float diffLineNoCharSpacing = positions[i + 1].x - positions[i].x;
+
+    float diffLineCondensedCharSpacing = positions[numberOfGlyphsOneLine + i + 1].x - positions[numberOfGlyphsOneLine + i].x;
+    DALI_TEST_EQUALS(diffLineCondensedCharSpacing, diffLineNoCharSpacing + condensedCharSpacing, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+    float diffLineExpandedCharSpacing = positions[2u * numberOfGlyphsOneLine + i + 1].x - positions[2u * numberOfGlyphsOneLine + i].x;
+    DALI_TEST_EQUALS(diffLineExpandedCharSpacing, diffLineNoCharSpacing + expandedCharSpacing, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+  }
+
+  END_TEST;
 }
\ No newline at end of file
 }
\ No newline at end of file
index 1ac00b5..2f1d1c6 100644 (file)
@@ -1221,3 +1221,59 @@ int UtcDaliTextLabelMarkupParagraphTagAlignAttribute(void)
 
   END_TEST;
 }
 
   END_TEST;
 }
+
+int UtcDaliTextLabelMarkupCharacterSpacingTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupCharacterSpacingTag ");
+
+  const Length EXPECTED_NUMBER_OF_GLYPHS = 21u;
+
+  const float expandedCharSpacing  = 10.0f;
+  const float condensedCharSpacing = -5.0f;
+
+  TextLabel textLabel = TextLabel::New();
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, "ABC EF\n<char-spacing value='-5.0f'>ABC EF\n</char-spacing><char-spacing value='10.0f'>ABC EF\n</char-spacing>");
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+  textLabel.SetProperty(TextLabel::Property::MULTI_LINE, true);
+
+  application.GetScene().Add(textLabel);
+
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextLabel& textLabelImpl = GetImpl(textLabel);
+  Text::ViewInterface&          view          = textLabelImpl.GetTextController()->GetView();
+
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+  DALI_TEST_EQUALS(numberOfGlyphs, EXPECTED_NUMBER_OF_GLYPHS, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+  Vector<GlyphInfo> glyphs;
+  glyphs.Resize(numberOfGlyphs);
+
+  Vector<Vector2> positions;
+  positions.Resize(numberOfGlyphs);
+
+  float alignmentOffset = 0u;
+  numberOfGlyphs        = view.GetGlyphs(glyphs.Begin(),
+                                  positions.Begin(),
+                                  alignmentOffset,
+                                  0u,
+                                  numberOfGlyphs);
+
+  const Length numberOfGlyphsOneLine = 7u;
+  for(Length i = 0; i < numberOfGlyphsOneLine - 1u; i++)
+  {
+    float diffLineNoCharSpacing = positions[i + 1].x - positions[i].x;
+
+    float diffLineCondensedCharSpacing = positions[numberOfGlyphsOneLine + i + 1].x - positions[numberOfGlyphsOneLine + i].x;
+    DALI_TEST_EQUALS(diffLineCondensedCharSpacing, diffLineNoCharSpacing + condensedCharSpacing, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+
+    float diffLineExpandedCharSpacing = positions[2u * numberOfGlyphsOneLine + i + 1].x - positions[2u * numberOfGlyphsOneLine + i].x;
+    DALI_TEST_EQUALS(diffLineExpandedCharSpacing, diffLineNoCharSpacing + expandedCharSpacing, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
\ No newline at end of file
index 7b5e36e..c9ab7b5 100644 (file)
@@ -36,6 +36,7 @@
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 #include <dali-toolkit/internal/text/markup-processor.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 #include <dali-toolkit/internal/text/markup-processor.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
@@ -178,7 +179,8 @@ void ShapeTextPreprocess(const RendererParameters& textParameters, TextAbstracti
                                       textModel->mLogicalModel->mUnderlinedCharacterRuns,
                                       textModel->mLogicalModel->mBackgroundColorRuns,
                                       textModel->mLogicalModel->mStrikethroughCharacterRuns,
                                       textModel->mLogicalModel->mUnderlinedCharacterRuns,
                                       textModel->mLogicalModel->mBackgroundColorRuns,
                                       textModel->mLogicalModel->mStrikethroughCharacterRuns,
-                                      textModel->mLogicalModel->mBoundedParagraphRuns);
+                                      textModel->mLogicalModel->mBoundedParagraphRuns,
+                                      textModel->mLogicalModel->mCharacterSpacingCharacterRuns);
 
   if(textParameters.markupEnabled)
   {
 
   if(textParameters.markupEnabled)
   {
@@ -819,10 +821,14 @@ void Ellipsis(const RendererParameters& textParameters, TextAbstraction::TextRen
   Vector<LineRun>&        lines                     = textModel->mVisualModel->mLines; // The laid out lines.
   Vector<bool>&           isEmoji                   = internalDataModel.isEmoji;
   const Size              textLayoutArea            = internalDataModel.textLayoutArea;
   Vector<LineRun>&        lines                     = textModel->mVisualModel->mLines; // The laid out lines.
   Vector<bool>&           isEmoji                   = internalDataModel.isEmoji;
   const Size              textLayoutArea            = internalDataModel.textLayoutArea;
-  const float             characterSpacing          = textModel->mVisualModel->GetCharacterSpacing();
+  const float             modelCharacterSpacing     = textModel->mVisualModel->GetCharacterSpacing();
   float                   calculatedAdvance         = 0.f;
   Vector<CharacterIndex>& glyphToCharacterMap       = textModel->mVisualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
   float                   calculatedAdvance         = 0.f;
   Vector<CharacterIndex>& glyphToCharacterMap       = textModel->mVisualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = textModel->mVisualModel->GetCharacterSpacingGlyphRuns();
+
   ////////////////////////////////////////////////////////////////////////////////
   // Ellipsis the text.
   ////////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////////
   // Ellipsis the text.
   ////////////////////////////////////////////////////////////////////////////////
@@ -908,7 +914,8 @@ void Ellipsis(const RendererParameters& textParameters, TextAbstraction::TextRen
                 firstPenSet = true;
               }
 
                 firstPenSet = true;
               }
 
-              calculatedAdvance = GetCalculatedAdvance(*(textModel->mLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + index))), characterSpacing, glyphToRemove.advance);
+              const float characterSpacing = GetGlyphCharacterSpacing(index, characterSpacingGlyphRuns, modelCharacterSpacing);
+              calculatedAdvance            = GetCalculatedAdvance(*(textModel->mLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + index))), characterSpacing, glyphToRemove.advance);
               removedGlypsWidth += std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width));
 
               // Calculate the width of the ellipsis glyph and check if it fits.
               removedGlypsWidth += std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width));
 
               // Calculate the width of the ellipsis glyph and check if it fits.
index 7e9c1aa..65d46fb 100644 (file)
@@ -154,6 +154,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/markup-processor-span.cpp
    ${toolkit_src_dir}/text/markup-processor-strikethrough.cpp
    ${toolkit_src_dir}/text/markup-processor-underline.cpp
    ${toolkit_src_dir}/text/markup-processor-span.cpp
    ${toolkit_src_dir}/text/markup-processor-strikethrough.cpp
    ${toolkit_src_dir}/text/markup-processor-underline.cpp
+   ${toolkit_src_dir}/text/markup-processor-character-spacing.cpp
    ${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
    ${toolkit_src_dir}/text/markup-processor-attribute-helper-functions.cpp
    ${toolkit_src_dir}/text/multi-language-support.cpp
    ${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
    ${toolkit_src_dir}/text/markup-processor-attribute-helper-functions.cpp
    ${toolkit_src_dir}/text/multi-language-support.cpp
@@ -203,7 +204,8 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/rendering/text-typesetter.cpp
    ${toolkit_src_dir}/text/rendering/view-model.cpp
    ${toolkit_src_dir}/text/rendering/styles/underline-helper-functions.cpp
    ${toolkit_src_dir}/text/rendering/text-typesetter.cpp
    ${toolkit_src_dir}/text/rendering/view-model.cpp
    ${toolkit_src_dir}/text/rendering/styles/underline-helper-functions.cpp
-   ${toolkit_src_dir}/text/rendering/styles/strikethrough-helper-functions
+   ${toolkit_src_dir}/text/rendering/styles/strikethrough-helper-functions.cpp
+   ${toolkit_src_dir}/text/rendering/styles/character-spacing-helper-functions.cpp
    ${toolkit_src_dir}/transition/fade-transition-impl.cpp
    ${toolkit_src_dir}/transition/slide-transition-impl.cpp
    ${toolkit_src_dir}/transition/scale-transition-impl.cpp
    ${toolkit_src_dir}/transition/fade-transition-impl.cpp
    ${toolkit_src_dir}/transition/slide-transition-impl.cpp
    ${toolkit_src_dir}/transition/scale-transition-impl.cpp
diff --git a/dali-toolkit/internal/text/character-spacing-character-run.h b/dali-toolkit/internal/text/character-spacing-character-run.h
new file mode 100644 (file)
index 0000000..5c4238e
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_TOOLKIT_TEXT_CHARACTER_SPACING_CHARACTER_RUN_H
+#define DALI_TOOLKIT_TEXT_CHARACTER_SPACING_CHARACTER_RUN_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Run of character-spacing characters with same properties.
+ */
+struct CharacterSpacingCharacterRun
+{
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  CharacterSpacingCharacterRun()
+  : characterRun{},
+    value{0.f} //The default value is 0.f which does nothing.
+  {
+  }
+
+  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
+  float        value;        /// The spaces between characters in Pixels. A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
+
+  //TODO: Add unit property to choose between Pixel or Scale (%)
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CHARACTER_SPACING_CHARACTER_RUN_H
diff --git a/dali-toolkit/internal/text/character-spacing-glyph-run.h b/dali-toolkit/internal/text/character-spacing-glyph-run.h
new file mode 100644 (file)
index 0000000..7375533
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef DALI_TOOLKIT_TEXT_CHARACTER_SPACING_GLYPH_RUN_H
+#define DALI_TOOLKIT_TEXT_CHARACTER_SPACING_GLYPH_RUN_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/glyph-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Run of character-spacing glyphs with same properties.
+ */
+struct CharacterSpacingGlyphRun
+{
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  CharacterSpacingGlyphRun()
+  : glyphRun{},
+    value{0.f} //The default value is 0.f which does nothing.
+  {
+  }
+
+  GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs in the run.
+  float    value;    ///< The spaces between characters in Pixels.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CHARACTER_SPACING_GLYPH_RUN_H
index 3bfc059..3b3bf44 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 
 namespace
 {
 
 namespace
 {
@@ -214,7 +215,10 @@ CharacterIndex GetClosestCursorIndex(VisualModelPtr         visualModel,
   {
     return logicalIndex;
   }
   {
     return logicalIndex;
   }
-  const float characterSpacing = visualModel->GetCharacterSpacing();
+
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
+  const float                             modelCharacterSpacing     = visualModel->GetCharacterSpacing();
 
   // Whether there is a hit on a line.
   bool matchedLine = false;
 
   // Whether there is a hit on a line.
   bool matchedLine = false;
@@ -289,7 +293,8 @@ CharacterIndex GetClosestCursorIndex(VisualModelPtr         visualModel,
 
       // Get the metrics for the group of glyphs.
       GlyphMetrics glyphMetrics;
 
       // Get the metrics for the group of glyphs.
       GlyphMetrics glyphMetrics;
-      calculatedAdvance = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + firstLogicalGlyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + firstLogicalGlyphIndex)).advance);
+      const float  characterSpacing = GetGlyphCharacterSpacing(firstLogicalGlyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+      calculatedAdvance             = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + firstLogicalGlyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + firstLogicalGlyphIndex)).advance);
       GetGlyphsMetrics(firstLogicalGlyphIndex,
                        numberOfGlyphs,
                        glyphMetrics,
       GetGlyphsMetrics(firstLogicalGlyphIndex,
                        numberOfGlyphs,
                        glyphMetrics,
@@ -606,7 +611,9 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
     const Length* const         charactersPerGlyphBuffer = parameters.visualModel->mCharactersPerGlyph.Begin();
     const CharacterIndex* const glyphsToCharactersBuffer = parameters.visualModel->mGlyphsToCharacters.Begin();
     const Vector2* const        glyphPositionsBuffer     = parameters.visualModel->mGlyphPositions.Begin();
     const Length* const         charactersPerGlyphBuffer = parameters.visualModel->mCharactersPerGlyph.Begin();
     const CharacterIndex* const glyphsToCharactersBuffer = parameters.visualModel->mGlyphsToCharacters.Begin();
     const Vector2* const        glyphPositionsBuffer     = parameters.visualModel->mGlyphPositions.Begin();
-    const float                 characterSpacing         = parameters.visualModel->GetCharacterSpacing();
+    const float                 modelCharacterSpacing    = parameters.visualModel->GetCharacterSpacing();
+
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = parameters.visualModel->GetCharacterSpacingGlyphRuns();
 
     // Get the metrics for the group of glyphs.
     GetGlyphMetricsFromCharacterIndex(index, parameters.visualModel, parameters.logicalModel, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
 
     // Get the metrics for the group of glyphs.
     GetGlyphMetricsFromCharacterIndex(index, parameters.visualModel, parameters.logicalModel, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
@@ -723,6 +730,7 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
       const bool addGlyphAdvance = ((!isFirstPositionOfLine && !isCurrentRightToLeft) ||
                                     (isFirstPositionOfLine && !isRightToLeftParagraph));
 
       const bool addGlyphAdvance = ((!isFirstPositionOfLine && !isCurrentRightToLeft) ||
                                     (isFirstPositionOfLine && !isRightToLeftParagraph));
 
+      const float characterSpacing   = GetGlyphCharacterSpacing(secondaryGlyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
       cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + (addGlyphAdvance ? (glyphMetrics.advance + characterSpacing) : 0.f);
       cursorInfo.secondaryPosition.y = cursorInfo.lineOffset + cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight;
 
       cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + (addGlyphAdvance ? (glyphMetrics.advance + characterSpacing) : 0.f);
       cursorInfo.secondaryPosition.y = cursorInfo.lineOffset + cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight;
 
index 01c62c7..c46fefd 100644 (file)
@@ -19,6 +19,9 @@
 // FILE HEADER
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 
 // FILE HEADER
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
+
 namespace Dali
 {
 namespace Toolkit
 namespace Dali
 {
 namespace Toolkit
@@ -114,7 +117,10 @@ void GetGlyphMetricsFromCharacterIndex(CharacterIndex         index,
   const GlyphInfo* const  glyphInfoBuffer           = visualModel->mGlyphs.Begin();
   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
   const GlyphInfo* const  glyphInfoBuffer           = visualModel->mGlyphs.Begin();
   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
-  const float             characterSpacing          = visualModel->GetCharacterSpacing();
+  const float             modelCharacterSpacing     = visualModel->GetCharacterSpacing();
+
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
 
   //Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
   glyphIndex     = *(charactersToGlyphBuffer + index);
 
   //Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
   glyphIndex     = *(charactersToGlyphBuffer + index);
@@ -122,7 +128,8 @@ void GetGlyphMetricsFromCharacterIndex(CharacterIndex         index,
 
   float calculatedAdvance = 0.f;
 
 
   float calculatedAdvance = 0.f;
 
-  calculatedAdvance = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + glyphIndex)).advance);
+  const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+  calculatedAdvance            = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(visualModel->mGlyphs.Begin() + glyphIndex)).advance);
 
   // Get the metrics for the group of glyphs.
   GetGlyphsMetrics(glyphIndex,
 
   // Get the metrics for the group of glyphs.
   GetGlyphsMetrics(glyphIndex,
index 85676cf..db2fddf 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDE
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 
 // INTERNAL INCLUDE
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 
 namespace Dali
 {
 
 namespace Dali
 {
@@ -38,13 +39,16 @@ void CalculateGlyphPositionsLTR(const VisualModelPtr&  visualModel,
                                 Vector2*               glyphPositionsBuffer,
                                 float&                 penX)
 {
                                 Vector2*               glyphPositionsBuffer,
                                 float&                 penX)
 {
-  const GlyphInfo* const glyphsBuffer     = visualModel->mGlyphs.Begin();
-  const float            characterSpacing = visualModel->GetCharacterSpacing();
-  const Character* const textBuffer       = logicalModel->mText.Begin();
+  const GlyphInfo* const glyphsBuffer          = visualModel->mGlyphs.Begin();
+  const float            modelCharacterSpacing = visualModel->GetCharacterSpacing();
+  const Character* const textBuffer            = logicalModel->mText.Begin();
 
   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
 
   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
+
   float calculatedAdvance = 0.f;
 
   for(GlyphIndex i = 0u; i < numberOfGlyphs; ++i)
   float calculatedAdvance = 0.f;
 
   for(GlyphIndex i = 0u; i < numberOfGlyphs; ++i)
@@ -55,7 +59,8 @@ void CalculateGlyphPositionsLTR(const VisualModelPtr&  visualModel,
     position.x = penX + glyph.xBearing;
     position.y = -glyph.yBearing;
 
     position.x = penX + glyph.xBearing;
     position.y = -glyph.yBearing;
 
-    calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + (startIndexForGlyph + i)))), characterSpacing, glyph.advance);
+    const float characterSpacing = GetGlyphCharacterSpacing((startIndexForGlyph + i), characterSpacingGlyphRuns, modelCharacterSpacing);
+    calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + (startIndexForGlyph + i)))), characterSpacing, glyph.advance);
     penX += (calculatedAdvance + interGlyphExtraAdvance);
   }
 }
     penX += (calculatedAdvance + interGlyphExtraAdvance);
   }
 }
@@ -73,7 +78,10 @@ void CalculateGlyphPositionsRTL(const VisualModelPtr&            visualModel,
   const BidirectionalLineInfoRun& bidiLine                 = logicalModel->mBidirectionalLineInfo[bidiLineIndex];
   const GlyphInfo* const          glyphsBuffer             = visualModel->mGlyphs.Begin();
   const GlyphIndex* const         charactersToGlyphsBuffer = visualModel->mCharactersToGlyph.Begin();
   const BidirectionalLineInfoRun& bidiLine                 = logicalModel->mBidirectionalLineInfo[bidiLineIndex];
   const GlyphInfo* const          glyphsBuffer             = visualModel->mGlyphs.Begin();
   const GlyphIndex* const         charactersToGlyphsBuffer = visualModel->mCharactersToGlyph.Begin();
-  const float                     characterSpacing         = visualModel->GetCharacterSpacing();
+  const float                     modelCharacterSpacing    = visualModel->GetCharacterSpacing();
+
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
 
   float calculatedAdvance = 0.f;
 
 
   float calculatedAdvance = 0.f;
 
@@ -86,7 +94,8 @@ void CalculateGlyphPositionsRTL(const VisualModelPtr&            visualModel,
     position.x        = penX;
     position.y        = -glyph.yBearing;
 
     position.x        = penX;
     position.y        = -glyph.yBearing;
 
-    calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyph.advance);
+    const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+    calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyph.advance);
     penX += calculatedAdvance;
 
     ++characterLogicalIndex;
     penX += calculatedAdvance;
 
     ++characterLogicalIndex;
@@ -106,9 +115,12 @@ void TraversesCharactersForGlyphPositionsRTL(const VisualModelPtr&  visualModel,
 {
   const GlyphInfo* const  glyphsBuffer             = visualModel->mGlyphs.Begin();
   const GlyphIndex* const charactersToGlyphsBuffer = visualModel->mCharactersToGlyph.Begin();
 {
   const GlyphInfo* const  glyphsBuffer             = visualModel->mGlyphs.Begin();
   const GlyphIndex* const charactersToGlyphsBuffer = visualModel->mCharactersToGlyph.Begin();
-  const float             characterSpacing         = visualModel->GetCharacterSpacing();
+  const float             modelCharacterSpacing    = visualModel->GetCharacterSpacing();
   const Length* const     glyphsPerCharacterBuffer = visualModel->mGlyphsPerCharacter.Begin();
 
   const Length* const     glyphsPerCharacterBuffer = visualModel->mGlyphsPerCharacter.Begin();
 
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
+
   float calculatedAdvance = 0.f;
 
   for(; characterLogicalIndex < bidiLineCharacterRun.numberOfCharacters;
   float calculatedAdvance = 0.f;
 
   for(; characterLogicalIndex < bidiLineCharacterRun.numberOfCharacters;
@@ -133,7 +145,8 @@ void TraversesCharactersForGlyphPositionsRTL(const VisualModelPtr&  visualModel,
       position.x = penX + glyph.xBearing;
       position.y = -glyph.yBearing;
 
       position.x = penX + glyph.xBearing;
       position.y = -glyph.yBearing;
 
-      calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyph.advance);
+      const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+      calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyph.advance);
       penX += (calculatedAdvance + interGlyphExtraAdvance);
     }
   }
       penX += (calculatedAdvance + interGlyphExtraAdvance);
     }
   }
index aff78c6..3fcc82c 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 #include <dali-toolkit/internal/text/layouts/layout-engine-helper-functions.h>
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 #include <dali-toolkit/internal/text/layouts/layout-engine-helper-functions.h>
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 
 namespace Dali
 {
 
 namespace Dali
 {
@@ -299,7 +300,10 @@ struct Engine::Impl
 
     const float      outlineWidth                = static_cast<float>(parameters.textModel->GetOutlineWidth());
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
 
     const float      outlineWidth                = static_cast<float>(parameters.textModel->GetOutlineWidth());
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
-    const float      characterSpacing            = parameters.textModel->mVisualModel->GetCharacterSpacing();
+    const float      modelCharacterSpacing       = parameters.textModel->mVisualModel->GetCharacterSpacing();
+
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = parameters.textModel->mVisualModel->GetCharacterSpacingGlyphRuns();
 
     CharacterIndex characterLogicalIndex = 0u;
     CharacterIndex characterVisualIndex  = 0u;
 
     CharacterIndex characterLogicalIndex = 0u;
     CharacterIndex characterVisualIndex  = 0u;
@@ -330,7 +334,8 @@ struct Engine::Impl
         {
           const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
         {
           const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
-          calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
+          const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+          calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
           whiteSpaceLengthEndOfLine += calculatedAdvance;
 
           ++characterLogicalIndex;
           whiteSpaceLengthEndOfLine += calculatedAdvance;
 
           ++characterLogicalIndex;
@@ -352,7 +357,8 @@ struct Engine::Impl
         {
           const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
         {
           const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
-          calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
+          const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+          calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
           whiteSpaceLengthEndOfLine += calculatedAdvance;
 
           ++characterLogicalIndex;
           whiteSpaceLengthEndOfLine += calculatedAdvance;
 
           ++characterLogicalIndex;
@@ -370,7 +376,8 @@ struct Engine::Impl
                                                                   charactersPerGlyphBuffer);
 
     GlyphMetrics glyphMetrics;
                                                                   charactersPerGlyphBuffer);
 
     GlyphMetrics glyphMetrics;
-    calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
+    const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+    calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
     GetGlyphsMetrics(glyphIndex,
                      numberOfGLyphsInGroup,
                      glyphMetrics,
     GetGlyphsMetrics(glyphIndex,
                      numberOfGLyphsInGroup,
                      glyphMetrics,
@@ -401,7 +408,8 @@ struct Engine::Impl
         characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
 
         GlyphMetrics glyphMetrics;
         characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
 
         GlyphMetrics glyphMetrics;
-        calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
+        const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+        calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
         GetGlyphsMetrics(glyphIndex,
                          numberOfGLyphsInGroup,
                          glyphMetrics,
         GetGlyphsMetrics(glyphIndex,
                          numberOfGLyphsInGroup,
                          glyphMetrics,
@@ -463,7 +471,8 @@ struct Engine::Impl
       characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
 
       GlyphMetrics glyphMetrics;
       characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
 
       GlyphMetrics glyphMetrics;
-      calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
+      const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+      calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
       GetGlyphsMetrics(glyphIndex,
                        numberOfGLyphsInGroup,
                        glyphMetrics,
       GetGlyphsMetrics(glyphIndex,
                        numberOfGLyphsInGroup,
                        glyphMetrics,
@@ -700,13 +709,17 @@ struct Engine::Impl
 
     bool isSecondHalf = false;
     // Character Spacing
 
     bool isSecondHalf = false;
     // Character Spacing
-    const float             characterSpacing          = parameters.textModel->mVisualModel->GetCharacterSpacing();
+    const float             modelCharacterSpacing     = parameters.textModel->mVisualModel->GetCharacterSpacing();
     float                   calculatedAdvance         = 0.f;
     Vector<CharacterIndex>& glyphToCharacterMap       = parameters.textModel->mVisualModel->mGlyphsToCharacters;
     const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
     float                   calculatedAdvance         = 0.f;
     Vector<CharacterIndex>& glyphToCharacterMap       = parameters.textModel->mVisualModel->mGlyphsToCharacters;
     const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = parameters.textModel->mVisualModel->GetCharacterSpacingGlyphRuns();
+
     GlyphMetrics glyphMetrics;
     GlyphMetrics glyphMetrics;
-    calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance);
+    const float  characterSpacing = GetGlyphCharacterSpacing(lineLayout.glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+    calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance);
     GetGlyphsMetrics(lineLayout.glyphIndex,
                      numberOfGLyphsInGroup,
                      glyphMetrics,
     GetGlyphsMetrics(lineLayout.glyphIndex,
                      numberOfGLyphsInGroup,
                      glyphMetrics,
@@ -747,7 +760,8 @@ struct Engine::Impl
                                                                     charactersPerGlyphBuffer);
 
       GlyphMetrics glyphMetrics;
                                                                     charactersPerGlyphBuffer);
 
       GlyphMetrics glyphMetrics;
-      calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
+      const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+      calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
       GetGlyphsMetrics(glyphIndex,
                        numberOfGLyphsInGroup,
                        glyphMetrics,
       GetGlyphsMetrics(glyphIndex,
                        numberOfGLyphsInGroup,
                        glyphMetrics,
@@ -847,7 +861,8 @@ struct Engine::Impl
         while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex)
         {
           GlyphMetrics glyphMetrics;
         while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex)
         {
           GlyphMetrics glyphMetrics;
-          calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance);
+          const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndexToRemove, characterSpacingGlyphRuns, modelCharacterSpacing);
+          calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance);
           GetGlyphsMetrics(glyphIndexToRemove,
                            numberOfGLyphsInGroup,
                            glyphMetrics,
           GetGlyphsMetrics(glyphIndexToRemove,
                            numberOfGLyphsInGroup,
                            glyphMetrics,
index 9ad00bc..7ebf2a7 100644 (file)
@@ -345,6 +345,13 @@ void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharact
                                            totalNumberOfCharacters,
                                            mBoundedParagraphRuns,
                                            removedBoundedParagraphRuns);
                                            totalNumberOfCharacters,
                                            mBoundedParagraphRuns,
                                            removedBoundedParagraphRuns);
+
+  Vector<CharacterSpacingCharacterRun> removedCharacterSpacingCharacterRuns;
+  UpdateCharacterRuns<CharacterSpacingCharacterRun>(index,
+                                                    numberOfCharacters,
+                                                    totalNumberOfCharacters,
+                                                    mCharacterSpacingCharacterRuns,
+                                                    removedCharacterSpacingCharacterRuns);
 }
 
 void LogicalModel::RetrieveStyle(CharacterIndex index, InputStyle& style)
 }
 
 void LogicalModel::RetrieveStyle(CharacterIndex index, InputStyle& style)
@@ -624,6 +631,16 @@ const Vector<BoundedParagraphRun>& LogicalModel::GetBoundedParagraphRuns() const
   return mBoundedParagraphRuns;
 }
 
   return mBoundedParagraphRuns;
 }
 
+Length LogicalModel::GetNumberOfCharacterSpacingCharacterRuns() const
+{
+  return mCharacterSpacingCharacterRuns.Count();
+}
+
+const Vector<CharacterSpacingCharacterRun>& LogicalModel::GetCharacterSpacingCharacterRuns() const
+{
+  return mCharacterSpacingCharacterRuns;
+}
+
 void LogicalModel::ClearEmbeddedImages()
 {
   FreeEmbeddedItems(mEmbeddedItems);
 void LogicalModel::ClearEmbeddedImages()
 {
   FreeEmbeddedItems(mEmbeddedItems);
index c54c523..0fa3df2 100644 (file)
@@ -28,6 +28,7 @@
 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
 #include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
 #include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/character-spacing-character-run.h>
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/embedded-item.h>
 #include <dali-toolkit/internal/text/font-description-run.h>
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/embedded-item.h>
 #include <dali-toolkit/internal/text/font-description-run.h>
@@ -197,6 +198,20 @@ public:
    */
   const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const;
 
    */
   const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const;
 
+  /**
+   * @brief Retrieves the number of character-spacing runs.
+   *
+   * @return The number of character-spacing runs.
+   */
+  Length GetNumberOfCharacterSpacingCharacterRuns() const;
+
+  /**
+   * @brief Retrieves the reference for character-spacing runs.
+   *
+   * @return The reference for character-spacing runs.
+   */
+  const Vector<CharacterSpacingCharacterRun>& GetCharacterSpacingCharacterRuns() const;
+
   // Embedded images
 
   /**
   // Embedded images
 
   /**
@@ -241,9 +256,10 @@ public:
   Vector<BidirectionalLineInfoRun>      mBidirectionalLineInfo;
   Vector<EmbeddedItem>                  mEmbeddedItems;
   Vector<Anchor>                        mAnchors;
   Vector<BidirectionalLineInfoRun>      mBidirectionalLineInfo;
   Vector<EmbeddedItem>                  mEmbeddedItems;
   Vector<Anchor>                        mAnchors;
-  Vector<UnderlinedCharacterRun>        mUnderlinedCharacterRuns;    ///< The underlined character run from markup-processor
-  Vector<StrikethroughCharacterRun>     mStrikethroughCharacterRuns; ///< The strikethrough character run from markup-processor
-  Vector<BoundedParagraphRun>           mBoundedParagraphRuns;       ///< The bounded paragraph is used to handle a paragraph mark-up tag and it's attributes. Like TextAlign, TextDirection, TextIndent, LineHeight, etc.
+  Vector<UnderlinedCharacterRun>        mUnderlinedCharacterRuns;       ///< The underlined character run from markup-processor
+  Vector<StrikethroughCharacterRun>     mStrikethroughCharacterRuns;    ///< The strikethrough character run from markup-processor
+  Vector<BoundedParagraphRun>           mBoundedParagraphRuns;          ///< The bounded paragraph is used to handle a paragraph mark-up tag and it's attributes. Like TextAlign, TextDirection, TextIndent, LineHeight, etc.
+  Vector<CharacterSpacingCharacterRun>  mCharacterSpacingCharacterRuns; ///< The character-spacing character run from markup-processor.
 
   BidirectionalLineRunIndex mBidirectionalLineIndex; ///< The last fetched bidirectional line info.
 };
 
   BidirectionalLineRunIndex mBidirectionalLineIndex; ///< The last fetched bidirectional line info.
 };
diff --git a/dali-toolkit/internal/text/markup-processor-character-spacing.cpp b/dali-toolkit/internal/text/markup-processor-character-spacing.cpp
new file mode 100644 (file)
index 0000000..f0ef362
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022 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 <dali-toolkit/internal/text/markup-processor-character-spacing.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-spacing-character-run.h>
+#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string XHTML_VALUE_ATTRIBUTE("value");
+
+} // namespace
+
+void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
+{
+  characterSpacingCharacterRun.value = ProcessFloatAttribute(attribute);
+}
+
+void ProcessCharacterSpacingTag(const Tag& tag, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
+{
+  for(Vector<Attribute>::ConstIterator it    = tag.attributes.Begin(),
+                                       endIt = tag.attributes.End();
+      it != endIt;
+      ++it)
+  {
+    const Attribute& attribute(*it);
+
+    if(TokenComparison(XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessValueAttribute(attribute, characterSpacingCharacterRun);
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-character-spacing.h b/dali-toolkit/internal/text/markup-processor-character-spacing.h
new file mode 100644 (file)
index 0000000..b8b9beb
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct Attribute;
+struct CharacterSpacingCharacterRun;
+
+/**
+ * @brief Fill the character-spacing character run with the value (space or advance) attribute.
+ *
+ * @param[in] attribute the value attribute.
+ * @param[out] characterSpacingCharacterRun The underlined character run
+ */
+void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun);
+
+/**
+ * @brief Retrieves the character-spacing run info from the tag and sets it to the character-spacing run.
+ *
+ * @param[in] tag The character-spacing tag and its attributes.
+ * @param[in,out] characterSpacingCharacterRun The character-spacing character run
+ */
+void ProcessCharacterSpacingTag(const Tag& tag, CharacterSpacingCharacterRun& characterSpacingCharacterRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
index 9c26b39..a11b303 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 #include <dali-toolkit/internal/text/markup-processor-anchor.h>
 #include <dali-toolkit/internal/text/markup-processor-background.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 #include <dali-toolkit/internal/text/markup-processor-anchor.h>
 #include <dali-toolkit/internal/text/markup-processor-background.h>
+#include <dali-toolkit/internal/text/markup-processor-character-spacing.h>
 #include <dali-toolkit/internal/text/markup-processor-color.h>
 #include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
 #include <dali-toolkit/internal/text/markup-processor-font.h>
 #include <dali-toolkit/internal/text/markup-processor-color.h>
 #include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
 #include <dali-toolkit/internal/text/markup-processor-font.h>
@@ -62,6 +63,7 @@ const std::string XHTML_BACKGROUND_TAG("background");
 const std::string XHTML_SPAN_TAG("span");
 const std::string XHTML_STRIKETHROUGH_TAG("s");
 const std::string XHTML_PARAGRAPH_TAG("p");
 const std::string XHTML_SPAN_TAG("span");
 const std::string XHTML_STRIKETHROUGH_TAG("s");
 const std::string XHTML_PARAGRAPH_TAG("p");
+const std::string XHTML_CHARACTER_SPACING_TAG("char-spacing");
 
 const char LESS_THAN      = '<';
 const char GREATER_THAN   = '>';
 
 const char LESS_THAN      = '<';
 const char GREATER_THAN   = '>';
@@ -240,6 +242,18 @@ void Initialize(BoundedParagraphRun& boundedParagraphRun)
 }
 
 /**
 }
 
 /**
+ * @brief Initializes a character-spacing run to its defaults.
+ *
+ * @param[in,out] characterSpacingCharacterRun The character-spacing run to initialize.
+ */
+void Initialize(CharacterSpacingCharacterRun& characterSpacingCharacterRun)
+{
+  characterSpacingCharacterRun.characterRun.characterIndex     = 0u;
+  characterSpacingCharacterRun.characterRun.numberOfCharacters = 0u;
+  characterSpacingCharacterRun.value                           = 0.0f;
+}
+
+/**
  * @brief Splits the tag string into the tag name and its attributes.
  *
  * The attributes are stored in a vector in the tag.
  * @brief Splits the tag string into the tag name and its attributes.
  *
  * The attributes are stored in a vector in the tag.
@@ -893,6 +907,7 @@ void ProcessSpanForRun(
  * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
  * @param[in] backgroundRunIndex The background run index
  * @param[in] boundedParagraphRunIndex The bounded paragraph run index
  * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
  * @param[in] backgroundRunIndex The background run index
  * @param[in] boundedParagraphRunIndex The bounded paragraph run index
+ * @param[in] characterSpacingCharacterRunIndex The character-spacing character run index
  *
  */
 void ResizeModelVectors(MarkupProcessData& markupProcessData,
  *
  */
 void ResizeModelVectors(MarkupProcessData& markupProcessData,
@@ -901,7 +916,8 @@ void ResizeModelVectors(MarkupProcessData& markupProcessData,
                         const RunIndex     underlinedCharacterRunIndex,
                         const RunIndex     strikethroughCharacterRunIndex,
                         const RunIndex     backgroundRunIndex,
                         const RunIndex     underlinedCharacterRunIndex,
                         const RunIndex     strikethroughCharacterRunIndex,
                         const RunIndex     backgroundRunIndex,
-                        const RunIndex     boundedParagraphRunIndex)
+                        const RunIndex     boundedParagraphRunIndex,
+                        const RunIndex     characterSpacingCharacterRunIndex)
 {
   markupProcessData.fontRuns.Resize(fontRunIndex);
   markupProcessData.colorRuns.Resize(colorRunIndex);
 {
   markupProcessData.fontRuns.Resize(fontRunIndex);
   markupProcessData.colorRuns.Resize(colorRunIndex);
@@ -909,6 +925,7 @@ void ResizeModelVectors(MarkupProcessData& markupProcessData,
   markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
   markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
   markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
   markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
   markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
   markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
+  markupProcessData.characterSpacingCharacterRuns.Resize(characterSpacingCharacterRunIndex);
 
 #ifdef DEBUG_ENABLED
   for(unsigned int i = 0; i < colorRunIndex; ++i)
 
 #ifdef DEBUG_ENABLED
   for(unsigned int i = 0; i < colorRunIndex; ++i)
@@ -1028,23 +1045,25 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   StyleStack<Span> spanStack;
 
   // Points the next free position in the vector of runs.
   StyleStack<Span> spanStack;
 
   // Points the next free position in the vector of runs.
-  RunIndex colorRunIndex                  = 0u;
-  RunIndex fontRunIndex                   = 0u;
-  RunIndex underlinedCharacterRunIndex    = 0u;
-  RunIndex backgroundRunIndex             = 0u;
-  RunIndex strikethroughCharacterRunIndex = 0u;
-  RunIndex boundedParagraphRunIndex       = 0u;
+  RunIndex colorRunIndex                     = 0u;
+  RunIndex fontRunIndex                      = 0u;
+  RunIndex underlinedCharacterRunIndex       = 0u;
+  RunIndex backgroundRunIndex                = 0u;
+  RunIndex strikethroughCharacterRunIndex    = 0u;
+  RunIndex boundedParagraphRunIndex          = 0u;
+  RunIndex characterSpacingCharacterRunIndex = 0u;
 
   // check tag reference
 
   // check tag reference
-  int colorTagReference      = 0u;
-  int fontTagReference       = 0u;
-  int iTagReference          = 0u;
-  int bTagReference          = 0u;
-  int uTagReference          = 0u;
-  int backgroundTagReference = 0u;
-  int spanTagReference       = 0u;
-  int sTagReference          = 0u;
-  int pTagReference          = 0u;
+  int colorTagReference            = 0u;
+  int fontTagReference             = 0u;
+  int iTagReference                = 0u;
+  int bTagReference                = 0u;
+  int uTagReference                = 0u;
+  int backgroundTagReference       = 0u;
+  int spanTagReference             = 0u;
+  int sTagReference                = 0u;
+  int pTagReference                = 0u;
+  int characterSpacingTagReference = 0u;
 
   // Give an initial default value to the model's vectors.
   markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
 
   // Give an initial default value to the model's vectors.
   markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
@@ -1052,6 +1071,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
+  markupProcessData.characterSpacingCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
 
   // Get the mark-up string buffer.
   const char*       markupStringBuffer    = markupString.c_str();
 
   // Get the mark-up string buffer.
   const char*       markupStringBuffer    = markupString.c_str();
@@ -1167,6 +1187,11 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
         ProcessTagForRun<BoundedParagraphRun>(
           markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
       } // <p></p>
         ProcessTagForRun<BoundedParagraphRun>(
           markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
       } // <p></p>
+      else if(TokenComparison(XHTML_CHARACTER_SPACING_TAG, tag.buffer, tag.length))
+      {
+        ProcessTagForRun<CharacterSpacingCharacterRun>(
+          markupProcessData.characterSpacingCharacterRuns, styleStack, tag, characterIndex, characterSpacingCharacterRunIndex, characterSpacingTagReference, [](const Tag& tag, CharacterSpacingCharacterRun& run) { ProcessCharacterSpacingTag(tag, run); });
+      } // <char-spacing></char-spacing>
     }   // end if( IsTag() )
     else if(markupStringBuffer < markupStringEndBuffer)
     {
     }   // end if( IsTag() )
     else if(markupStringBuffer < markupStringEndBuffer)
     {
@@ -1175,7 +1200,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   }
 
   // Resize the model's vectors.
   }
 
   // Resize the model's vectors.
-  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex);
+  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex, characterSpacingCharacterRunIndex);
 
   // Handle the nested tags
   OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
 
   // Handle the nested tags
   OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
index 3ef7a2d..f751843 100644 (file)
@@ -25,6 +25,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/anchor.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/anchor.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/character-spacing-character-run.h>
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/embedded-item.h>
 #include <dali-toolkit/internal/text/font-description-run.h>
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/embedded-item.h>
 #include <dali-toolkit/internal/text/font-description-run.h>
@@ -42,14 +43,15 @@ namespace Text
  */
 struct MarkupProcessData
 {
  */
 struct MarkupProcessData
 {
-  MarkupProcessData(Vector<ColorRun>&                  colorRuns,
-                    Vector<FontDescriptionRun>&        fontRuns,
-                    Vector<EmbeddedItem>&              items,
-                    Vector<Anchor>&                    anchors,
-                    Vector<UnderlinedCharacterRun>&    underlinedCharacterRuns,
-                    Vector<ColorRun>&                  backgroundColorRuns,
-                    Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns,
-                    Vector<BoundedParagraphRun>&       boundedParagraphRuns)
+  MarkupProcessData(Vector<ColorRun>&                     colorRuns,
+                    Vector<FontDescriptionRun>&           fontRuns,
+                    Vector<EmbeddedItem>&                 items,
+                    Vector<Anchor>&                       anchors,
+                    Vector<UnderlinedCharacterRun>&       underlinedCharacterRuns,
+                    Vector<ColorRun>&                     backgroundColorRuns,
+                    Vector<StrikethroughCharacterRun>&    strikethroughCharacterRuns,
+                    Vector<BoundedParagraphRun>&          boundedParagraphRuns,
+                    Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns)
   : colorRuns(colorRuns),
     fontRuns(fontRuns),
     items(items),
   : colorRuns(colorRuns),
     fontRuns(fontRuns),
     items(items),
@@ -58,19 +60,22 @@ struct MarkupProcessData
     backgroundColorRuns(backgroundColorRuns),
     strikethroughCharacterRuns(strikethroughCharacterRuns),
     boundedParagraphRuns(boundedParagraphRuns),
     backgroundColorRuns(backgroundColorRuns),
     strikethroughCharacterRuns(strikethroughCharacterRuns),
     boundedParagraphRuns(boundedParagraphRuns),
+    characterSpacingCharacterRuns(characterSpacingCharacterRuns),
     markupProcessedText()
   {
   }
 
     markupProcessedText()
   {
   }
 
-  Vector<ColorRun>&                  colorRuns;                  ///< The color runs.
-  Vector<FontDescriptionRun>&        fontRuns;                   ///< The font description runs.
-  Vector<EmbeddedItem>&              items;                      ///< The embedded items.
-  Vector<Anchor>&                    anchors;                    ///< The anchors.
-  Vector<UnderlinedCharacterRun>&    underlinedCharacterRuns;    ///< The underlined character runs.
-  Vector<ColorRun>&                  backgroundColorRuns;        ///< The background color runs.
-  Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns; ///< The strikethrough character runs.
-  Vector<BoundedParagraphRun>&       boundedParagraphRuns;       ///< The bounded paragraph runs
-  std::string                        markupProcessedText;        ///< The mark-up string.
+  Vector<ColorRun>&                     colorRuns;                     ///< The color runs.
+  Vector<FontDescriptionRun>&           fontRuns;                      ///< The font description runs.
+  Vector<EmbeddedItem>&                 items;                         ///< The embedded items.
+  Vector<Anchor>&                       anchors;                       ///< The anchors.
+  Vector<UnderlinedCharacterRun>&       underlinedCharacterRuns;       ///< The underlined character runs.
+  Vector<ColorRun>&                     backgroundColorRuns;           ///< The background color runs.
+  Vector<StrikethroughCharacterRun>&    strikethroughCharacterRuns;    ///< The strikethrough character runs.
+  Vector<BoundedParagraphRun>&          boundedParagraphRuns;          ///< The bounded paragraph runs
+  Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns; ///< The character-spacing runs
+
+  std::string markupProcessedText; ///< The mark-up string.
 };
 
 /**
 };
 
 /**
diff --git a/dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.cpp b/dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.cpp
new file mode 100644 (file)
index 0000000..b166c99
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+static const Vector<CharacterSpacingGlyphRun> EMPTY_CHARACTER_SPACING_GLYPH_RUNS;
+}
+float GetGlyphCharacterSpacing(const GlyphIndex&                       index,
+                               const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns,
+                               const float                             modelCharacterSpacing)
+{
+  float characterSpacing = modelCharacterSpacing;
+  for(Vector<CharacterSpacingGlyphRun>::ConstIterator it    = characterSpacingGlyphRuns.Begin(),
+                                                      endIt = characterSpacingGlyphRuns.End();
+      it != endIt;
+      ++it)
+  {
+    const CharacterSpacingGlyphRun& run = *it;
+
+    if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
+    {
+      // Retrieve the latest run to handle the nested case.
+      //TODO: Using reverse Iterator will improve performance in this loop
+      characterSpacing = run.value;
+    }
+  }
+
+  return characterSpacing;
+}
+
+const Vector<CharacterSpacingGlyphRun>& GetEmptyCharacterSpacingGlyphRuns()
+{
+  // This is needed to return a common empty vector for CharacterSpacingGlyphRun
+  return EMPTY_CHARACTER_SPACING_GLYPH_RUNS;
+}
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h b/dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h
new file mode 100644 (file)
index 0000000..3865b97
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_TOOLKIT_TEXT_RENDERING_STYLES_CHARACTER_SPACING_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_RENDERING_STYLES_CHARACTER_SPACING_HELPER_FUNCTIONS_H
+
+/*
+ * Copyright (c) 2022 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-spacing-glyph-run.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Check the glyph at index is had character-spacing or not then return its value. Otherwise return the model character-spacing height.
+ *
+ * @param[in] index the index of glyph.
+ * @param[in] characterSpacingGlyphRuns the character-spacing glyph runs.
+ * @param[in] modelCharacterSpacing the model character-spacing value.
+ *
+ * @return the determined character-spacing value
+ */
+float GetGlyphCharacterSpacing(const GlyphIndex&                       index,
+                               const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns,
+                               const float                             modelCharacterSpacing);
+
+/**
+ * @brief Create static empty vector and retrun it.
+ *
+ * @return The reference for the empty character-spacing glyph runs.
+ */
+const Vector<CharacterSpacingGlyphRun>& GetEmptyCharacterSpacingGlyphRuns();
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_RENDERING_STYLES_CHARACTER_SPACING_HELPER_FUNCTIONS_H
\ No newline at end of file
index 9d58934..628434e 100644 (file)
@@ -26,6 +26,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/view-model.h>
 #include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/view-model.h>
@@ -877,9 +878,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       }
     }
 
       }
     }
 
-    const bool  underlineEnabled     = mModel->IsUnderlineEnabled();
-    const bool  strikethroughEnabled = mModel->IsStrikethroughEnabled();
-    const float characterSpacing     = mModel->GetCharacterSpacing();
+    const bool  underlineEnabled      = mModel->IsUnderlineEnabled();
+    const bool  strikethroughEnabled  = mModel->IsStrikethroughEnabled();
+    const float modelCharacterSpacing = mModel->GetCharacterSpacing();
+
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = mModel->GetCharacterSpacingGlyphRuns();
 
     // Aggregate underline-style-properties from mModel
     const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
 
     // Aggregate underline-style-properties from mModel
     const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
@@ -1024,10 +1028,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
 
       if(addHyphen)
       {
 
       if(addHyphen)
       {
-        GlyphInfo tempInfo = *(glyphsBuffer + elidedGlyphIndex);
-        calculatedAdvance  = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + elidedGlyphIndex))), characterSpacing, tempInfo.advance);
-        position.x         = position.x + calculatedAdvance - tempInfo.xBearing + glyphInfo->xBearing;
-        position.y         = -glyphInfo->yBearing;
+        GlyphInfo   tempInfo         = *(glyphsBuffer + elidedGlyphIndex);
+        const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+        calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + elidedGlyphIndex))), characterSpacing, tempInfo.advance);
+        position.x                   = position.x + calculatedAdvance - tempInfo.xBearing + glyphInfo->xBearing;
+        position.y                   = -glyphInfo->yBearing;
       }
 
       if(baseline < position.y + glyphInfo->yBearing)
       }
 
       if(baseline < position.y + glyphInfo->yBearing)
index 0b26e4e..f02bb95 100644 (file)
@@ -655,6 +655,16 @@ const Vector<BoundedParagraphRun>& ViewModel::GetBoundedParagraphRuns() const
   return mModel->GetBoundedParagraphRuns();
 }
 
   return mModel->GetBoundedParagraphRuns();
 }
 
+Length ViewModel::GetNumberOfCharacterSpacingGlyphRuns() const
+{
+  return mModel->GetNumberOfCharacterSpacingGlyphRuns();
+}
+
+const Vector<CharacterSpacingGlyphRun>& ViewModel::GetCharacterSpacingGlyphRuns() const
+{
+  return mModel->GetCharacterSpacingGlyphRuns();
+}
+
 } // namespace Text
 
 } // namespace Toolkit
 } // namespace Text
 
 } // namespace Toolkit
index 73b7fa6..c7b0b18 100644 (file)
@@ -329,6 +329,16 @@ public:
    */
   void GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const override;
 
    */
   void GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const override;
 
+  /**
+   * @copydoc ModelInterface::GetNumberOfCharacterSpacingGlyphRuns()
+   */
+  Length GetNumberOfCharacterSpacingGlyphRuns() const override;
+
+  /**
+   * @copydoc ModelInterface::GetCharacterSpacingGlyphRuns()
+   */
+  const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const override;
+
 private:
   const ModelInterface* const mModel;                           ///< Pointer to the text's model.
   Vector<GlyphInfo>           mElidedGlyphs;                    ///< Stores the glyphs of the elided text.
 private:
   const ModelInterface* const mModel;                           ///< Pointer to the text's model.
   Vector<GlyphInfo>           mElidedGlyphs;                    ///< Stores the glyphs of the elided text.
index a129c5e..7def7e8 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 #include <dali-toolkit/internal/text/text-view.h>
 
 namespace Dali::Toolkit::Text
 #include <dali-toolkit/internal/text/text-view.h>
 
 namespace Dali::Toolkit::Text
@@ -98,11 +99,14 @@ Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr
     const Vector4* const    backgroundColorsBuffer       = textView.GetBackgroundColors();
     const ColorIndex* const backgroundColorIndicesBuffer = textView.GetBackgroundColorIndices();
     const Vector4&          defaultBackgroundColor       = textVisualModel->IsBackgroundEnabled() ? textVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
     const Vector4* const    backgroundColorsBuffer       = textView.GetBackgroundColors();
     const ColorIndex* const backgroundColorIndicesBuffer = textView.GetBackgroundColorIndices();
     const Vector4&          defaultBackgroundColor       = textVisualModel->IsBackgroundEnabled() ? textVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
-    const float             characterSpacing             = textVisualModel->GetCharacterSpacing();
+    const float             modelCharacterSpacing        = textVisualModel->GetCharacterSpacing();
     Vector<CharacterIndex>& glyphToCharacterMap          = textVisualModel->mGlyphsToCharacters;
     const CharacterIndex*   glyphToCharacterMapBuffer    = glyphToCharacterMap.Begin();
     float                   calculatedAdvance            = 0.f;
 
     Vector<CharacterIndex>& glyphToCharacterMap          = textVisualModel->mGlyphsToCharacters;
     const CharacterIndex*   glyphToCharacterMapBuffer    = glyphToCharacterMap.Begin();
     float                   calculatedAdvance            = 0.f;
 
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = textVisualModel->GetCharacterSpacingGlyphRuns();
+
     Vector4   quad;
     uint32_t  numberOfQuads = 0u;
     Length    yLineOffset   = 0;
     Vector4   quad;
     uint32_t  numberOfQuads = 0u;
     Length    yLineOffset   = 0;
@@ -137,6 +141,8 @@ Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr
       // Only create quads for glyphs with a background color
       if(backgroundColor != Color::TRANSPARENT)
       {
       // Only create quads for glyphs with a background color
       if(backgroundColor != Color::TRANSPARENT)
       {
+        const float characterSpacing = GetGlyphCharacterSpacing(i, characterSpacingGlyphRuns, modelCharacterSpacing);
+
         const Vector2 position = *(positionsBuffer + i);
         calculatedAdvance      = GetCalculatedAdvance(*(textLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + i))), characterSpacing, glyph.advance);
 
         const Vector2 position = *(positionsBuffer + i);
         calculatedAdvance      = GetCalculatedAdvance(*(textLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + i))), characterSpacing, glyph.advance);
 
index e6ec978..de18e85 100644 (file)
@@ -572,6 +572,7 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
     {
       impl.CopyUnderlinedFromLogicalToVisualModels(true);
       impl.CopyStrikethroughFromLogicalToVisualModels();
     {
       impl.CopyUnderlinedFromLogicalToVisualModels(true);
       impl.CopyStrikethroughFromLogicalToVisualModels();
+      impl.CopyCharacterSpacingFromLogicalToVisualModels();
     }
 
     updated = true;
     }
 
     updated = true;
index e97535c..318c196 100644 (file)
@@ -1692,6 +1692,39 @@ void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels()
   }
 }
 
   }
 }
 
+void Controller::Impl::CopyCharacterSpacingFromLogicalToVisualModels()
+{
+  //CharacterSpacing character runs from markup-processor
+  const Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns = mModel->mLogicalModel->mCharacterSpacingCharacterRuns;
+  const Vector<GlyphIndex>&                   charactersToGlyph             = mModel->mVisualModel->mCharactersToGlyph;
+  const Vector<Length>&                       glyphsPerCharacter            = mModel->mVisualModel->mGlyphsPerCharacter;
+
+  mModel->mVisualModel->mCharacterSpacingRuns.Clear();
+
+  for(Vector<CharacterSpacingCharacterRun>::ConstIterator it = characterSpacingCharacterRuns.Begin(), endIt = characterSpacingCharacterRuns.End(); it != endIt; ++it)
+  {
+    const CharacterIndex& characterIndex     = it->characterRun.characterIndex;
+    const Length&         numberOfCharacters = it->characterRun.numberOfCharacters;
+
+    if(numberOfCharacters == 0)
+    {
+      continue;
+    }
+
+    CharacterSpacingGlyphRun characterSpacingGlyphRun;
+    characterSpacingGlyphRun.value                   = it->value;
+    characterSpacingGlyphRun.glyphRun.glyphIndex     = charactersToGlyph[characterIndex];
+    characterSpacingGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+
+    for(Length index = 1u; index < numberOfCharacters; index++)
+    {
+      characterSpacingGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
+    }
+
+    mModel->mVisualModel->mCharacterSpacingRuns.PushBack(characterSpacingGlyphRun);
+  }
+}
+
 void Controller::Impl::SetAutoScrollEnabled(bool enable)
 {
   if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
 void Controller::Impl::SetAutoScrollEnabled(bool enable)
 {
   if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
index 0757bc0..8be1767 100644 (file)
@@ -961,6 +961,12 @@ private:
    */
   void CopyStrikethroughFromLogicalToVisualModels();
 
    */
   void CopyStrikethroughFromLogicalToVisualModels();
 
+  /**
+   * @brief Copy CharacterSpacing-Character-Runs from Logical-Model to CharacterSpacing-Glyph-Runs in Visual-Model
+   *
+   */
+  void CopyCharacterSpacingFromLogicalToVisualModels();
+
 public:
   ControlInterface*            mControlInterface;           ///< Reference to the text controller.
   EditableControlInterface*    mEditableControlInterface;   ///< Reference to the editable text controller.
 public:
   ControlInterface*            mControlInterface;           ///< Reference to the text controller.
   EditableControlInterface*    mEditableControlInterface;   ///< Reference to the editable text controller.
index 0b24bc0..e31a3f1 100644 (file)
@@ -92,7 +92,8 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string&
                                         logicalModel->mUnderlinedCharacterRuns,
                                         logicalModel->mBackgroundColorRuns,
                                         logicalModel->mStrikethroughCharacterRuns,
                                         logicalModel->mUnderlinedCharacterRuns,
                                         logicalModel->mBackgroundColorRuns,
                                         logicalModel->mStrikethroughCharacterRuns,
-                                        logicalModel->mBoundedParagraphRuns);
+                                        logicalModel->mBoundedParagraphRuns,
+                                        logicalModel->mCharacterSpacingCharacterRuns);
 
     Length         textSize = 0u;
     const uint8_t* utf8     = NULL;
 
     Length         textSize = 0u;
     const uint8_t* utf8     = NULL;
index c7e7b98..0f2bd7b 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/character-spacing-glyph-run.h>
 #include <dali-toolkit/internal/text/line-run.h>
 #include <dali-toolkit/internal/text/script-run.h>
 #include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
 #include <dali-toolkit/internal/text/line-run.h>
 #include <dali-toolkit/internal/text/script-run.h>
 #include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
@@ -403,6 +404,20 @@ public:
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const = 0;
 
   /**
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const = 0;
 
   /**
+   * @brief Retrieves the number of character-spacing glyph runs.
+   *
+   * @return The number of character-spacing glyph runs.
+   */
+  virtual Length GetNumberOfCharacterSpacingGlyphRuns() const = 0;
+
+  /**
+   * @brief Retrieves the reference for character-spacing glyph runs.
+   *
+   * @return The reference for character-spacing glyph runs.
+   */
+  virtual const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const = 0;
+
+  /**
    * @brief Retrieves the strikethrough runs.
    *
    * @param[out] strikethroughRuns Pointer to a buffer where the strikethrough runs are copied.
    * @brief Retrieves the strikethrough runs.
    *
    * @param[out] strikethroughRuns Pointer to a buffer where the strikethrough runs are copied.
index 924343c..0ac67ca 100644 (file)
@@ -291,6 +291,16 @@ void Model::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, Strik
   mVisualModel->GetStrikethroughRuns(strikethroughRuns, index, numberOfRuns);
 }
 
   mVisualModel->GetStrikethroughRuns(strikethroughRuns, index, numberOfRuns);
 }
 
+Length Model::GetNumberOfCharacterSpacingGlyphRuns() const
+{
+  return mVisualModel->GetNumberOfCharacterSpacingGlyphRuns();
+}
+
+const Vector<CharacterSpacingGlyphRun>& Model::GetCharacterSpacingGlyphRuns() const
+{
+  return mVisualModel->GetCharacterSpacingGlyphRuns();
+}
+
 const float Model::GetCharacterSpacing() const
 {
   return mVisualModel->GetCharacterSpacing();
 const float Model::GetCharacterSpacing() const
 {
   return mVisualModel->GetCharacterSpacing();
index ded9496..416df17 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/character-spacing-glyph-run.h>
 #include <dali-toolkit/internal/text/logical-model-impl.h>
 #include <dali-toolkit/internal/text/text-model-interface.h>
 #include <dali-toolkit/internal/text/visual-model-impl.h>
 #include <dali-toolkit/internal/text/logical-model-impl.h>
 #include <dali-toolkit/internal/text/text-model-interface.h>
 #include <dali-toolkit/internal/text/visual-model-impl.h>
@@ -313,6 +314,16 @@ public:
    */
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const override;
 
    */
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const override;
 
+  /**
+   * @copydoc ModelInterface::GetNumberOfCharacterSpacingGlyphRuns()
+   */
+  Length GetNumberOfCharacterSpacingGlyphRuns() const override;
+
+  /**
+   * @copydoc ModelInterface::GetCharacterSpacingGlyphRuns()
+   */
+  const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const override;
+
 private: // Private contructors & copy operator.
   /**
    * @brief Private constructor.
 private: // Private contructors & copy operator.
   /**
    * @brief Private constructor.
index a36f81f..05d8ad5 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
 
 using namespace Dali;
 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
 
 using namespace Dali;
@@ -108,10 +109,13 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
   const GlyphIndex        glyphStart                = *(charactersToGlyphBuffer + selectionStart);
   const Length            numberOfGlyphs            = *(glyphsPerCharacterBuffer + selectionEndMinusOne);
   const GlyphIndex        glyphEnd                  = *(charactersToGlyphBuffer + selectionEndMinusOne) + ((numberOfGlyphs > 0) ? numberOfGlyphs - 1u : 0u);
   const GlyphIndex        glyphStart                = *(charactersToGlyphBuffer + selectionStart);
   const Length            numberOfGlyphs            = *(glyphsPerCharacterBuffer + selectionEndMinusOne);
   const GlyphIndex        glyphEnd                  = *(charactersToGlyphBuffer + selectionEndMinusOne) + ((numberOfGlyphs > 0) ? numberOfGlyphs - 1u : 0u);
-  const float             characterSpacing          = visualModel->GetCharacterSpacing();
+  const float             modelCharacterSpacing     = visualModel->GetCharacterSpacing();
   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
   Vector<CharacterIndex>& glyphToCharacterMap       = visualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = visualModel->GetCharacterSpacingGlyphRuns();
+
   // Get the lines where the glyphs are laid-out.
   const LineRun* lineRun = visualModel->mLines.Begin();
 
   // Get the lines where the glyphs are laid-out.
   const LineRun* lineRun = visualModel->mLines.Begin();
 
@@ -174,9 +178,10 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
   // Traverse the glyphs.
   for(GlyphIndex index = glyphStart; index <= glyphEnd; ++index)
   {
   // Traverse the glyphs.
   for(GlyphIndex index = glyphStart; index <= glyphEnd; ++index)
   {
-    const GlyphInfo& glyph    = *(glyphsBuffer + index);
-    const Vector2&   position = *(positionsBuffer + index);
-    calculatedAdvance         = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + index))), characterSpacing, glyph.advance);
+    const float      characterSpacing = GetGlyphCharacterSpacing(index, characterSpacingGlyphRuns, modelCharacterSpacing);
+    const GlyphInfo& glyph            = *(glyphsBuffer + index);
+    const Vector2&   position         = *(positionsBuffer + index);
+    calculatedAdvance                 = GetCalculatedAdvance(*(logicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + index))), characterSpacing, glyph.advance);
 
     if(splitStartGlyph)
     {
 
     if(splitStartGlyph)
     {
index 9caf068..98b420d 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/character-spacing-glyph-run.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
 #include <dali-toolkit/internal/text/underlined-glyph-run.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
 #include <dali-toolkit/internal/text/underlined-glyph-run.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
@@ -338,6 +339,20 @@ public:
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const = 0;
 
   /**
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const = 0;
 
   /**
+   * @brief Retrieves the number of character-spacing glyph runs.
+   *
+   * @return The number of character-spacing glyph runs.
+   */
+  virtual Length GetNumberOfCharacterSpacingGlyphRuns() const = 0;
+
+  /**
+   * @brief Retrieves the reference for character-spacing glyph runs.
+   *
+   * @return The reference for character-spacing glyph runs.
+   */
+  virtual const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const = 0;
+
+  /**
    * @brief Retrieves the strikethrough runs.
    *
    * @param[out] strikethroughRuns Pointer to a buffer where the strikethrough runs are copied.
    * @brief Retrieves the strikethrough runs.
    *
    * @param[out] strikethroughRuns Pointer to a buffer where the strikethrough runs are copied.
index fdccbe1..1ec978d 100644 (file)
@@ -25,6 +25,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 
 namespace Dali
 {
 
 namespace Dali
 {
@@ -107,12 +108,15 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 {
   Length                  numberOfLaidOutGlyphs       = 0u;
   Length                  numberOfActualLaidOutGlyphs = 0u;
 {
   Length                  numberOfLaidOutGlyphs       = 0u;
   Length                  numberOfActualLaidOutGlyphs = 0u;
-  const float             characterSpacing            = mImpl->mVisualModel->GetCharacterSpacing();
+  const float             modelCharacterSpacing       = mImpl->mVisualModel->GetCharacterSpacing();
   Vector<CharacterIndex>& glyphToCharacterMap         = mImpl->mVisualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer   = glyphToCharacterMap.Begin();
   float                   calculatedAdvance           = 0.f;
   const Character*        textBuffer                  = mImpl->mLogicalModel->mText.Begin();
 
   Vector<CharacterIndex>& glyphToCharacterMap         = mImpl->mVisualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer   = glyphToCharacterMap.Begin();
   float                   calculatedAdvance           = 0.f;
   const Character*        textBuffer                  = mImpl->mLogicalModel->mText.Begin();
 
+  // Get the character-spacing runs.
+  const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = mImpl->mVisualModel->GetCharacterSpacingGlyphRuns();
+
   if(mImpl->mVisualModel)
   {
     bool                              textElided       = false;
   if(mImpl->mVisualModel)
   {
     bool                              textElided       = false;
@@ -356,7 +360,8 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
                 firstPenSet = true;
               }
 
                 firstPenSet = true;
               }
 
-              calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + indexOfEllipsis))), characterSpacing, glyphToRemove.advance);
+              const float characterSpacing = GetGlyphCharacterSpacing(indexOfEllipsis, characterSpacingGlyphRuns, modelCharacterSpacing);
+              calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + indexOfEllipsis))), characterSpacing, glyphToRemove.advance);
               removedGlypsWidth += std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width));
 
               // Calculate the width of the ellipsis glyph and check if it fits.
               removedGlypsWidth += std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width));
 
               // Calculate the width of the ellipsis glyph and check if it fits.
@@ -839,6 +844,16 @@ const Vector<BoundedParagraphRun>& View::GetBoundedParagraphRuns() const
   return mImpl->mLogicalModel->GetBoundedParagraphRuns();
 }
 
   return mImpl->mLogicalModel->GetBoundedParagraphRuns();
 }
 
+Length View::GetNumberOfCharacterSpacingGlyphRuns() const
+{
+  return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetNumberOfCharacterSpacingGlyphRuns() : 0u;
+}
+
+const Vector<CharacterSpacingGlyphRun>& View::GetCharacterSpacingGlyphRuns() const
+{
+  return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetCharacterSpacingGlyphRuns() : GetEmptyCharacterSpacingGlyphRuns();
+}
+
 const float View::GetCharacterSpacing() const
 {
   return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetCharacterSpacing() : 0.f;
 const float View::GetCharacterSpacing() const
 {
   return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetCharacterSpacing() : 0.f;
index 06bf838..93542cc 100644 (file)
@@ -259,6 +259,16 @@ public:
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const;
 
   /**
   virtual const Vector<BoundedParagraphRun>& GetBoundedParagraphRuns() const;
 
   /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetNumberOfCharacterSpacingGlyphRuns()
+   */
+  Length GetNumberOfCharacterSpacingGlyphRuns() const override;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetCharacterSpacingGlyphRuns()
+   */
+  const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const override;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetCharacterSpacing()
    */
   const float GetCharacterSpacing() const override;
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetCharacterSpacing()
    */
   const float GetCharacterSpacing() const override;
index ce0fb7c..5ef2b50 100644 (file)
@@ -609,6 +609,16 @@ Length VisualModel::GetNumberOfStrikethroughRuns() const
   return mStrikethroughRuns.Count();
 }
 
   return mStrikethroughRuns.Count();
 }
 
+Length VisualModel::GetNumberOfCharacterSpacingGlyphRuns() const
+{
+  return mCharacterSpacingRuns.Count();
+}
+
+const Vector<CharacterSpacingGlyphRun>& VisualModel::GetCharacterSpacingGlyphRuns() const
+{
+  return mCharacterSpacingRuns;
+}
+
 void VisualModel::ClearCaches()
 {
   mCachedLineIndex = 0u;
 void VisualModel::ClearCaches()
 {
   mCachedLineIndex = 0u;
index 4bae17c..9c0af3a 100644 (file)
@@ -26,6 +26,7 @@
 #include <dali/public-api/object/ref-object.h>
 
 // INTERNAL INCLUDES
 #include <dali/public-api/object/ref-object.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-spacing-glyph-run.h>
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/line-run.h>
 #include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/line-run.h>
 #include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
@@ -596,6 +597,20 @@ public:
    */
   Length GetNumberOfStrikethroughRuns() const;
 
    */
   Length GetNumberOfStrikethroughRuns() const;
 
+  /**
+   * @brief Retrieves the number of character-spacing glyph runs.
+   *
+   * @return The number of character-spacing glyph runs.
+   */
+  Length GetNumberOfCharacterSpacingGlyphRuns() const;
+
+  /**
+   * @brief Retrieves the reference for character-spacing glyph runs.
+   *
+   * @return The reference for character-spacing glyph runs.
+   */
+  const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const;
+
 protected:
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
 protected:
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -615,34 +630,35 @@ private:
   VisualModel& operator=(const VisualModel& handle);
 
 public:
   VisualModel& operator=(const VisualModel& handle);
 
 public:
-  Vector<GlyphInfo>             mGlyphs;                 ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
-  Vector<CharacterIndex>        mGlyphsToCharacters;     ///< For each glyph, the index of the first character.
-  Vector<GlyphIndex>            mCharactersToGlyph;      ///< For each character, the index of the first glyph.
-  Vector<Length>                mCharactersPerGlyph;     ///< For each glyph, the number of characters that form the glyph.
-  Vector<Length>                mGlyphsPerCharacter;     ///< For each character, the number of glyphs that are shaped.
-  Vector<Vector2>               mGlyphPositions;         ///< For each glyph, the position.
-  Vector<LineRun>               mLines;                  ///< The laid out lines.
-  Vector<UnderlinedGlyphRun>    mUnderlineRuns;          ///< Runs of glyphs that are underlined.
-  Vector<Vector4>               mColors;                 ///< Colors of the glyphs.
-  Vector<ColorIndex>            mColorIndices;           ///< Indices to the vector of colors for each glyphs.
-  Vector<Vector4>               mBackgroundColors;       ///< Background colors of the glyphs.
-  Vector<ColorIndex>            mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
-  Vector4                       mTextColor;              ///< The text color
-  Vector4                       mShadowColor;            ///< Color of drop shadow
-  Vector4                       mUnderlineColor;         ///< Color of underline
-  Vector4                       mOutlineColor;           ///< Color of outline
-  Vector4                       mBackgroundColor;        ///< Color of text background
-  Vector4                       mStrikethroughColor;     ///< Color of text background
-  Size                          mControlSize;            ///< The size of the UI control.
-  Vector2                       mShadowOffset;           ///< Offset for drop shadow, 0 indicates no shadow
-  float                         mUnderlineHeight;        ///< Fixed height for underline to override font metrics.
-  float                         mStrikethroughHeight;    ///< Fixed height for strikethrough to override font metrics.
-  Text::Underline::Type         mUnderlineType;          ///< The type of the underline.
-  float                         mDashedUnderlineWidth;   ///< The width of the dashes of the dashed underline.
-  float                         mDashedUnderlineGap;     ///< The gap between the dashes of the dashed underline.
-  float                         mShadowBlurRadius;       ///< Blur radius of shadow, 0 indicates no blur.
-  uint16_t                      mOutlineWidth;           ///< Width of outline.
-  Vector<StrikethroughGlyphRun> mStrikethroughRuns;      ///< Runs of glyphs that have strikethrough.
+  Vector<GlyphInfo>                mGlyphs;                 ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
+  Vector<CharacterIndex>           mGlyphsToCharacters;     ///< For each glyph, the index of the first character.
+  Vector<GlyphIndex>               mCharactersToGlyph;      ///< For each character, the index of the first glyph.
+  Vector<Length>                   mCharactersPerGlyph;     ///< For each glyph, the number of characters that form the glyph.
+  Vector<Length>                   mGlyphsPerCharacter;     ///< For each character, the number of glyphs that are shaped.
+  Vector<Vector2>                  mGlyphPositions;         ///< For each glyph, the position.
+  Vector<LineRun>                  mLines;                  ///< The laid out lines.
+  Vector<UnderlinedGlyphRun>       mUnderlineRuns;          ///< Runs of glyphs that are underlined.
+  Vector<Vector4>                  mColors;                 ///< Colors of the glyphs.
+  Vector<ColorIndex>               mColorIndices;           ///< Indices to the vector of colors for each glyphs.
+  Vector<Vector4>                  mBackgroundColors;       ///< Background colors of the glyphs.
+  Vector<ColorIndex>               mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
+  Vector4                          mTextColor;              ///< The text color
+  Vector4                          mShadowColor;            ///< Color of drop shadow
+  Vector4                          mUnderlineColor;         ///< Color of underline
+  Vector4                          mOutlineColor;           ///< Color of outline
+  Vector4                          mBackgroundColor;        ///< Color of text background
+  Vector4                          mStrikethroughColor;     ///< Color of text background
+  Size                             mControlSize;            ///< The size of the UI control.
+  Vector2                          mShadowOffset;           ///< Offset for drop shadow, 0 indicates no shadow
+  float                            mUnderlineHeight;        ///< Fixed height for underline to override font metrics.
+  float                            mStrikethroughHeight;    ///< Fixed height for strikethrough to override font metrics.
+  Text::Underline::Type            mUnderlineType;          ///< The type of the underline.
+  float                            mDashedUnderlineWidth;   ///< The width of the dashes of the dashed underline.
+  float                            mDashedUnderlineGap;     ///< The gap between the dashes of the dashed underline.
+  float                            mShadowBlurRadius;       ///< Blur radius of shadow, 0 indicates no blur.
+  uint16_t                         mOutlineWidth;           ///< Width of outline.
+  Vector<StrikethroughGlyphRun>    mStrikethroughRuns;      ///< Runs of glyphs that have strikethrough.
+  Vector<CharacterSpacingGlyphRun> mCharacterSpacingRuns;   ///< Runs of glyphs that have character-spacing.
 
 private:
   Size mNaturalSize; ///< Size of the text with no line wrapping.
 
 private:
   Size mNaturalSize; ///< Size of the text with no line wrapping.