Merge "Support align attribute for paragraph tag in markup" into devel/master
authorBowon Ryu <bowon.ryu@samsung.com>
Thu, 24 Feb 2022 10:36:34 +0000 (10:36 +0000)
committerGerrit Code Review <gerrit@review>
Thu, 24 Feb 2022 10:36:34 +0000 (10:36 +0000)
automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/text/bounded-paragraph-run.h
dali-toolkit/internal/text/markup-processor-helper-functions.cpp
dali-toolkit/internal/text/markup-processor-helper-functions.h
dali-toolkit/internal/text/markup-processor-paragraph.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-paragraph.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/text/text-controller-relayouter.h

index 9d78336..99b9e03 100644 (file)
@@ -671,4 +671,137 @@ int UtcDaliTextEditorMarkupParagraphTag(void)
   DALI_TEST_EQUALS(boundedParagraphRuns[1u].characterRun.numberOfCharacters, 15u, TEST_LOCATION);
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliTextEditorMarkupParagraphTagAlignAttribute(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute ");
+
+  // Apply alignment for each type on property level on three paragraphs and in-between text.
+  // Apply align in markup on the three paragraphs (each one a type).
+  // Using the same text to gain similar results from both the property level and the markup.
+  // Compare line alignment between the property level and the markup.
+
+  std::string textAlignOnPropertyLevel = "text outside<p>Paragraph end</p>text outside<p>Paragraph center</p>text outside<p>Paragraph begin</p><p>Paragraph property alignment</p>";
+  std::string textAlignInMarkup        = "text outside<p align='end'>Paragraph end</p>text outside<p align='center'>Paragraph center</p>text outside<p align='begin' >Paragraph begin</p><p>Paragraph property alignment</p>";
+
+  //Set size to avoid automatic eliding
+  Vector2 controllerSize = Vector2(1025, 1025);
+
+  TextEditor textEditorBeginAlign  = TextEditor::New();
+  TextEditor textEditorCenterAlign = TextEditor::New();
+  TextEditor textEditorEndAlign    = TextEditor::New();
+  TextEditor textEditorMultiAlign  = TextEditor::New();
+
+  application.GetScene().Add(textEditorBeginAlign);
+  application.GetScene().Add(textEditorCenterAlign);
+  application.GetScene().Add(textEditorEndAlign);
+  application.GetScene().Add(textEditorMultiAlign);
+
+  textEditorBeginAlign.SetProperty(TextEditor::Property::TEXT, textAlignOnPropertyLevel);
+  textEditorBeginAlign.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+  textEditorBeginAlign.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+  textEditorBeginAlign.SetProperty(TextEditor::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::BEGIN);
+  textEditorBeginAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  textEditorCenterAlign.SetProperty(TextEditor::Property::TEXT, textAlignOnPropertyLevel);
+  textEditorCenterAlign.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+  textEditorCenterAlign.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+  textEditorCenterAlign.SetProperty(TextEditor::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::CENTER);
+  textEditorCenterAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  textEditorEndAlign.SetProperty(TextEditor::Property::TEXT, textAlignOnPropertyLevel);
+  textEditorEndAlign.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+  textEditorEndAlign.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+  textEditorEndAlign.SetProperty(TextEditor::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::END);
+  textEditorEndAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  textEditorMultiAlign.SetProperty(TextEditor::Property::TEXT, textAlignInMarkup);
+  textEditorMultiAlign.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+  textEditorMultiAlign.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+  textEditorMultiAlign.SetProperty(TextEditor::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::CENTER);
+  textEditorMultiAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfBoundedParagraphRuns = 4u;
+  uint32_t expectedNumberOfLines                = 7u;
+
+  Toolkit::Internal::TextEditor& textEditorMultiAlignImpl  = GetImpl(textEditorMultiAlign);
+  Toolkit::Internal::TextEditor& textEditorBeginAlignImpl  = GetImpl(textEditorBeginAlign);
+  Toolkit::Internal::TextEditor& textEditorCenterAlignImpl = GetImpl(textEditorCenterAlign);
+  Toolkit::Internal::TextEditor& textEditorEndAlignImpl    = GetImpl(textEditorEndAlign);
+
+  const Text::Length numberOfBoundedParagraphRuns = textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetNumberOfBoundedParagraphRuns();
+  DALI_TEST_EQUALS(numberOfBoundedParagraphRuns, expectedNumberOfBoundedParagraphRuns, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  DALI_TEST_EQUALS(textEditorBeginAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textEditorBeginAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  DALI_TEST_EQUALS(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  DALI_TEST_EQUALS(textEditorEndAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textEditorEndAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  const uint32_t LINE_INDEX_ALIGN_END    = 1u;
+  const uint32_t LINE_INDEX_ALIGN_CENTER = 3u;
+  const uint32_t LINE_INDEX_ALIGN_BEGIN  = 5u;
+  const uint32_t LINE_INDEX_OUTSIDE_1    = 0u;
+  const uint32_t LINE_INDEX_OUTSIDE_2    = 2u;
+  const uint32_t LINE_INDEX_OUTSIDE_3    = 4u;
+  const uint32_t LINE_INDEX_PARAGRAPH    = 6u;
+
+  //<p align='end'>Paragraph end</p>
+  const LineRun& lineEndFromMultiAlign = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_END);
+  const LineRun& lineEndFromEndAlign   = *(textEditorEndAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_END);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - <p align='end'>Paragraph end</p>");
+  DALI_TEST_EQUALS(lineEndFromMultiAlign.alignmentOffset, lineEndFromEndAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineEndFromMultiAlign.width, lineEndFromEndAlign.width, TEST_LOCATION);
+
+  //<p align='center'>Paragraph center</p>
+  const LineRun& lineCenterFromMultiAlign = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_CENTER);
+  const LineRun& lineEndFromCenterAlign   = *(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_CENTER);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - <p align='center'>Paragraph center</p>");
+  DALI_TEST_EQUALS(lineCenterFromMultiAlign.alignmentOffset, lineEndFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineCenterFromMultiAlign.width, lineEndFromCenterAlign.width, TEST_LOCATION);
+
+  //<p align='begin' >Paragraph begin</p>
+  const LineRun& lineBeginFromMultiAlign = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_BEGIN);
+  const LineRun& lineEndFromBeginAlign   = *(textEditorBeginAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_BEGIN);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - <p align='begin' >Paragraph begin</p>");
+  DALI_TEST_EQUALS(lineBeginFromMultiAlign.alignmentOffset, lineEndFromBeginAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineBeginFromMultiAlign.width, lineEndFromBeginAlign.width, TEST_LOCATION);
+
+  //text outside
+  const LineRun& lineOutsideOneFromMultiAlign  = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_1);
+  const LineRun& lineOutsideOneFromCenterAlign = *(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_1);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - text outside one");
+  DALI_TEST_EQUALS(lineOutsideOneFromMultiAlign.alignmentOffset, lineOutsideOneFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineOutsideOneFromMultiAlign.width, lineOutsideOneFromCenterAlign.width, TEST_LOCATION);
+
+  const LineRun& lineOutsideTwoFromMultiAlign  = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_2);
+  const LineRun& lineOutsideTwoFromCenterAlign = *(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_2);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - text outside two");
+  DALI_TEST_EQUALS(lineOutsideTwoFromMultiAlign.alignmentOffset, lineOutsideTwoFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineOutsideTwoFromMultiAlign.width, lineOutsideTwoFromCenterAlign.width, TEST_LOCATION);
+
+  const LineRun& lineOutsideThreeFromMultiAlign  = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_3);
+  const LineRun& lineOutsideThreeFromCenterAlign = *(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_3);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - text outside three");
+  DALI_TEST_EQUALS(lineOutsideThreeFromMultiAlign.alignmentOffset, lineOutsideThreeFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineOutsideThreeFromMultiAlign.width, lineOutsideThreeFromCenterAlign.width, TEST_LOCATION);
+
+  const LineRun& lineParagraphFromMultiAlign  = *(textEditorMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_PARAGRAPH);
+  const LineRun& lineParagraphFromCenterAlign = *(textEditorCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_PARAGRAPH);
+  tet_infoline(" UtcDaliTextEditorMarkupParagraphTagAlignAttribute - <p>Paragraph property alignment</p>");
+  DALI_TEST_EQUALS(lineParagraphFromMultiAlign.alignmentOffset, lineParagraphFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineParagraphFromMultiAlign.width, lineParagraphFromCenterAlign.width, TEST_LOCATION);
+
+  END_TEST;
+}
index 4939775..4259cdc 100644 (file)
@@ -559,4 +559,141 @@ int UtcDaliTextLabelMarkupParagraphTag(void)
   DALI_TEST_EQUALS(boundedParagraphRuns[1u].characterRun.numberOfCharacters, 15u, TEST_LOCATION);
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliTextLabelMarkupParagraphTagAlignAttribute(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute ");
+
+  // Apply alignment for each type on property level on three paragraphs and in-between text.
+  // Apply align in markup on the three paragraphs (each one a type).
+  // Using the same text to gain similar results from both the property level and the markup.
+  // Compare line alignment between the property level and the markup.
+
+  std::string textAlignOnPropertyLevel = "text outside<p>Paragraph end</p>text outside<p>Paragraph center</p>text outside<p>Paragraph begin</p><p>Paragraph property alignment</p>";
+  std::string textAlignInMarkup        = "text outside<p align='end'>Paragraph end</p>text outside<p align='center'>Paragraph center</p>text outside<p align='begin' >Paragraph begin</p><p>Paragraph property alignment</p>";
+
+  //Set size to avoid automatic eliding
+  Vector2 controllerSize = Vector2(1025, 1025);
+
+  TextLabel textLabelBeginAlign  = TextLabel::New();
+  TextLabel textLabelCenterAlign = TextLabel::New();
+  TextLabel textLabelEndAlign    = TextLabel::New();
+  TextLabel textLabelMultiAlign  = TextLabel::New();
+
+  application.GetScene().Add(textLabelBeginAlign);
+  application.GetScene().Add(textLabelCenterAlign);
+  application.GetScene().Add(textLabelEndAlign);
+  application.GetScene().Add(textLabelMultiAlign);
+
+  textLabelBeginAlign.SetProperty(TextLabel::Property::TEXT, textAlignOnPropertyLevel);
+  textLabelBeginAlign.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+  textLabelBeginAlign.SetProperty(TextLabel::Property::MULTI_LINE, true);
+  textLabelBeginAlign.SetProperty(TextLabel::Property::ELLIPSIS, false);
+  textLabelBeginAlign.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::BEGIN);
+  textLabelBeginAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  textLabelCenterAlign.SetProperty(TextLabel::Property::TEXT, textAlignOnPropertyLevel);
+  textLabelCenterAlign.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+  textLabelCenterAlign.SetProperty(TextLabel::Property::MULTI_LINE, true);
+  textLabelCenterAlign.SetProperty(TextLabel::Property::ELLIPSIS, false);
+  textLabelCenterAlign.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::CENTER);
+  textLabelCenterAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  textLabelEndAlign.SetProperty(TextLabel::Property::TEXT, textAlignOnPropertyLevel);
+  textLabelEndAlign.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+  textLabelEndAlign.SetProperty(TextLabel::Property::MULTI_LINE, true);
+  textLabelEndAlign.SetProperty(TextLabel::Property::ELLIPSIS, false);
+  textLabelEndAlign.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::END);
+  textLabelEndAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  textLabelMultiAlign.SetProperty(TextLabel::Property::TEXT, textAlignInMarkup);
+  textLabelMultiAlign.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+  textLabelMultiAlign.SetProperty(TextLabel::Property::MULTI_LINE, true);
+  textLabelMultiAlign.SetProperty(TextLabel::Property::ELLIPSIS, false);
+  textLabelMultiAlign.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::CENTER);
+  textLabelMultiAlign.SetProperty(Actor::Property::SIZE, controllerSize);
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfBoundedParagraphRuns = 4u;
+  uint32_t expectedNumberOfLines                = 7u;
+
+  Toolkit::Internal::TextLabel& textLabelMultiAlignImpl  = GetImpl(textLabelMultiAlign);
+  Toolkit::Internal::TextLabel& textLabelBeginAlignImpl  = GetImpl(textLabelBeginAlign);
+  Toolkit::Internal::TextLabel& textLabelCenterAlignImpl = GetImpl(textLabelCenterAlign);
+  Toolkit::Internal::TextLabel& textLabelEndAlignImpl    = GetImpl(textLabelEndAlign);
+
+  const Text::Length numberOfBoundedParagraphRuns = textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetNumberOfBoundedParagraphRuns();
+  DALI_TEST_EQUALS(numberOfBoundedParagraphRuns, expectedNumberOfBoundedParagraphRuns, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  DALI_TEST_EQUALS(textLabelBeginAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textLabelBeginAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  DALI_TEST_EQUALS(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  DALI_TEST_EQUALS(textLabelEndAlignImpl.GetTextController()->GetTextModel()->GetNumberOfLines(), expectedNumberOfLines, TEST_LOCATION);
+  DALI_TEST_CHECK(textLabelEndAlignImpl.GetTextController()->GetTextModel()->GetLines());
+
+  const uint32_t LINE_INDEX_ALIGN_END    = 1u;
+  const uint32_t LINE_INDEX_ALIGN_CENTER = 3u;
+  const uint32_t LINE_INDEX_ALIGN_BEGIN  = 5u;
+  const uint32_t LINE_INDEX_OUTSIDE_1    = 0u;
+  const uint32_t LINE_INDEX_OUTSIDE_2    = 2u;
+  const uint32_t LINE_INDEX_OUTSIDE_3    = 4u;
+  const uint32_t LINE_INDEX_PARAGRAPH    = 6u;
+
+  //<p align='end'>Paragraph end</p>
+  const LineRun& lineEndFromMultiAlign = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_END);
+  const LineRun& lineEndFromEndAlign   = *(textLabelEndAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_END);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - <p align='end'>Paragraph end</p>");
+  DALI_TEST_EQUALS(lineEndFromMultiAlign.alignmentOffset, lineEndFromEndAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineEndFromMultiAlign.width, lineEndFromEndAlign.width, TEST_LOCATION);
+
+  //<p align='center'>Paragraph center</p>
+  const LineRun& lineCenterFromMultiAlign = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_CENTER);
+  const LineRun& lineEndFromCenterAlign   = *(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_CENTER);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - <p align='center'>Paragraph center</p>");
+  DALI_TEST_EQUALS(lineCenterFromMultiAlign.alignmentOffset, lineEndFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineCenterFromMultiAlign.width, lineEndFromCenterAlign.width, TEST_LOCATION);
+
+  //<p align='begin' >Paragraph begin</p>
+  const LineRun& lineBeginFromMultiAlign = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_BEGIN);
+  const LineRun& lineEndFromBeginAlign   = *(textLabelBeginAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_ALIGN_BEGIN);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - <p align='begin' >Paragraph begin</p>");
+  DALI_TEST_EQUALS(lineBeginFromMultiAlign.alignmentOffset, lineEndFromBeginAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineBeginFromMultiAlign.width, lineEndFromBeginAlign.width, TEST_LOCATION);
+
+  //text outside
+  const LineRun& lineOutsideOneFromMultiAlign  = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_1);
+  const LineRun& lineOutsideOneFromCenterAlign = *(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_1);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - text outside one");
+  DALI_TEST_EQUALS(lineOutsideOneFromMultiAlign.alignmentOffset, lineOutsideOneFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineOutsideOneFromMultiAlign.width, lineOutsideOneFromCenterAlign.width, TEST_LOCATION);
+
+  const LineRun& lineOutsideTwoFromMultiAlign  = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_2);
+  const LineRun& lineOutsideTwoFromCenterAlign = *(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_2);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - text outside two");
+  DALI_TEST_EQUALS(lineOutsideTwoFromMultiAlign.alignmentOffset, lineOutsideTwoFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineOutsideTwoFromMultiAlign.width, lineOutsideTwoFromCenterAlign.width, TEST_LOCATION);
+
+  const LineRun& lineOutsideThreeFromMultiAlign  = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_3);
+  const LineRun& lineOutsideThreeFromCenterAlign = *(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_OUTSIDE_3);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - text outside three");
+  DALI_TEST_EQUALS(lineOutsideThreeFromMultiAlign.alignmentOffset, lineOutsideThreeFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineOutsideThreeFromMultiAlign.width, lineOutsideThreeFromCenterAlign.width, TEST_LOCATION);
+
+  const LineRun& lineParagraphFromMultiAlign  = *(textLabelMultiAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_PARAGRAPH);
+  const LineRun& lineParagraphFromCenterAlign = *(textLabelCenterAlignImpl.GetTextController()->GetTextModel()->GetLines() + LINE_INDEX_PARAGRAPH);
+  tet_infoline(" UtcDaliTextLabelMarkupParagraphTagAlignAttribute - <p>Paragraph property alignment</p>");
+  DALI_TEST_EQUALS(lineParagraphFromMultiAlign.alignmentOffset, lineParagraphFromCenterAlign.alignmentOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(lineParagraphFromMultiAlign.width, lineParagraphFromCenterAlign.width, TEST_LOCATION);
+
+  END_TEST;
+}
index 994fc0d..7e9c1aa 100644 (file)
@@ -150,6 +150,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/markup-processor-anchor.cpp
    ${toolkit_src_dir}/text/markup-processor-font.cpp
    ${toolkit_src_dir}/text/markup-processor-background.cpp
