From 29bbe2381a1cfdd96757dfd441e7f9747560b2c8 Mon Sep 17 00:00:00 2001 From: ssabah Date: Wed, 26 Jan 2022 18:00:03 +0200 Subject: [PATCH] Support paragraph tag

in markup Paragraph tag is used as block of text start & end with new-line (implicitly). The paragraph tag is nedded to support styles on paragraph level in markup. They are attributes for paragraph tag like: Align, Direction (LTR, RTL), Wrap, etc. Example: Text: "Before paragraph

first paragraph

second paragraph

new line \n third paragraph

After paragraph" Output: ============================ | Before paragraph | | first paragraph | | second paragraph | | new line | | third paragraph | | After paragraph | ============================ How to apply it in TextEditor: textEditor.SetProperty(TextEditor::Property::ENABLE_MARKUP, true); textEditor.SetProperty(TextEditor::Property::TEXT, "text one

Paragraph two

text three

Paragraph four

text five"); How to apply it in TextLabel: textLabel.SetProperty(TextLabel::Property::MULTI_LINE, true); textLabel.SetProperty(TextLabel::Property::ENABLE_MARKUP, true); textLabel.SetProperty(TextLabel::Property::TEXT, "text one

Paragraph two

text three

Paragraph four

text five"); Change-Id: Icee044db488d82646758ccc59a23ce896a3e28c7 --- .../src/dali-toolkit-internal/CMakeLists.txt | 1 + .../dali-toolkit-test-utils/toolkit-text-utils.cpp | 3 +- .../utc-Dali-BoundedParagraph-Functions.cpp | 238 +++++++++++++++++++++ .../dali-toolkit-internal/utc-Dali-Text-Markup.cpp | 3 +- .../utc-Dali-TextEditor-internal.cpp | 34 +++ .../utc-Dali-TextLabel-internal.cpp | 36 ++++ .../src/dali-toolkit/utc-Dali-TextEditor.cpp | 39 ++++ .../src/dali-toolkit/utc-Dali-TextField.cpp | 39 ++++ .../src/dali-toolkit/utc-Dali-TextLabel.cpp | 43 ++++ dali-toolkit/devel-api/text/text-utils-devel.cpp | 3 +- dali-toolkit/internal/file.list | 1 + .../text/bounded-paragraph-helper-functions.cpp | 204 ++++++++++++++++++ .../text/bounded-paragraph-helper-functions.h | 54 +++++ dali-toolkit/internal/text/bounded-paragraph-run.h | 53 +++++ dali-toolkit/internal/text/character-run.h | 15 ++ dali-toolkit/internal/text/logical-model-impl.cpp | 24 +++ dali-toolkit/internal/text/logical-model-impl.h | 16 ++ dali-toolkit/internal/text/markup-processor.cpp | 57 ++++- dali-toolkit/internal/text/markup-processor.h | 6 +- .../internal/text/rendering/view-model.cpp | 10 + dali-toolkit/internal/text/rendering/view-model.h | 11 + .../internal/text/text-controller-text-updater.cpp | 3 +- dali-toolkit/internal/text/text-model-interface.h | 15 ++ dali-toolkit/internal/text/text-model.cpp | 10 + dali-toolkit/internal/text/text-model.h | 11 + dali-toolkit/internal/text/text-view-interface.h | 15 ++ dali-toolkit/internal/text/text-view.cpp | 15 ++ dali-toolkit/internal/text/text-view.h | 11 + 28 files changed, 963 insertions(+), 7 deletions(-) create mode 100644 automated-tests/src/dali-toolkit-internal/utc-Dali-BoundedParagraph-Functions.cpp create mode 100644 dali-toolkit/internal/text/bounded-paragraph-helper-functions.cpp create mode 100644 dali-toolkit/internal/text/bounded-paragraph-helper-functions.h create mode 100644 dali-toolkit/internal/text/bounded-paragraph-run.h diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 6ea7182..198d183 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -9,6 +9,7 @@ SET(CAPI_LIB "dali-toolkit-internal") SET(TC_SOURCES utc-Dali-AddOns.cpp utc-Dali-BidirectionalSupport.cpp + utc-Dali-BoundedParagraph-Functions.cpp utc-Dali-ColorConversion.cpp utc-Dali-Control-internal.cpp utc-Dali-DebugRendering.cpp diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp index 065e5fd..e22071a 100644 --- a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp @@ -115,7 +115,8 @@ void CreateTextModel(const std::string& text, logicalModel->mAnchors, logicalModel->mUnderlinedCharacterRuns, logicalModel->mBackgroundColorRuns, - logicalModel->mStrikethroughCharacterRuns); + logicalModel->mStrikethroughCharacterRuns, + logicalModel->mBoundedParagraphRuns); Length textSize = 0u; const uint8_t* utf8 = NULL; diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-BoundedParagraph-Functions.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-BoundedParagraph-Functions.cpp new file mode 100644 index 0000000..07be747 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-BoundedParagraph-Functions.cpp @@ -0,0 +1,238 @@ +/* + * 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. + * + */ + +#include +#include + +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include + +using namespace Dali; +using namespace Toolkit; +using namespace Text; + +struct BoundedParagraphData +{ + CharacterIndex characterIndex; + Length numberOfCharacters; +}; + +struct TestCaseData +{ + std::string description; ///< Description of the test. + std::string text; ///< The text. + CharacterIndex firstIndexOfRemovedCharacters; ///< The first index of removed characters. + int numberOfRemovedCharacters; ///< The number of removed characters. + Length numberOfBoundedParagraphs; ///< The number of bounded paragraphs before merging. + BoundedParagraphData* boundedParagraphs; ///< The bounded paragraphs info before merging. + Length numberOfExpectedBoundedParagraphs; ///< The number of expected bounded paragraphs after merging. + BoundedParagraphData* expectedBoundedParagraphs; ///< The expected bounded paragraphs info after merging. +}; + +void CreateBoundedParagraphRunsFromBoundedParagraphData( + Vector& boundedParagraphRuns, + const BoundedParagraphData* boundedParagraphs, + const Length& numberOfBoundedParagraphs) +{ + boundedParagraphRuns.Clear(); + + if(boundedParagraphs != nullptr) + { + for(Length index = 0u; index < numberOfBoundedParagraphs; index++) + { + BoundedParagraphRun boundedParagraphRun; + boundedParagraphRun.characterRun.characterIndex = boundedParagraphs[index].characterIndex; + boundedParagraphRun.characterRun.numberOfCharacters = boundedParagraphs[index].numberOfCharacters; + + boundedParagraphRuns.PushBack(boundedParagraphRun); + } + } +} + +bool MergeBoundedParagraphRunsTest(TestCaseData testCase) +{ + // 1) Convert boundedParagraphs to vector of BoundedParagraphRun + Vector boundedParagraphRuns; + CreateBoundedParagraphRunsFromBoundedParagraphData(boundedParagraphRuns, testCase.boundedParagraphs, testCase.numberOfBoundedParagraphs); + + // 2) Convert expectedBoundedParagraphs to vector of BoundedParagraphRun + Vector expectedBoundedParagraphRuns; + CreateBoundedParagraphRunsFromBoundedParagraphData(expectedBoundedParagraphRuns, testCase.expectedBoundedParagraphs, testCase.numberOfExpectedBoundedParagraphs); + + // 3) Convert string text to vector of character utf32 + Vector utf32Text; + utf32Text.Resize(testCase.text.size()); + const uint32_t numberOfCharacters = (testCase.text.size() == 0) ? 0 : Utf8ToUtf32(reinterpret_cast(testCase.text.c_str()), testCase.text.size(), &utf32Text[0u]); + utf32Text.Resize(numberOfCharacters); + + // 4) Call MergeBoundedParagraphRunsWhenRemoveCharacters + MergeBoundedParagraphRunsWhenRemoveCharacters(utf32Text, testCase.firstIndexOfRemovedCharacters, testCase.numberOfRemovedCharacters, boundedParagraphRuns); + + // 5) Verify actual with expected + if(testCase.numberOfExpectedBoundedParagraphs != boundedParagraphRuns.Count()) + { + std::cout << " Different number of bounded paragraph runs after merging: " << boundedParagraphRuns.Count() << ", expected : " << testCase.numberOfExpectedBoundedParagraphs << std::endl; + return false; + } + + for(unsigned int index = 0u; index < testCase.numberOfExpectedBoundedParagraphs; ++index) + { + if(expectedBoundedParagraphRuns[index].characterRun.characterIndex != boundedParagraphRuns[index].characterRun.characterIndex) + { + std::cout << " Different bounded paragraph runs after merging, index : " << index << std::endl; + std::cout << " Different characterIndex, actual: " << boundedParagraphRuns[index].characterRun.characterIndex + << ", expected : " << expectedBoundedParagraphRuns[index].characterRun.characterIndex << std::endl; + return false; + } + + if(expectedBoundedParagraphRuns[index].characterRun.numberOfCharacters != boundedParagraphRuns[index].characterRun.numberOfCharacters) + { + std::cout << " Different bounded paragraph runs after merging, index : " << index << std::endl; + std::cout << " Different numberOfCharacters, actual: " << boundedParagraphRuns[index].characterRun.numberOfCharacters + << ", expected : " << expectedBoundedParagraphRuns[index].characterRun.numberOfCharacters << std::endl; + return false; + } + } + + return true; +} + +int UtcDaliMergeBoundedParagraphRunsWhenRemoveCharacters(void) +{ + tet_infoline(" UtcDaliMergeBoundedParagraphRunsWhenRemoveCharacters "); + + BoundedParagraphData boundedParagraphs01[] = {{10u, 14u}, {37u, 15u}}; + BoundedParagraphData expectedBoundedParagraphs01[] = {{10u, 42u}}; + + BoundedParagraphData boundedParagraphs02[] = {{10u, 14u}, {37u, 15u}}; + BoundedParagraphData expectedBoundedParagraphs02[] = {{37u, 15u}}; + + BoundedParagraphData boundedParagraphs03[] = {{10u, 14u}, {37u, 15u}}; + BoundedParagraphData expectedBoundedParagraphs03[] = {{10u, 14u}, {37u, 20u}}; + + BoundedParagraphData boundedParagraphs04[] = {{10u, 14u}, {37u, 15u}}; + BoundedParagraphData expectedBoundedParagraphs04[] = {{10u, 14u}, {37u, 15u}}; + + BoundedParagraphData boundedParagraphs05[] = {{10u, 14u}, {37u, 15u}}; + BoundedParagraphData expectedBoundedParagraphs05[] = {{10u, 14u}, {37u, 15u}}; + + BoundedParagraphData boundedParagraphs06[] = {{10u, 14u}, {37u, 15u}, {64u, 14u}}; + BoundedParagraphData expectedBoundedParagraphs06[] = {{10u, 68u}}; + + TestCaseData testCases[] = + { + { + + "test-case 01", + "text one \nParagraph two\n text three \nParagraph four\n text five", + 20u, + -26, + 2u, + boundedParagraphs01, + 1u, + expectedBoundedParagraphs01 + + }, + + { + + "test-case 02", + "text one \nParagraph two\n text three \nParagraph four\n text five", + 5u, + -5, + 2u, + boundedParagraphs02, + 1u, + expectedBoundedParagraphs02 + + }, + + { + + "test-case 03", + "text one \nParagraph two\n text three \nParagraph four\n text five", + 47u, + -10, + 2u, + boundedParagraphs03, + 2u, + expectedBoundedParagraphs03 + + }, + + { + + "test-case 04", + "text one \nParagraph two\n text three \nParagraph four\n text five", + 10u, + -9, + 2u, + boundedParagraphs04, + 2u, + expectedBoundedParagraphs04 + + }, + + { + + "test-case 05", + "text one \nParagraph two\n text three \nParagraph four\n text five", + 25u, + -4, + 2u, + boundedParagraphs05, + 2u, + expectedBoundedParagraphs05 + + }, + + { + + "test-case 06", + "text one \nParagraph two\n text three \nParagraph four\n text five \nParagraph six\n text seven", + 10u, + -63, + 3u, + boundedParagraphs06, + 1u, + expectedBoundedParagraphs06 + + }, + + }; + + const unsigned int numberOfTests = 6u; + + for(unsigned int index = 0u; index < numberOfTests; ++index) + { + ToolkitTestApplication application; + tet_infoline(testCases[index].description.c_str()); + + if(!MergeBoundedParagraphRunsTest(testCases[index])) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} \ No newline at end of file diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp index 67299b4..7817c02 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp @@ -185,7 +185,8 @@ bool XHTMLEntityToUTF8Test(const XHTMLEntityToUTF8Data& data) Vector underlinedCharacterRuns; Vector backgroundColorRuns; Vector strikethroughCharacterRuns; - MarkupProcessData markupProcessData(colorRuns, fontRuns, items, anchors, underlinedCharacterRuns, backgroundColorRuns, strikethroughCharacterRuns); + Vector boundedParagraphRuns; + MarkupProcessData markupProcessData(colorRuns, fontRuns, items, anchors, underlinedCharacterRuns, backgroundColorRuns, strikethroughCharacterRuns, boundedParagraphRuns); ProcessMarkupString(data.xHTMLEntityString, markupProcessData); for(Vector::Iterator it = items.Begin(), 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 46abf15..9d78336 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 @@ -637,4 +637,38 @@ int UtcDaliTextEditorMarkupStrikethroughNoEndTag(void) DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION); END_TEST; +} + +int UtcDaliTextEditorMarkupParagraphTag(void) + +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextEditorMarkupParagraphTag "); + + TextEditor textEditor = TextEditor::New(); + application.GetScene().Add(textEditor); + + textEditor.SetProperty(TextEditor::Property::TEXT, "text one

Paragraph two

text three

Paragraph four

text five"); + textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true); + + application.SendNotification(); + application.Render(); + + uint32_t expectedNumberOfBoundedParagraphRuns = 2u; + + Toolkit::Internal::TextEditor& textEditorImpl = GetImpl(textEditor); + const Text::Length numberOfBoundedParagraphRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfBoundedParagraphRuns(); + DALI_TEST_EQUALS(numberOfBoundedParagraphRuns, expectedNumberOfBoundedParagraphRuns, TEST_LOCATION); + + const Vector& boundedParagraphRuns = textEditorImpl.GetTextController()->GetTextModel()->GetBoundedParagraphRuns(); + + //

Paragraph two

+ DALI_TEST_EQUALS(boundedParagraphRuns[0u].characterRun.characterIndex, 10u, TEST_LOCATION); + DALI_TEST_EQUALS(boundedParagraphRuns[0u].characterRun.numberOfCharacters, 14u, TEST_LOCATION); + + //

Paragraph four

+ DALI_TEST_EQUALS(boundedParagraphRuns[1u].characterRun.characterIndex, 37u, TEST_LOCATION); + DALI_TEST_EQUALS(boundedParagraphRuns[1u].characterRun.numberOfCharacters, 15u, TEST_LOCATION); + + END_TEST; } \ No newline at end of file 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 b1c380a..bec9416 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 @@ -524,4 +524,40 @@ int UtcDaliTextLabelMarkupStrikethroughNoEndTag(void) DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION); END_TEST; +} + +int UtcDaliTextLabelMarkupParagraphTag(void) + +{ + ToolkitTestApplication application; + + tet_infoline(" UtcDaliTextLabelMarkupParagraphTag "); + TextLabel textLabel = TextLabel::New(); + + application.GetScene().Add(textLabel); + + textLabel.SetProperty(TextLabel::Property::TEXT, "text one

Paragraph two

text three

Paragraph four

text five"); + textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true); + textLabel.SetProperty(TextLabel::Property::MULTI_LINE, true); + + application.SendNotification(); + application.Render(); + + uint32_t expectedNumberOfBoundedParagraphRuns = 2u; + + Toolkit::Internal::TextLabel& textLabelImpl = GetImpl(textLabel); + const Text::Length numberOfBoundedParagraphRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfBoundedParagraphRuns(); + DALI_TEST_EQUALS(numberOfBoundedParagraphRuns, expectedNumberOfBoundedParagraphRuns, TEST_LOCATION); + + const Vector& boundedParagraphRuns = textLabelImpl.GetTextController()->GetTextModel()->GetBoundedParagraphRuns(); + + //

Paragraph two

+ DALI_TEST_EQUALS(boundedParagraphRuns[0u].characterRun.characterIndex, 10u, TEST_LOCATION); + DALI_TEST_EQUALS(boundedParagraphRuns[0u].characterRun.numberOfCharacters, 14u, TEST_LOCATION); + + //

Paragraph four

+ DALI_TEST_EQUALS(boundedParagraphRuns[1u].characterRun.characterIndex, 37u, TEST_LOCATION); + DALI_TEST_EQUALS(boundedParagraphRuns[1u].characterRun.numberOfCharacters, 15u, TEST_LOCATION); + + END_TEST; } \ No newline at end of file diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp index acf34a6..b2e1f16 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp @@ -5748,3 +5748,42 @@ int UtcDaliTextEditorCharacterSpacing(void) END_TEST; } + +int UtcDaliToolkitTexteditorParagraphTag(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTexteditorParagraphTag"); + TextEditor editorNewlineSeparator = TextEditor::New(); + TextEditor editorParagraphTag = TextEditor::New(); + DALI_TEST_CHECK(editorNewlineSeparator); + DALI_TEST_CHECK(editorParagraphTag); + + application.GetScene().Add(editorNewlineSeparator); + application.GetScene().Add(editorParagraphTag); + + //Same utterance uses new-line to split paragraphs should give similar results for paragraph tag. + editorNewlineSeparator.SetProperty(TextEditor::Property::ENABLE_MARKUP, true); + editorNewlineSeparator.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); + editorNewlineSeparator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + editorNewlineSeparator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + editorNewlineSeparator.SetProperty(TextEditor::Property::TEXT, "test paragraph tag \ntest paragraph tag \ntest paragraph tag "); + + editorParagraphTag.SetProperty(TextEditor::Property::ENABLE_MARKUP, true); + editorParagraphTag.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); + editorParagraphTag.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + editorParagraphTag.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + editorParagraphTag.SetProperty(TextEditor::Property::TEXT, "test paragraph tag

test paragraph tag

test paragraph tag "); + + application.SendNotification(); + application.Render(); + + Vector3 textNaturalSizeNewlineSeparator = editorNewlineSeparator.GetNaturalSize(); + Vector3 textNaturalSizeParagraphTag = editorParagraphTag.GetNaturalSize(); + + DALI_TEST_EQUALS(textNaturalSizeNewlineSeparator, textNaturalSizeParagraphTag, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + END_TEST; +} \ No newline at end of file diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp index 06612b8..060fc9a 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp @@ -5280,4 +5280,43 @@ int UtcDaliToolkitTextFieldUnderlineTypesGeneration3(void) application.Render(); END_TEST; +} + +int UtcDaliToolkitTextfieldParagraphTag(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextfieldParagraphTag"); + TextField fieldNewlineSeparator = TextField::New(); + TextField fieldParagraphTag = TextField::New(); + DALI_TEST_CHECK(fieldNewlineSeparator); + DALI_TEST_CHECK(fieldParagraphTag); + + application.GetScene().Add(fieldNewlineSeparator); + application.GetScene().Add(fieldParagraphTag); + + //Same utterance uses new-line to split paragraphs should give similar results for paragraph tag. + fieldNewlineSeparator.SetProperty(TextField::Property::ENABLE_MARKUP, true); + fieldNewlineSeparator.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); + fieldNewlineSeparator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + fieldNewlineSeparator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + fieldNewlineSeparator.SetProperty(TextField::Property::TEXT, "test paragraph tag \ntest paragraph tag \ntest paragraph tag "); + + fieldParagraphTag.SetProperty(TextField::Property::ENABLE_MARKUP, true); + fieldParagraphTag.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); + fieldParagraphTag.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + fieldParagraphTag.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + fieldParagraphTag.SetProperty(TextField::Property::TEXT, "test paragraph tag

