From 82031ca68ee58a2f30f01af3992523d0bb8e5fa6 Mon Sep 17 00:00:00 2001 From: ssabah Date: Thu, 3 Feb 2022 00:39:30 +0200 Subject: [PATCH] Support align attribute for paragraph tag in markup

text

Values: begin | center | end //How to apply it: textEditorMultiAlign.SetProperty(TextEditor::Property::TEXT, "text outside

Paragraph end

Paragraph center

Paragraph begin

Paragraph property alignment

"); textEditorMultiAlign.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true); //The alignment on property level works on outside text or on a paragraph without the align attribute textEditorMultiAlign.SetProperty(TextEditor::Property::HORIZONTAL_ALIGNMENT, Dali::Toolkit::Text::HorizontalAlignment::CENTER); Change-Id: I3ccd6e6669a5887cdcbfa80be44998fd487e580c --- .../utc-Dali-TextEditor-internal.cpp | 135 +++++++++++++++++- .../utc-Dali-TextLabel-internal.cpp | 139 ++++++++++++++++++- dali-toolkit/internal/file.list | 1 + dali-toolkit/internal/text/bounded-paragraph-run.h | 15 +- .../text/markup-processor-helper-functions.cpp | 30 +++- .../text/markup-processor-helper-functions.h | 13 +- .../internal/text/markup-processor-paragraph.cpp | 68 ++++++++++ .../internal/text/markup-processor-paragraph.h | 53 ++++++++ dali-toolkit/internal/text/markup-processor.cpp | 3 +- .../internal/text/text-controller-relayouter.cpp | 151 +++++++++++++++++---- .../internal/text/text-controller-relayouter.h | 12 ++ 11 files changed, 591 insertions(+), 29 deletions(-) create mode 100644 dali-toolkit/internal/text/markup-processor-paragraph.cpp create mode 100644 dali-toolkit/internal/text/markup-processor-paragraph.h diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp index 9d78336..99b9e03 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp @@ -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

Paragraph end

text outside

Paragraph center

text outside

Paragraph begin

Paragraph property alignment

"; + std::string textAlignInMarkup = "text outside

Paragraph end

text outside

Paragraph center

text outside

Paragraph begin

Paragraph property alignment

"; + + //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; + + //

Paragraph end

+ 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 -

Paragraph end

"); + DALI_TEST_EQUALS(lineEndFromMultiAlign.alignmentOffset, lineEndFromEndAlign.alignmentOffset, TEST_LOCATION); + DALI_TEST_EQUALS(lineEndFromMultiAlign.width, lineEndFromEndAlign.width, TEST_LOCATION); + + //

Paragraph center

+ 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 -

Paragraph center

"); + DALI_TEST_EQUALS(lineCenterFromMultiAlign.alignmentOffset, lineEndFromCenterAlign.alignmentOffset, TEST_LOCATION); + DALI_TEST_EQUALS(lineCenterFromMultiAlign.width, lineEndFromCenterAlign.width, TEST_LOCATION); + + //

Paragraph begin

+ 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 -

Paragraph begin

"); + 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 -

Paragraph property alignment

"); + DALI_TEST_EQUALS(lineParagraphFromMultiAlign.alignmentOffset, lineParagraphFromCenterAlign.alignmentOffset, TEST_LOCATION); + DALI_TEST_EQUALS(lineParagraphFromMultiAlign.width, lineParagraphFromCenterAlign.width, TEST_LOCATION); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp index bec9416..1d6a85f 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp @@ -560,4 +560,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

Paragraph end

text outside

Paragraph center

text outside

Paragraph begin

Paragraph property alignment

"; + std::string textAlignInMarkup = "text outside

Paragraph end

text outside

Paragraph center

text outside

Paragraph begin

Paragraph property alignment

"; + + //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; + + //

Paragraph end

+ 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 -

Paragraph end

"); + DALI_TEST_EQUALS(lineEndFromMultiAlign.alignmentOffset, lineEndFromEndAlign.alignmentOffset, TEST_LOCATION); + DALI_TEST_EQUALS(lineEndFromMultiAlign.width, lineEndFromEndAlign.width, TEST_LOCATION); + + //

Paragraph center

+ 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 -

Paragraph center

"); + DALI_TEST_EQUALS(lineCenterFromMultiAlign.alignmentOffset, lineEndFromCenterAlign.alignmentOffset, TEST_LOCATION); + DALI_TEST_EQUALS(lineCenterFromMultiAlign.width, lineEndFromCenterAlign.width, TEST_LOCATION); + + //

Paragraph begin

+ 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 -

Paragraph begin

"); + 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 -

Paragraph property alignment

"); + DALI_TEST_EQUALS(lineParagraphFromMultiAlign.alignmentOffset, lineParagraphFromCenterAlign.alignmentOffset, TEST_LOCATION); + DALI_TEST_EQUALS(lineParagraphFromMultiAlign.width, lineParagraphFromCenterAlign.width, TEST_LOCATION); + + END_TEST; +} diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 9b543fd..851f2fd 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -148,6 +148,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 diff --git a/dali-toolkit/internal/text/bounded-paragraph-run.h b/dali-toolkit/internal/text/bounded-paragraph-run.h index 6c5b2d8..ec15ff4 100644 --- a/dali-toolkit/internal/text/bounded-paragraph-run.h +++ b/dali-toolkit/internal/text/bounded-paragraph-run.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include 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 diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp index e4cb1c4..9f4c34d 100644 --- a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp +++ b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp @@ -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 diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.h b/dali-toolkit/internal/text/markup-processor-helper-functions.h index a28c1cb..d763318 100644 --- a/dali-toolkit/internal/text/markup-processor-helper-functions.h +++ b/dali-toolkit/internal/text/markup-processor-helper-functions.h @@ -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 index 0000000..35a1cc5 --- /dev/null +++ b/dali-toolkit/internal/text/markup-processor-paragraph.cpp @@ -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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include + +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::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 index 0000000..484b3a5 --- /dev/null +++ b/dali-toolkit/internal/text/markup-processor-paragraph.h @@ -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 diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp index e046049..9b1e019 100644 --- a/dali-toolkit/internal/text/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1052,7 +1053,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar { ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex); ProcessTagForRun( - 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); }); } //

} // end if( IsTag() ) else if(markupStringBuffer < markupStringEndBuffer) diff --git a/dali-toolkit/internal/text/text-controller-relayouter.cpp b/dali-toolkit/internal/text/text-controller-relayouter.cpp index c9a4fb0..6f4763e 100644 --- a/dali-toolkit/internal/text/text-controller-relayouter.cpp +++ b/dali-toolkit/internal/text/text-controller-relayouter.cpp @@ -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& 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& 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& 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) diff --git a/dali-toolkit/internal/text/text-controller-relayouter.h b/dali-toolkit/internal/text/text-controller-relayouter.h index b605545..c0ab806 100644 --- a/dali-toolkit/internal/text/text-controller-relayouter.h +++ b/dali-toolkit/internal/text/text-controller-relayouter.h @@ -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 -- 2.7.4