+   ${toolkit_src_dir}/text/markup-processor-paragraph.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
index 6c5b2d8..ec15ff4 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
 
 namespace Dali
 {
@@ -41,7 +42,19 @@ namespace Text
  */
 struct BoundedParagraphRun
 {
-  CharacterRun characterRun; ///< The initial character index within the whole text and the number of characters of the run.
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  BoundedParagraphRun()
+  : characterRun{},
+    horizontalAlignment(Text::HorizontalAlignment::BEGIN),
+    horizontalAlignmentDefined{false}
+  {
+  }
+
+  CharacterRun                    characterRun;                   ///< The initial character index within the whole text and the number of characters of the run.
+  Text::HorizontalAlignment::Type horizontalAlignment;            ///< The paragraph horizontal alignment. Values "BEGIN" "CENTER" "END".
+  bool                            horizontalAlignmentDefined : 1; ///< Whether the horizontal alignment is defined.
 };
 
 } // namespace Text
index e4cb1c4..9f4c34d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * 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.
@@ -57,6 +57,11 @@ const std::string TRANSPARENT_COLOR("transparent");
 const std::string SOLID_UNDERLINE("solid");
 const std::string DASHED_UNDERLINE("dashed");
 const std::string DOUBLE_UNDERLINE("double");
+
+const std::string BEGIN_HORIZONTAL_ALIGNMENT("begin");
+const std::string CENTER_HORIZONTAL_ALIGNMENT("center");
+const std::string END_HORIZONTAL_ALIGNMENT("end");
+
 } // namespace
 
 bool TokenComparison(const std::string& string1, const char* const stringBuffer2, Length length)