test paragraph tag

test paragraph tag "); + + application.SendNotification(); + application.Render(); + + Vector3 textNaturalSizeNewlineSeparator = fieldNewlineSeparator.GetNaturalSize(); + Vector3 textNaturalSizeParagraphTag = fieldParagraphTag.GetNaturalSize(); + + DALI_TEST_EQUALS(textNaturalSizeNewlineSeparator, textNaturalSizeParagraphTag, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + END_TEST; } \ No newline at end of file diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 95d0689..ecc5f67 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -2653,4 +2653,47 @@ int UtcDaliTextLabelCharacterSpacing(void) application.Render(); END_TEST; +} + +int UtcDaliToolkitTextlabelParagraphTag(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextlabelParagraphTag"); + TextLabel labelNewlineSeparator = TextLabel::New(); + TextLabel labelParagraphTag = TextLabel::New(); + DALI_TEST_CHECK(labelNewlineSeparator); + DALI_TEST_CHECK(labelParagraphTag); + + application.GetScene().Add(labelNewlineSeparator); + application.GetScene().Add(labelParagraphTag); + + //Same utterance uses new-line to split paragraphs should give similar results for paragraph tag. + labelNewlineSeparator.SetProperty(TextLabel::Property::MULTI_LINE, true); + labelNewlineSeparator.SetProperty(TextLabel::Property::ELLIPSIS, false); + labelNewlineSeparator.SetProperty(TextLabel::Property::ENABLE_MARKUP, true); + labelNewlineSeparator.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); + labelNewlineSeparator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + labelNewlineSeparator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + labelNewlineSeparator.SetProperty(TextLabel::Property::TEXT, "test paragraph tag \ntest paragraph tag \ntest paragraph tag "); + + labelParagraphTag.SetProperty(TextLabel::Property::MULTI_LINE, true); + labelParagraphTag.SetProperty(TextLabel::Property::ELLIPSIS, false); + labelParagraphTag.SetProperty(TextLabel::Property::ENABLE_MARKUP, true); + labelParagraphTag.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f)); + labelParagraphTag.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + labelParagraphTag.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + labelParagraphTag.SetProperty(TextLabel::Property::TEXT, "test paragraph tag

test paragraph tag

test paragraph tag "); + + application.SendNotification(); + application.Render(); + + Vector3 textNaturalSizeNewlineSeparator = labelNewlineSeparator.GetNaturalSize(); + Vector3 textNaturalSizeParagraphTag = labelParagraphTag.GetNaturalSize(); + + DALI_TEST_EQUALS(textNaturalSizeNewlineSeparator, textNaturalSizeParagraphTag, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + END_TEST; } \ No newline at end of file diff --git a/dali-toolkit/devel-api/text/text-utils-devel.cpp b/dali-toolkit/devel-api/text/text-utils-devel.cpp index 7242687..81b82d8 100644 --- a/dali-toolkit/devel-api/text/text-utils-devel.cpp +++ b/dali-toolkit/devel-api/text/text-utils-devel.cpp @@ -177,7 +177,8 @@ void ShapeTextPreprocess(const RendererParameters& textParameters, TextAbstracti textModel->mLogicalModel->mAnchors, textModel->mLogicalModel->mUnderlinedCharacterRuns, textModel->mLogicalModel->mBackgroundColorRuns, - textModel->mLogicalModel->mStrikethroughCharacterRuns); + textModel->mLogicalModel->mStrikethroughCharacterRuns, + textModel->mLogicalModel->mBoundedParagraphRuns); if(textParameters.markupEnabled) { diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index c65b61e..9b543fd 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -136,6 +136,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/image-loader/image-url-impl.cpp ${toolkit_src_dir}/styling/style-manager-impl.cpp ${toolkit_src_dir}/text/bidirectional-support.cpp + ${toolkit_src_dir}/text/bounded-paragraph-helper-functions.cpp ${toolkit_src_dir}/text/character-set-conversion.cpp ${toolkit_src_dir}/text/color-segmentation.cpp ${toolkit_src_dir}/text/cursor-helper-functions.cpp diff --git a/dali-toolkit/internal/text/bounded-paragraph-helper-functions.cpp b/dali-toolkit/internal/text/bounded-paragraph-helper-functions.cpp new file mode 100644 index 0000000..7b207f4 --- /dev/null +++ b/dali-toolkit/internal/text/bounded-paragraph-helper-functions.cpp @@ -0,0 +1,204 @@ +/* + * 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 + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Text +{ +void MergeBoundedParagraphRunsWhenRemoveCharacters(const Vector& text, + const CharacterIndex& index, + const int& numberOfCharacters, + Vector& boundedParagraphRuns) +{ + // This works on boundedParagraphRuns before applying on them the changes of the removed characters. + // Update to merge only when characters have been removed. + if(numberOfCharacters >= 0) + { + return; + } + + //No runs to merge + if(boundedParagraphRuns.Count() == 0u) + { + return; + } + + const Length numberOfRemovedCharacters = (Length)(-1 * numberOfCharacters); + const Length totalNumberOfCharacters = text.Count(); + const CharacterIndex& firstIndexOfRemovedCharacters = index; + const CharacterIndex lastIndexOfRemovedCharacters = ((firstIndexOfRemovedCharacters + numberOfRemovedCharacters) > 0u) ? (firstIndexOfRemovedCharacters + numberOfRemovedCharacters - 1u) : firstIndexOfRemovedCharacters; // Note: Length is uint32. Extra validation to avoid a potential defects. + + Length numberOfRuns = boundedParagraphRuns.Count(); + Length firstRunIndexToUpdate = 0; + Length lastRunIndexToUpdate = 0; + bool noNeedToMerge = false; + + // Find the first boundedParagraphRuns that is possible to be updated. + while(firstRunIndexToUpdate < numberOfRuns) + { + const CharacterIndex startCharIndex = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.characterIndex; + const CharacterIndex endCharIndex = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.GetEndCharacterIndex(); + + // In-case the paragraph separator of the plain text (before the current bounded paragraph) is removed. + // In-case the start index of the current bounded paragraph is between start and end indices of removed characters. + // In-case the end index of the current bounded paragraph is between start and end indices of removed characters. + if((startCharIndex == lastIndexOfRemovedCharacters + 1u) || + ((firstIndexOfRemovedCharacters <= startCharIndex) && (startCharIndex <= lastIndexOfRemovedCharacters)) || + ((firstIndexOfRemovedCharacters <= endCharIndex) && (endCharIndex <= lastIndexOfRemovedCharacters))) + { + break; + } + else if(lastIndexOfRemovedCharacters + 1u < startCharIndex) + { // The whole removed characters are exist before the remaining bounded paragraphs. + noNeedToMerge = true; + break; + } + firstRunIndexToUpdate++; + } + + // There is no run was affected by the removed characters. + if(noNeedToMerge || (firstRunIndexToUpdate == numberOfRuns)) + { + return; + } + + // Find the last boundedParagraphRuns that is possible to be updated. + lastRunIndexToUpdate = firstRunIndexToUpdate; + while(lastRunIndexToUpdate < numberOfRuns - 1u) + { + const CharacterIndex startCharIndex = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.characterIndex; + const CharacterIndex endCharIndex = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.GetEndCharacterIndex(); + + if((lastIndexOfRemovedCharacters < endCharIndex) || + (lastIndexOfRemovedCharacters + 1u <= startCharIndex)) + { + break; + } + + lastRunIndexToUpdate++; + } + + // Remove all boundedParagraphRun between firstRunIndexToUpdate and lastRunIndexToUpdate + // At least one boundedParagraphRun between firstRunIndexToUpdate and lastRunIndexToUpdate + if(firstRunIndexToUpdate + 1u < lastRunIndexToUpdate) + { + Length runIndexToDelete = firstRunIndexToUpdate + 1u; + + while(runIndexToDelete < lastRunIndexToUpdate) + { + Dali::Vector::Iterator paragraphToDelete = boundedParagraphRuns.Begin() + (runIndexToDelete); + boundedParagraphRuns.Remove(paragraphToDelete); + + lastRunIndexToUpdate--; + numberOfRuns--; + } + } + + CharacterIndex endCharIndexFirstRun = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.GetEndCharacterIndex(); + ; + if(firstRunIndexToUpdate == lastRunIndexToUpdate) + { + if(endCharIndexFirstRun < lastIndexOfRemovedCharacters) + { + boundedParagraphRuns[firstRunIndexToUpdate].characterRun.numberOfCharacters += (lastIndexOfRemovedCharacters - endCharIndexFirstRun); + } + } + else + { + CharacterIndex startCharIndexLastRun = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.characterIndex; + boundedParagraphRuns[firstRunIndexToUpdate].characterRun.numberOfCharacters += ((startCharIndexLastRun - endCharIndexFirstRun) > 0u) ? (startCharIndexLastRun - endCharIndexFirstRun - 1u) : 0u; // Note: Length is uint32. Extra validation to avoid a potential defects. + + CharacterIndex endCharIndexLastRun = boundedParagraphRuns[lastRunIndexToUpdate].characterRun.GetEndCharacterIndex(); + + if(endCharIndexLastRun < lastIndexOfRemovedCharacters) + { + boundedParagraphRuns[lastRunIndexToUpdate].characterRun.numberOfCharacters += (lastIndexOfRemovedCharacters - endCharIndexLastRun); + } + } + + // Each endCharIndex for boundedParagraphRun is a paragraph separator. + // If not then keep adding characters until find paragraph separator. + Length runIndex = firstRunIndexToUpdate; + while(runIndex <= lastRunIndexToUpdate) + { + CharacterIndex endCharIndex = boundedParagraphRuns[runIndex].characterRun.GetEndCharacterIndex(); + + // The remaining text was not affected. + if(endCharIndex > lastIndexOfRemovedCharacters) + { + break; + } + + // Reference for numberOfCharacters in current run to update it + CharacterIndex& numberOfCharactersInRun = boundedParagraphRuns[runIndex].characterRun.numberOfCharacters; + + // In-case arrived to the start of the next run and there is no paragraph separator. + // Merging the next run with the current run. Removing the next run. + if((runIndex + 1u < numberOfRuns) && + (endCharIndex <= lastIndexOfRemovedCharacters) && + ((lastIndexOfRemovedCharacters + 1u) < totalNumberOfCharacters) && + (!TextAbstraction::IsNewParagraph(*(text.Begin() + lastIndexOfRemovedCharacters + 1u)))) + { + numberOfCharactersInRun += boundedParagraphRuns[runIndex + 1u].characterRun.numberOfCharacters; + + Dali::Vector::Iterator paragraphToDelete = boundedParagraphRuns.Begin() + (runIndex + 1u); + boundedParagraphRuns.Remove(paragraphToDelete); + + numberOfRuns--; + lastRunIndexToUpdate--; + + continue; + } + + runIndex++; + } + + // Each startCharIndex-1u for boundedParagraphRun is a paragraph separator. + // If not then remove boundedParagraphRun. + if(numberOfRuns > 0u && + firstIndexOfRemovedCharacters > 0u && + boundedParagraphRuns[firstRunIndexToUpdate].characterRun.characterIndex > 0u) + { + const CharacterIndex startCharIndex = boundedParagraphRuns[firstRunIndexToUpdate].characterRun.characterIndex; + + if(firstIndexOfRemovedCharacters <= startCharIndex && startCharIndex <= lastIndexOfRemovedCharacters + 1u) + { + // Verify the paragraph separator before the first run to update + // In-case the paragraph separator is removed before the boundedParagraphRun. + // Remove the boundedParagraphRun. + if((!TextAbstraction::IsNewParagraph(*(text.Begin() + firstIndexOfRemovedCharacters - 1u))) && + (!TextAbstraction::IsNewParagraph(*(text.Begin() + startCharIndex)))) + { + Dali::Vector::Iterator paragraphToDelete = boundedParagraphRuns.Begin() + (firstRunIndexToUpdate); + boundedParagraphRuns.Remove(paragraphToDelete); + } + } + } +} +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali \ No newline at end of file diff --git a/dali-toolkit/internal/text/bounded-paragraph-helper-functions.h b/dali-toolkit/internal/text/bounded-paragraph-helper-functions.h new file mode 100644 index 0000000..cdcbc69 --- /dev/null +++ b/dali-toolkit/internal/text/bounded-paragraph-helper-functions.h @@ -0,0 +1,54 @@ +#ifndef DALI_TOOLKIT_TEXT_BOUNDED_PARAGRAPH_HELPER_FUNCTIONS_H +#define DALI_TOOLKIT_TEXT_BOUNDED_PARAGRAPH_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 + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Text +{ +/** + * @brief Merge BoundedParagraphRun when the paragraph separator has been removed. + * Adding the next characters until arrived to a paragraph separator. + * Or merging with the next BoundedParagraphRun and removing the next BoundedParagraphRun. + * + * @param[in] text Vector of UTF-32 characters. + * @param[in] index Index to the first character updated. + * @param[in] numberOfCharacters The number of the removed characters. + * @param[inout] boundedParagraphRuns The bounded paragraph runs. + * + */ +void MergeBoundedParagraphRunsWhenRemoveCharacters(const Vector& text, + const CharacterIndex& index, + const int& numberOfCharacters, + Vector& boundedParagraphRuns); +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_BOUNDED_PARAGRAPH_HELPER_FUNCTIONS_H diff --git a/dali-toolkit/internal/text/bounded-paragraph-run.h b/dali-toolkit/internal/text/bounded-paragraph-run.h new file mode 100644 index 0000000..6c5b2d8 --- /dev/null +++ b/dali-toolkit/internal/text/bounded-paragraph-run.h @@ -0,0 +1,53 @@ +#ifndef DALI_TOOLKIT_TEXT_BOUNDED_PARAGRAPH_RUN_H +#define DALI_TOOLKIT_TEXT_BOUNDED_PARAGRAPH_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 + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Text +{ +/** + * @brief BoundedParagraphRun + * + * In terms of the bidirectional algorithm, a 'paragraph' is understood as a run of characters between Paragraph Separators or appropriate Newline Functions. + * A 'paragraph' may also be determined by higher-level protocols like a mark-up tag. + * Bounded-paragraph is a pragraph that have been bounded by explicit tags like a mark-up tag. + * Bounded-paragraph could contain multi paragraphs that have been breaked by Paragraph Separators or appropriate Newline Functions. + * This will be used to handle information for the attributes of markup tag. Like TextAlign, TextDirection, TextIndent, LineHeight, etc. + */ +struct BoundedParagraphRun +{ + CharacterRun characterRun; ///< The initial character index within the whole text and the number of characters of the run. +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_BOUNDED_PARAGRAPH_RUN_H diff --git a/dali-toolkit/internal/text/character-run.h b/dali-toolkit/internal/text/character-run.h index 51a3ef7..757beb0 100644 --- a/dali-toolkit/internal/text/character-run.h +++ b/dali-toolkit/internal/text/character-run.h @@ -46,6 +46,21 @@ struct CharacterRun CharacterIndex characterIndex; ///< Index to the first character. Length numberOfCharacters; ///< Number of characters in the run. + + //Methods + + /** + * @brief Calculate the end index in run. + * @return the end character index in run. + */ + CharacterIndex GetEndCharacterIndex() const + { + DALI_ASSERT_DEBUG(!((0u == numberOfCharacters) && (characterIndex > 0u)) && + "Toolkit::Text::CharacterRun. NumberOfCharacters should be greater than zero"); + + // Note: Length is uint32. Extra validation to avoid a potential defects. + return (numberOfCharacters == 0u ? 0u : (characterIndex + numberOfCharacters - 1u)); + } }; } // namespace Text diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp index 4516662..9ad00bc 100644 --- a/dali-toolkit/internal/text/logical-model-impl.cpp +++ b/dali-toolkit/internal/text/logical-model-impl.cpp @@ -19,6 +19,7 @@ #include // INTERNAL INCLUDES +#include #include #include @@ -331,6 +332,19 @@ void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharact // Free memory allocated for the font family name. FreeFontFamilyNames(removedFontDescriptionRuns); + + // Process the bounded paragraph runs + MergeBoundedParagraphRunsWhenRemoveCharacters(mText, + index, + numberOfCharacters, + mBoundedParagraphRuns); + + Vector removedBoundedParagraphRuns; + UpdateCharacterRuns(index, + numberOfCharacters, + totalNumberOfCharacters, + mBoundedParagraphRuns, + removedBoundedParagraphRuns); } void LogicalModel::RetrieveStyle(CharacterIndex index, InputStyle& style) @@ -600,6 +614,16 @@ void LogicalModel::FindParagraphs(CharacterIndex index, } } +Length LogicalModel::GetNumberOfBoundedParagraphRuns() const +{ + return mBoundedParagraphRuns.Count(); +} + +const Vector& LogicalModel::GetBoundedParagraphRuns() const +{ + return mBoundedParagraphRuns; +} + void LogicalModel::ClearEmbeddedImages() { FreeEmbeddedItems(mEmbeddedItems); diff --git a/dali-toolkit/internal/text/logical-model-impl.h b/dali-toolkit/internal/text/logical-model-impl.h index 08c636d..c54c523 100644 --- a/dali-toolkit/internal/text/logical-model-impl.h +++ b/dali-toolkit/internal/text/logical-model-impl.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -182,6 +183,20 @@ public: Length numberOfCharacters, Vector& paragraphs); + /** + * @brief Retrieves the number of bounded paragraph runs. + * + * @return The number of bounded paragraph runs. + */ + Length GetNumberOfBoundedParagraphRuns() const; + + /** + * @brief Retrieves the reference for bounded paragraph runs. + * + * @return The reference for bounded paragraph runs. + */ + const Vector& GetBoundedParagraphRuns() const; + // Embedded images /** @@ -228,6 +243,7 @@ public: Vector mAnchors; Vector mUnderlinedCharacterRuns; ///< The underlined character run from markup-processor Vector mStrikethroughCharacterRuns; ///< The strikethrough character run from markup-processor + Vector mBoundedParagraphRuns; ///< The bounded paragraph is used to handle a paragraph mark-up tag and it's attributes. Like TextAlign, TextDirection, TextIndent, LineHeight, etc. BidirectionalLineRunIndex mBidirectionalLineIndex; ///< The last fetched bidirectional line info. }; diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp index 17aae96..e046049 100644 --- a/dali-toolkit/internal/text/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor.cpp @@ -60,6 +60,7 @@ const std::string XHTML_ANCHOR_TAG("a"); 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 char LESS_THAN = '<'; const char GREATER_THAN = '>'; @@ -74,6 +75,7 @@ const char CHAR_ARRAY_END = '\0'; const char HEX_CODE = 'x'; const char WHITE_SPACE = 0x20; // ASCII value of the white space. +const char NEW_LINE = 0x0A; // ASCII value of the newline. // Range 1 0x0u < XHTML_DECIMAL_ENTITY_RANGE <= 0xD7FFu // Range 2 0xE000u < XHTML_DECIMAL_ENTITY_RANGE <= 0xFFFDu @@ -211,6 +213,17 @@ void Initialize(StrikethroughCharacterRun& strikethroughCharacterRun) } /** + * @brief Initializes a bounded-paragraph character run to its defaults. + * + * @param[in,out] boundedParagraphRun The bounded paragraphRun run to initialize. + */ +void Initialize(BoundedParagraphRun& boundedParagraphRun) +{ + boundedParagraphRun.characterRun.characterIndex = 0u; + boundedParagraphRun.characterRun.numberOfCharacters = 0u; +} + +/** * @brief Splits the tag string into the tag name and its attributes. * * The attributes are stored in a vector in the tag. @@ -637,6 +650,30 @@ void ProcessItemTag( } /** + * @brief Processes the paragraph-tag + * + * @param[in/out] markupProcessData The markup process data + * @param[in] tag The current tag + * @param[in] isEndBuffer Whether the end of buffer + * @param[in/out] characterIndex The current character index + */ +void ProcessParagraphTag( + MarkupProcessData& markupProcessData, + const Tag tag, + bool isEndBuffer, + CharacterIndex& characterIndex) +{ + if((characterIndex > 0 && + markupProcessData.markupProcessedText[characterIndex - 1u] != NEW_LINE) && + (!(tag.isEndTag && isEndBuffer))) + { + // Insert new-line character at the start and end of paragraph. + markupProcessData.markupProcessedText.append(1u, NEW_LINE); + ++characterIndex; + } +} + +/** * @brief Processes the anchor tag * * @param[in/out] markupProcessData The markup process data @@ -764,13 +801,21 @@ void ProcessSpanForRun( * @param[in] colorRunIndex The color run index * @param[in] underlinedCharacterRunIndex The underlined character run index * @param[in] backgroundRunIndex The background run index + * @param[in] boundedParagraphRunIndex The bounded paragraph run index + * */ -void ResizeModelVectors(MarkupProcessData& markupProcessData, const RunIndex fontRunIndex, const RunIndex colorRunIndex, const RunIndex underlinedCharacterRunIndex, const RunIndex backgroundRunIndex) +void ResizeModelVectors(MarkupProcessData& markupProcessData, + const RunIndex fontRunIndex, + const RunIndex colorRunIndex, + const RunIndex underlinedCharacterRunIndex, + const RunIndex backgroundRunIndex, + const RunIndex boundedParagraphRunIndex) { markupProcessData.fontRuns.Resize(fontRunIndex); markupProcessData.colorRuns.Resize(colorRunIndex); markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex); markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex); + markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex); #ifdef DEBUG_ENABLED for(unsigned int i = 0; i < colorRunIndex; ++i) @@ -895,6 +940,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar RunIndex underlinedCharacterRunIndex = 0u; RunIndex backgroundRunIndex = 0u; RunIndex strikethroughCharacterRunIndex = 0u; + RunIndex boundedParagraphRunIndex = 0u; // check tag reference int colorTagReference = 0u; @@ -905,6 +951,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar int backgroundTagReference = 0u; int spanTagReference = 0u; int sTagReference = 0u; + int pTagReference = 0u; // Give an initial default value to the model's vectors. markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE); @@ -1001,6 +1048,12 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar ProcessTagForRun( markupProcessData.strikethroughCharacterRuns, styleStack, tag, characterIndex, strikethroughCharacterRunIndex, sTagReference, [](const Tag& tag, StrikethroughCharacterRun& run) { ProcessStrikethroughTag(tag, run); }); } // + else if(TokenComparison(XHTML_PARAGRAPH_TAG, tag.buffer, tag.length)) + { + ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex); + ProcessTagForRun( + markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) {}); + } //

} // end if( IsTag() ) else if(markupStringBuffer < markupStringEndBuffer) { @@ -1009,7 +1062,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar } // Resize the model's vectors. - ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, backgroundRunIndex); + ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex); } } // namespace Text diff --git a/dali-toolkit/internal/text/markup-processor.h b/dali-toolkit/internal/text/markup-processor.h index bb1b6ba..3ef7a2d 100644 --- a/dali-toolkit/internal/text/markup-processor.h +++ b/dali-toolkit/internal/text/markup-processor.h @@ -24,6 +24,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -47,7 +48,8 @@ struct MarkupProcessData Vector& anchors, Vector& underlinedCharacterRuns, Vector& backgroundColorRuns, - Vector& strikethroughCharacterRuns) + Vector& strikethroughCharacterRuns, + Vector& boundedParagraphRuns) : colorRuns(colorRuns), fontRuns(fontRuns), items(items), @@ -55,6 +57,7 @@ struct MarkupProcessData underlinedCharacterRuns(underlinedCharacterRuns), backgroundColorRuns(backgroundColorRuns), strikethroughCharacterRuns(strikethroughCharacterRuns), + boundedParagraphRuns(boundedParagraphRuns), markupProcessedText() { } @@ -66,6 +69,7 @@ struct MarkupProcessData Vector& underlinedCharacterRuns; ///< The underlined character runs. Vector& backgroundColorRuns; ///< The background color runs. Vector& strikethroughCharacterRuns; ///< The strikethrough character runs. + Vector& boundedParagraphRuns; ///< The bounded paragraph runs std::string markupProcessedText; ///< The mark-up string. }; diff --git a/dali-toolkit/internal/text/rendering/view-model.cpp b/dali-toolkit/internal/text/rendering/view-model.cpp index 47aed00..0b26e4e 100644 --- a/dali-toolkit/internal/text/rendering/view-model.cpp +++ b/dali-toolkit/internal/text/rendering/view-model.cpp @@ -645,6 +645,16 @@ void ViewModel::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, S mModel->GetStrikethroughRuns(strikethroughRuns, index, numberOfRuns); } +Length ViewModel::GetNumberOfBoundedParagraphRuns() const +{ + return mModel->GetNumberOfBoundedParagraphRuns(); +} + +const Vector& ViewModel::GetBoundedParagraphRuns() const +{ + return mModel->GetBoundedParagraphRuns(); +} + } // namespace Text } // namespace Toolkit diff --git a/dali-toolkit/internal/text/rendering/view-model.h b/dali-toolkit/internal/text/rendering/view-model.h index ef8ba87..73b7fa6 100644 --- a/dali-toolkit/internal/text/rendering/view-model.h +++ b/dali-toolkit/internal/text/rendering/view-model.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include #include #include @@ -314,6 +315,16 @@ public: Length GetNumberOfStrikethroughRuns() const override; /** + * @copydoc ModelInterface::GetNumberOfBoundedParagraphRuns() + */ + virtual Length GetNumberOfBoundedParagraphRuns() const override; + + /** + * @copydoc ModelInterface::GetBoundedParagraphRuns() + */ + virtual const Vector& GetBoundedParagraphRuns() const override; + + /** * @copydoc ModelInterface::GetStrikethroughRuns() */ void GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const override; diff --git a/dali-toolkit/internal/text/text-controller-text-updater.cpp b/dali-toolkit/internal/text/text-controller-text-updater.cpp index caf44f7..0b24bc0 100644 --- a/dali-toolkit/internal/text/text-controller-text-updater.cpp +++ b/dali-toolkit/internal/text/text-controller-text-updater.cpp @@ -91,7 +91,8 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string& logicalModel->mAnchors, logicalModel->mUnderlinedCharacterRuns, logicalModel->mBackgroundColorRuns, - logicalModel->mStrikethroughCharacterRuns); + logicalModel->mStrikethroughCharacterRuns, + logicalModel->mBoundedParagraphRuns); Length textSize = 0u; const uint8_t* utf8 = NULL; diff --git a/dali-toolkit/internal/text/text-model-interface.h b/dali-toolkit/internal/text/text-model-interface.h index f9d993a..c7e7b98 100644 --- a/dali-toolkit/internal/text/text-model-interface.h +++ b/dali-toolkit/internal/text/text-model-interface.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -388,6 +389,20 @@ public: virtual Length GetNumberOfStrikethroughRuns() const = 0; /** + * @brief Retrieves the number of bounded paragraph runs. + * + * @return The number of bounded paragraph runs. + */ + virtual Length GetNumberOfBoundedParagraphRuns() const = 0; + + /** + * @brief Retrieves the reference for bounded paragraph runs. + * + * @return The reference for bounded paragraph runs. + */ + virtual const Vector& GetBoundedParagraphRuns() const = 0; + + /** * @brief Retrieves the strikethrough runs. * * @param[out] strikethroughRuns Pointer to a buffer where the strikethrough runs are copied. diff --git a/dali-toolkit/internal/text/text-model.cpp b/dali-toolkit/internal/text/text-model.cpp index 7ce74ca..924343c 100644 --- a/dali-toolkit/internal/text/text-model.cpp +++ b/dali-toolkit/internal/text/text-model.cpp @@ -276,6 +276,16 @@ Length Model::GetNumberOfStrikethroughRuns() const return mVisualModel->GetNumberOfStrikethroughRuns(); } +Length Model::GetNumberOfBoundedParagraphRuns() const +{ + return mLogicalModel->GetNumberOfBoundedParagraphRuns(); +} + +const Vector& Model::GetBoundedParagraphRuns() const +{ + return mLogicalModel->GetBoundedParagraphRuns(); +} + void Model::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const { mVisualModel->GetStrikethroughRuns(strikethroughRuns, index, numberOfRuns); diff --git a/dali-toolkit/internal/text/text-model.h b/dali-toolkit/internal/text/text-model.h index 7077c85..ded9496 100644 --- a/dali-toolkit/internal/text/text-model.h +++ b/dali-toolkit/internal/text/text-model.h @@ -22,6 +22,7 @@ #include // INTERNAL INCLUDES +#include #include #include #include @@ -302,6 +303,16 @@ public: */ void GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const override; + /** + * @copydoc ModelInterface::GetNumberOfBoundedParagraphRuns() + */ + virtual Length GetNumberOfBoundedParagraphRuns() const override; + + /** + * @copydoc ModelInterface::GetBoundedParagraphRuns() + */ + virtual const Vector& GetBoundedParagraphRuns() const override; + private: // Private contructors & copy operator. /** * @brief Private constructor. diff --git a/dali-toolkit/internal/text/text-view-interface.h b/dali-toolkit/internal/text/text-view-interface.h index 2dda239..9caf068 100644 --- a/dali-toolkit/internal/text/text-view-interface.h +++ b/dali-toolkit/internal/text/text-view-interface.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include #include #include #include @@ -323,6 +324,20 @@ public: virtual Length GetNumberOfStrikethroughRuns() const = 0; /** + * @brief Retrieves the number of bounded paragraph runs. + * + * @return The number of bounded paragraph runs. + */ + virtual Length GetNumberOfBoundedParagraphRuns() const = 0; + + /** + * @brief Retrieves the reference for bounded paragraph runs. + * + * @return The reference for bounded paragraph runs. + */ + virtual const Vector& GetBoundedParagraphRuns() const = 0; + + /** * @brief Retrieves the strikethrough runs. * * @param[out] strikethroughRuns Pointer to a buffer where the strikethrough runs are copied. diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp index 137ded2..ed64520 100644 --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -824,6 +824,21 @@ void View::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, } } +Length View::GetNumberOfBoundedParagraphRuns() const +{ + if(mImpl->mLogicalModel) + { + return mImpl->mLogicalModel->GetNumberOfBoundedParagraphRuns(); + } + + return 0u; +} + +const Vector& View::GetBoundedParagraphRuns() const +{ + return mImpl->mLogicalModel->GetBoundedParagraphRuns(); +} + const float View::GetCharacterSpacing() const { return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetCharacterSpacing() : 0.f; diff --git a/dali-toolkit/internal/text/text-view.h b/dali-toolkit/internal/text/text-view.h index 8eeb882..06bf838 100644 --- a/dali-toolkit/internal/text/text-view.h +++ b/dali-toolkit/internal/text/text-view.h @@ -19,6 +19,7 @@ */ // INTERNAL INCLUDES +#include #include #include #include @@ -248,6 +249,16 @@ public: Length numberOfRuns) const; /** + * @copydoc Dali::Toolkit::Text::ViewInterface::GetNumberOfBoundedParagraphRuns() + */ + virtual Length GetNumberOfBoundedParagraphRuns() const; + + /** + * @copydoc Dali::Toolkit::Text::ViewInterface::GetBoundedParagraphRuns() + */ + virtual const Vector& GetBoundedParagraphRuns() const; + + /** * @copydoc Dali::Toolkit::Text::ViewInterface::GetCharacterSpacing() */ const float GetCharacterSpacing() const override; -- 2.7.4