@@ -317,6 +322,29 @@ void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Te
   }
 }
 
+bool HorizontalAlignmentTypeStringToTypeValue(const char* const typeStr, Length length, Text::HorizontalAlignment::Type& retType)
+{
+  // The string is valid value for HorizontalAlignment
+  bool valid = false;
+  if(TokenComparison(BEGIN_HORIZONTAL_ALIGNMENT, typeStr, length))
+  {
+    retType = Text::HorizontalAlignment::BEGIN;
+    valid   = true;
+  }
+  else if(TokenComparison(CENTER_HORIZONTAL_ALIGNMENT, typeStr, length))
+  {
+    retType = Text::HorizontalAlignment::CENTER;
+    valid   = true;
+  }
+  else if(TokenComparison(END_HORIZONTAL_ALIGNMENT, typeStr, length))
+  {
+    retType = Text::HorizontalAlignment::END;
+    valid   = true;
+  }
+
+  return valid;
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index a28c1cb..d763318 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -202,6 +202,17 @@ void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Te
  */
 float StringToFloat(const char* const floatStr);
 
+/**
+ * @brief Converts a string into its value in the enum Text::HorizontalAlignment::Type.
+ *
+ * @param[in] typeStr The horizontal-alignment type value packed inside a string.
+ * @param[in] length The length of the string.
+ * @param[out] retType The HorizontalAlignment type.
+ *
+ * @return Whether the value parsed or not.
+ */
+bool HorizontalAlignmentTypeStringToTypeValue(const char* const typeStr, Length length, Text::HorizontalAlignment::Type& retType);
+
 } // namespace Text
 
 } // namespace Toolkit
diff --git a/dali-toolkit/internal/text/markup-processor-paragraph.cpp b/dali-toolkit/internal/text/markup-processor-paragraph.cpp
new file mode 100644 (file)
index 0000000..35a1cc5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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-paragraph.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string XHTML_ALIGN_ATTRIBUTE("align");
+}
+
+void ProcessHorizontalAlignment(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
+{
+  boundedParagraphRun.horizontalAlignmentDefined = HorizontalAlignmentTypeStringToTypeValue(attribute.valueBuffer,
+                                                                                            attribute.valueLength,
+                                                                                            boundedParagraphRun.horizontalAlignment);
+}
+
+void ProcessAttributesOfParagraphTag(const Tag& tag, BoundedParagraphRun& boundedParagraphRun)
+{
+  // By default the align attribute is not defined until it's parsed.
+  boundedParagraphRun.horizontalAlignmentDefined = false;
+
+  for(Vector<Attribute>::ConstIterator it    = tag.attributes.Begin(),
+                                       endIt = tag.attributes.End();
+      it != endIt;
+      ++it)
+  {
+    const Attribute& attribute(*it);
+    if(TokenComparison(XHTML_ALIGN_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessHorizontalAlignment(attribute, boundedParagraphRun);
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-paragraph.h b/dali-toolkit/internal/text/markup-processor-paragraph.h
new file mode 100644 (file)
index 0000000..484b3a5
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_PARAGRAPH_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_PARAGRAPH_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 BoundedParagraphRun;
+
+/**
+ * @brief Retrieves the horizontal alignment value from the tag and sets it to the bounded paragraph run.
+ *
+ * @param[in] attribute the horizontal alignment attribute.
+ * @param[in,out] boundedParagraphRun The bounded paragraph run.
+ */
+void ProcessHorizontalAlignment(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun);
+
+/**
+ * @brief Retrieves the paragraph value from the tag and sets it to the bounded paragraph run.
+ *
+ * @param[in] tag The paragraph tag and its attributes.
+ * @param[in,out] boundedParagraphRun The bounded paragraph run.
+ */
+void ProcessAttributesOfParagraphTag(const Tag& tag, BoundedParagraphRun& boundedParagraphRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_PARAGRAPH_H
index 201093b..b41d70b 100644 (file)
@@ -31,6 +31,7 @@
 #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-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor-paragraph.h>
 #include <dali-toolkit/internal/text/markup-processor-span.h>
 #include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
 #include <dali-toolkit/internal/text/markup-processor-underline.h>
@@ -1058,7 +1059,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
       {
         ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex);
         ProcessTagForRun<BoundedParagraphRun>(
-          markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) {});
+          markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
       } // <p></p>
     }   // end if( IsTag() )
     else if(markupStringBuffer < markupStringEndBuffer)
index c9a4fb0..6f4763e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -464,8 +464,8 @@ Controller::UpdateTextType Controller::Relayouter::Relayout(Controller& controll
       if(EventData::IsEditingState(impl.mEventData->mState))
       {
         impl.mEventData->mScrollAfterUpdatePosition = true;
-        impl.mEventData->mUpdateCursorPosition = true;
-        impl.mEventData->mUpdateGrabHandlePosition = true;
+        impl.mEventData->mUpdateCursorPosition      = true;
+        impl.mEventData->mUpdateGrabHandlePosition  = true;
       }
       else if(impl.mEventData->mState == EventData::SELECTING)
       {
@@ -627,21 +627,51 @@ bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size
 
   if(NO_OPERATION != (ALIGN & operations))
   {
-    // The laid-out lines.
-    Vector<LineRun>& lines = visualModel->mLines;
+    DoRelayoutHorizontalAlignment(impl, size, startIndex, requestedNumberOfCharacters);
+    viewUpdated = true;
+  }
+#if defined(DEBUG_ENABLED)
+  std::string currentText;
+  impl.GetText(currentText);
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::Relayouter::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", &impl, (impl.mIsTextDirectionRTL) ? "true" : "false", currentText.c_str());
+#endif
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayouter::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false"));
+  return viewUpdated;
+}
+
+void Controller::Relayouter::DoRelayoutHorizontalAlignment(Controller::Impl&    impl,
+                                                           const Size&          size,
+                                                           const CharacterIndex startIndex,
+                                                           const Length         requestedNumberOfCharacters)
+{
+  // The visualModel
+  VisualModelPtr& visualModel = impl.mModel->mVisualModel;
 
-    CharacterIndex alignStartIndex                  = startIndex;
-    Length         alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
+  // The laid-out lines.
+  Vector<LineRun>& lines = visualModel->mLines;
 
-    // the whole text needs to be full aligned.
-    // If you do not do a full aligned, only the last line of the multiline input is aligned.
-    if(impl.mEventData && impl.mEventData->mUpdateAlignment)
-    {
-      alignStartIndex                   = 0u;
-      alignRequestedNumberOfCharacters  = impl.mModel->mLogicalModel->mText.Count();
-      impl.mEventData->mUpdateAlignment = false;
-    }
+  CharacterIndex alignStartIndex                  = startIndex;
+  Length         alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
+
+  // the whole text needs to be full aligned.
+  // If you do not do a full aligned, only the last line of the multiline input is aligned.
+  if(impl.mEventData && impl.mEventData->mUpdateAlignment)
+  {
+    alignStartIndex                   = 0u;
+    alignRequestedNumberOfCharacters  = impl.mModel->mLogicalModel->mText.Count();
+    impl.mEventData->mUpdateAlignment = false;
+  }
 
+  // If there is no BoundedParagraphRuns then apply the alignment of controller.
+  // Check whether the layout is single line. It's needed to apply one alignment for single-line.
+  // In single-line layout case we need to check whether to follow the alignment of controller or the first BoundedParagraph.
+  // Apply BoundedParagraph's alignment if and only if there is one BoundedParagraph contains all characters. Otherwise follow controller's alignment.
+  const bool isFollowControllerAlignment = ((impl.mModel->GetNumberOfBoundedParagraphRuns() == 0u) ||
+                                            ((Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout()) &&
+                                             (impl.mModel->GetBoundedParagraphRuns()[0].characterRun.numberOfCharacters != impl.mModel->mLogicalModel->mText.Count())));
+
+  if(isFollowControllerAlignment)
+  {
     // Need to align with the control's size as the text may contain lines
     // starting either with left to right text or right to left.
     impl.mLayoutEngine.Align(size,
@@ -652,16 +682,91 @@ bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size
                              impl.mModel->mAlignmentOffset,
                              impl.mLayoutDirection,
                              (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS));
+  }
+  else
+  {
+    //Override the controller horizontal-alignment by horizontal-alignment of bounded paragraph.
+    const Length&                      numberOfBoundedParagraphRuns = impl.mModel->GetNumberOfBoundedParagraphRuns();
+    const Vector<BoundedParagraphRun>& boundedParagraphRuns         = impl.mModel->GetBoundedParagraphRuns();
+    const CharacterIndex               alignEndIndex                = alignStartIndex + alignRequestedNumberOfCharacters - 1u;
 
-    viewUpdated = true;
+    Length alignIndex               = alignStartIndex;
+    Length boundedParagraphRunIndex = 0u;
+
+    while(alignIndex <= alignEndIndex && boundedParagraphRunIndex < numberOfBoundedParagraphRuns)
+    {
+      //BP: BoundedParagraph
+      const BoundedParagraphRun& boundedParagraphRun   = boundedParagraphRuns[boundedParagraphRunIndex];
+      const CharacterIndex&      characterStartIndexBP = boundedParagraphRun.characterRun.characterIndex;
+      const Length&              numberOfCharactersBP  = boundedParagraphRun.characterRun.numberOfCharacters;
+      const CharacterIndex       characterEndIndexBP   = characterStartIndexBP + numberOfCharactersBP - 1u;
+
+      CharacterIndex                  decidedAlignStartIndex         = alignIndex;
+      Length                          decidedAlignNumberOfCharacters = alignEndIndex - alignIndex + 1u;
+      Text::HorizontalAlignment::Type decidedHorizontalAlignment     = impl.mModel->mHorizontalAlignment;
+
+      /*
+         * Shortcuts to explain indexes cases:
+         *
+         * AS: Alignment Start Index
+         * AE: Alignment End Index
+         * PS: Paragraph Start Index
+         * PE: Paragraph End Index
+         * B: BoundedParagraph Alignment
+         * M: Model Alignment
+         *
+         */
+
+      if(alignIndex < characterStartIndexBP && characterStartIndexBP <= alignEndIndex) /// AS.MMMMMM.PS--------AE
+      {
+        // Alignment from "Alignment Start Index" to index before "Paragraph Start Index" according to "Model Alignment"
+        decidedAlignStartIndex         = alignIndex;
+        decidedAlignNumberOfCharacters = characterStartIndexBP - alignIndex;
+        decidedHorizontalAlignment     = impl.mModel->mHorizontalAlignment;
+
+        // Need to re-heck the case of current bounded paragraph
+        alignIndex = characterStartIndexBP; // Shift AS to be PS
+      }
+      else if((characterStartIndexBP <= alignIndex && alignIndex <= characterEndIndexBP) ||     /// ---PS.BBBBBBB.AS.BBBBBBB.PE---
+              (characterStartIndexBP <= alignEndIndex && alignEndIndex <= characterEndIndexBP)) /// ---PS.BBBBBB.AE.BBBBBBB.PE---
+      {
+        // Alignment from "Paragraph Start Index" to "Paragraph End Index" according to "BoundedParagraph Alignment"
+        decidedAlignStartIndex         = characterStartIndexBP;
+        decidedAlignNumberOfCharacters = numberOfCharactersBP;
+        decidedHorizontalAlignment     = boundedParagraphRun.horizontalAlignmentDefined ? boundedParagraphRun.horizontalAlignment : impl.mModel->mHorizontalAlignment;
+
+        alignIndex = characterEndIndexBP + 1u; // Shift AS to be after PE direct
+        boundedParagraphRunIndex++;            // Align then check the case of next bounded paragraph
+      }
+      else
+      {
+        boundedParagraphRunIndex++; // Check the case of next bounded paragraph
+        continue;
+      }
+
+      impl.mLayoutEngine.Align(size,
+                               decidedAlignStartIndex,
+                               decidedAlignNumberOfCharacters,
+                               decidedHorizontalAlignment,
+                               lines,
+                               impl.mModel->mAlignmentOffset,
+                               impl.mLayoutDirection,
+                               (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS));
+    }
+
+    //Align the remaining that is not aligned
+    if(alignIndex <= alignEndIndex)
+    {
+      impl.mLayoutEngine.Align(size,
+                               alignIndex,
+                               (alignEndIndex - alignIndex + 1u),
+                               impl.mModel->mHorizontalAlignment,
+                               lines,
+                               impl.mModel->mAlignmentOffset,
+                               impl.mLayoutDirection,
+                               (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS));
+    }
   }
-#if defined(DEBUG_ENABLED)
-  std::string currentText;
-  impl.GetText(currentText);
-  DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::Relayouter::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", &impl, (impl.mIsTextDirectionRTL) ? "true" : "false", currentText.c_str());
-#endif
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayouter::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false"));
-  return viewUpdated;
 }
 
 void Controller::Relayouter::CalculateVerticalOffset(Controller& controller, const Size& controlSize)
index b605545..c0ab806 100644 (file)
@@ -114,6 +114,18 @@ struct Controller::Relayouter
   * @return The calculated layout-size.
   */
   static Size CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask);
+
+private:
+  /**
+   * @brief Called by the DoRelayout to do HorizontalAlignment operation when relayouting.
+   *
+   * @param[in] impl A reference to the controller impl class
+   * @param[in] size The size to set
+   * @param[in] startIndex The start index for relayouting
+   * @param[in] requestedNumberOfCharacters The number Of characters for relayouting
+   */
+
+  static void DoRelayoutHorizontalAlignment(Controller::Impl& impl, const Size& size, const CharacterIndex startIndex, const Length requestedNumberOfCharacters);
 };
 
 } // namespace Text