#include <dali-toolkit/internal/text/hyphenator.h>
#include <dali-toolkit/internal/text/layouts/layout-engine.h>
#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
-#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
#include <dali-toolkit/internal/text/multi-language-support.h>
#include <dali-toolkit/internal/text/segmentation.h>
#include <dali-toolkit/internal/text/shaper.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
namespace Dali
{
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/metrics.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-model.h>
namespace Dali
/*
- * Copyright (c) 2020 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.
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/internal/text/line-helper-functions.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
#include <dali-toolkit/internal/text/rendering/view-model.h>
-#include <dali-toolkit/internal/text/text-controller.h>
#include <toolkit-text-utils.h>
using namespace Dali;
/*
- * 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.
#include <toolkit-text-utils.h>
#include <dali/devel-api/events/key-event-devel.h>
#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
using namespace Dali;
using namespace Toolkit;
/*
- * 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.
#include <dali-toolkit/internal/text/font-description-run.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
#include <dali-toolkit/internal/text/rendering/view-model.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-view.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/internal/text/color-run.h>
#include <dali-toolkit/internal/text/font-description-run.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
#include <dali-toolkit/internal/text/text-definitions.h>
#include <dali-toolkit/internal/text/text-io.h>
#include <toolkit-text-utils.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/text/bitmap-font.h>
#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
#include <dali-toolkit/internal/text/rendering/view-model.h>
-#include <dali-toolkit/internal/text/text-controller.h>
#include <dali/devel-api/text-abstraction/bitmap-font.h>
#include <toolkit-environment-variable.h>
#include <toolkit-text-utils.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.
#include <dali-toolkit/dali-toolkit.h>
#include <toolkit-text-utils.h>
#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
#include <dali-toolkit/internal/text/rendering/view-model.h>
-#include <dali-toolkit/internal/text/text-controller.h>
using namespace Dali;
using namespace Toolkit;
#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
using namespace Dali;
using namespace Toolkit;
}
END_TEST;
-}
\ No newline at end of file
+}
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller.h>
using namespace Dali;
using namespace Toolkit;
}
END_TEST;
-}
\ No newline at end of file
+}
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
#include <dali-toolkit/internal/text/rendering/view-model.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller.h>
using namespace Dali;
using namespace Toolkit;
}
END_TEST;
-}
\ No newline at end of file
+}
#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
#include <dali-toolkit/internal/text/layouts/layout-engine.h>
#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
-#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
#include <dali-toolkit/internal/text/multi-language-support.h>
#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
#include <dali-toolkit/internal/text/segmentation.h>
#define DALI_TOOLKIT_INTERNAL_TEXT_CONTROLS_COMMON_TEXT_UTILS_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.
#include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
#include <dali-toolkit/internal/text/rendering/text-renderer.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/public-api/controls/control.h>
#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
#include <dali-toolkit/internal/text/rendering/text-renderer.h>
#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-editable-control-interface.h>
#include <dali-toolkit/internal/text/text-selectable-control-interface.h>
#include <dali-toolkit/internal/text/text-vertical-scroller.h>
#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/internal/text/text-font-style.h>
#include <dali-toolkit/internal/text/rendering/text-renderer.h>
#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-editable-control-interface.h>
#include <dali-toolkit/internal/text/text-selectable-control-interface.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/devel-api/text/rendering-backend.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/internal/text/text-font-style.h>
#include <dali-toolkit/internal/text/rendering/text-renderer.h>
#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/text-scroller-interface.h>
#include <dali-toolkit/internal/text/text-scroller.h>
#include <dali-toolkit/internal/visuals/text/text-visual.h>
${toolkit_src_dir}/text/cursor-helper-functions.cpp
${toolkit_src_dir}/text/glyph-metrics-helper.cpp
${toolkit_src_dir}/text/logical-model-impl.cpp
- ${toolkit_src_dir}/text/markup-processor.cpp
- ${toolkit_src_dir}/text/markup-processor-color.cpp
- ${toolkit_src_dir}/text/markup-processor-embedded-item.cpp
- ${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
- ${toolkit_src_dir}/text/markup-processor-character-spacing.cpp
- ${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
- ${toolkit_src_dir}/text/markup-processor-attribute-helper-functions.cpp
${toolkit_src_dir}/text/multi-language-support.cpp
${toolkit_src_dir}/text/hidden-text.cpp
${toolkit_src_dir}/text/input-filter.cpp
${toolkit_src_dir}/text/shaper.cpp
${toolkit_src_dir}/text/hyphenator.cpp
${toolkit_src_dir}/text/text-enumerations-impl.cpp
- ${toolkit_src_dir}/text/text-controller.cpp
- ${toolkit_src_dir}/text/text-controller-background-actor.cpp
- ${toolkit_src_dir}/text/text-controller-event-handler.cpp
- ${toolkit_src_dir}/text/text-controller-impl.cpp
- ${toolkit_src_dir}/text/text-controller-impl-data-clearer.cpp
- ${toolkit_src_dir}/text/text-controller-impl-event-handler.cpp
- ${toolkit_src_dir}/text/text-controller-impl-model-updater.cpp
- ${toolkit_src_dir}/text/text-controller-input-font-handler.cpp
- ${toolkit_src_dir}/text/text-controller-input-properties.cpp
- ${toolkit_src_dir}/text/text-controller-placeholder-handler.cpp
- ${toolkit_src_dir}/text/text-controller-relayouter.cpp
- ${toolkit_src_dir}/text/text-controller-text-updater.cpp
${toolkit_src_dir}/text/text-effects-style.cpp
${toolkit_src_dir}/text/text-font-style.cpp
${toolkit_src_dir}/text/text-io.cpp
${toolkit_src_dir}/text/text-view-interface.cpp
${toolkit_src_dir}/text/visual-model-impl.cpp
${toolkit_src_dir}/text/decorator/text-decorator.cpp
+ ${toolkit_src_dir}/text/controller/text-controller.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-background-actor.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-event-handler.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-impl.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-impl-data-clearer.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-impl-event-handler.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-impl-model-updater.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-input-font-handler.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-input-properties.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-placeholder-handler.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-relayouter.cpp
+ ${toolkit_src_dir}/text/controller/text-controller-text-updater.cpp
${toolkit_src_dir}/text/layouts/layout-engine-helper-functions.cpp
${toolkit_src_dir}/text/layouts/layout-engine.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-color.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-embedded-item.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-anchor.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-font.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-background.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-paragraph.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-span.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-strikethrough.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-underline.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-character-spacing.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-helper-functions.cpp
+ ${toolkit_src_dir}/text/markup-processor/markup-processor-attribute-helper-functions.cpp
${toolkit_src_dir}/text/multi-language-helper-functions.cpp
${toolkit_src_dir}/text/multi-language-support-impl.cpp
${toolkit_src_dir}/text/rendering/text-backend.cpp
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+// HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-background-actor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
+#include <dali-toolkit/internal/text/text-view.h>
+
+namespace Dali::Toolkit::Text
+{
+namespace
+{
+struct BackgroundVertex
+{
+ Vector2 mPosition; ///< Vertex posiiton
+ Vector4 mColor; ///< Vertex color
+};
+
+struct BackgroundMesh
+{
+ Vector<BackgroundVertex> mVertices; ///< container of vertices
+ Vector<unsigned short> mIndices; ///< container of indices
+};
+} // unnamed namespace
+
+Length CalculateBackgroundLineHeight(LineRun lineRun)
+{
+ Length height = lineRun.ascender + -(lineRun.descender);
+
+ if(lineRun.lineSpacing > 0)
+ {
+ height += lineRun.lineSpacing;
+ }
+
+ return height;
+}
+
+Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground)
+{
+ // NOTE: Currently we only support background color for left-to-right text.
+
+ Actor actor;
+
+ Length numberOfGlyphs = textView.GetNumberOfGlyphs();
+ if(numberOfGlyphs > 0u)
+ {
+ Vector<GlyphInfo> glyphs;
+ glyphs.Resize(numberOfGlyphs);
+
+ Vector<Vector2> positions;
+ positions.Resize(numberOfGlyphs);
+
+ // Get the line where the glyphs are laid-out.
+ const LineRun* lineRun = textVisualModel->mLines.Begin();
+ float alignmentOffset = lineRun->alignmentOffset;
+ numberOfGlyphs = textView.GetGlyphs(glyphs.Begin(),
+ positions.Begin(),
+ alignmentOffset,
+ 0u,
+ numberOfGlyphs);
+
+ glyphs.Resize(numberOfGlyphs);
+ positions.Resize(numberOfGlyphs);
+
+ const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+ const Vector2* const positionsBuffer = positions.Begin();
+
+ BackgroundMesh mesh;
+ mesh.mVertices.Reserve(4u * glyphs.Size());
+ mesh.mIndices.Reserve(6u * glyphs.Size());
+
+ const Vector2 textSize = textView.GetLayoutSize();
+
+ const float offsetX = alignmentOffset + textSize.width * 0.5f;
+ const float offsetY = textSize.height * 0.5f;
+
+ const Vector4* const backgroundColorsBuffer = textView.GetBackgroundColors();
+ const ColorIndex* const backgroundColorIndicesBuffer = textView.GetBackgroundColorIndices();
+ const Vector4& defaultBackgroundColor = textVisualModel->IsBackgroundEnabled() ? textVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
+ const float modelCharacterSpacing = textVisualModel->GetCharacterSpacing();
+ Vector<CharacterIndex>& glyphToCharacterMap = textVisualModel->mGlyphsToCharacters;
+ const CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+ float calculatedAdvance = 0.f;
+
+ // Get the character-spacing runs.
+ const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = textVisualModel->GetCharacterSpacingGlyphRuns();
+
+ Vector4 quad;
+ uint32_t numberOfQuads = 0u;
+ Length yLineOffset = 0;
+ Length prevLineIndex = 0;
+ LineIndex lineIndex;
+
+ for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
+ {
+ const GlyphInfo& glyph = *(glyphsBuffer + i);
+
+ // Get the background color of the character.
+ // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
+ const bool isMarkupBackground = textView.IsMarkupBackgroundColorSet();
+ const ColorIndex backgroundColorIndex = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
+ const bool isDefaultBackgroundColor = (0u == backgroundColorIndex);
+ const Vector4& backgroundColor = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+
+ lineIndex = textVisualModel->GetLineOfGlyph(i);
+ Length lineHeight = CalculateBackgroundLineHeight(lineRun[lineIndex]);
+
+ if(lineIndex != prevLineIndex)
+ {
+ yLineOffset += CalculateBackgroundLineHeight(lineRun[prevLineIndex]);
+
+ if(lineRun[prevLineIndex].lineSpacing < 0)
+ {
+ yLineOffset += lineRun[prevLineIndex].lineSpacing;
+ }
+ }
+
+ // Only create quads for glyphs with a background color
+ if(backgroundColor != Color::TRANSPARENT)
+ {
+ const float characterSpacing = GetGlyphCharacterSpacing(i, characterSpacingGlyphRuns, modelCharacterSpacing);
+
+ const Vector2 position = *(positionsBuffer + i);
+ calculatedAdvance = GetCalculatedAdvance(*(textLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + i))), characterSpacing, glyph.advance);
+
+ if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
+ {
+ quad.x = position.x;
+ quad.y = yLineOffset;
+ quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
+ quad.w = lineHeight;
+ }
+ else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
+ {
+ quad.x = position.x;
+ quad.y = yLineOffset;
+ quad.z = quad.x - glyph.xBearing + calculatedAdvance;
+ quad.w = quad.y + lineHeight;
+ }
+ else if(i == glyphSize - 1u) // The last glyph in the whole text
+ {
+ quad.x = position.x - glyph.xBearing;
+ quad.y = yLineOffset;
+ quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
+ quad.w = quad.y + lineHeight;
+ }
+ else // The glyph in the middle of the text
+ {
+ quad.x = position.x - glyph.xBearing;
+ quad.y = yLineOffset;
+ quad.z = quad.x + calculatedAdvance;
+ quad.w = quad.y + lineHeight;
+ }
+
+ BackgroundVertex vertex;
+
+ // Top left
+ vertex.mPosition.x = quad.x - offsetX;
+ vertex.mPosition.y = quad.y - offsetY;
+ vertex.mColor = backgroundColor;
+ mesh.mVertices.PushBack(vertex);
+
+ // Top right
+ vertex.mPosition.x = quad.z - offsetX;
+ vertex.mPosition.y = quad.y - offsetY;
+ vertex.mColor = backgroundColor;
+ mesh.mVertices.PushBack(vertex);
+
+ // Bottom left
+ vertex.mPosition.x = quad.x - offsetX;
+ vertex.mPosition.y = quad.w - offsetY;
+ vertex.mColor = backgroundColor;
+ mesh.mVertices.PushBack(vertex);
+
+ // Bottom right
+ vertex.mPosition.x = quad.z - offsetX;
+ vertex.mPosition.y = quad.w - offsetY;
+ vertex.mColor = backgroundColor;
+ mesh.mVertices.PushBack(vertex);
+
+ // Six indices in counter clockwise winding
+ mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
+ mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
+ mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
+ mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
+ mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
+ mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
+
+ numberOfQuads++;
+ }
+
+ if(lineIndex != prevLineIndex)
+ {
+ prevLineIndex = lineIndex;
+ }
+ }
+
+ // Only create the background actor if there are glyphs with background color
+ if(mesh.mVertices.Count() > 0u)
+ {
+ Property::Map quadVertexFormat;
+ quadVertexFormat["aPosition"] = Property::VECTOR2;
+ quadVertexFormat["aColor"] = Property::VECTOR4;
+
+ VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
+ quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
+
+ Geometry quadGeometry = Geometry::New();
+ quadGeometry.AddVertexBuffer(quadVertices);
+ quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
+
+ if(!textShaderBackground)
+ {
+ textShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
+ }
+
+ Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, textShaderBackground);
+ renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
+ renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
+
+ actor = Actor::New();
+ actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
+ actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ actor.SetProperty(Actor::Property::SIZE, textSize);
+ actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
+ actor.AddRenderer(renderer);
+ }
+ }
+
+ return actor;
+}
+
+} // namespace Dali::Toolkit::Text
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_BACKGROUND_ACTOR_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_BACKGROUND_ACTOR_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
+
+namespace Dali::Toolkit::Text
+{
+class View;
+
+/**
+ * @brief Create an actor that renders the text background color
+ *
+ * @param[in] textView The text view.
+ * @param[in] textVisualModel The text visual model.
+ * @param[in] textLogicalModel The text logical model.
+ * @param[in] textShaderBackground The text shader for background.
+ *
+ * @return the created actor or an empty handle if no background color needs to be rendered.
+ */
+Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground);
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_BACKGROUND_ACTOR_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const std::string KEY_C_NAME = "c";
+const std::string KEY_V_NAME = "v";
+const std::string KEY_X_NAME = "x";
+const std::string KEY_A_NAME = "a";
+const std::string KEY_INSERT_NAME = "Insert";
+
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void Controller::EventHandler::KeyboardFocusGainEvent(Controller& controller)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected KeyboardFocusGainEvent");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if((EventData::INACTIVE == controller.mImpl->mEventData->mState) ||
+ (EventData::INTERRUPTED == controller.mImpl->mEventData->mState))
+ {
+ controller.mImpl->ChangeState(EventData::EDITING);
+ controller.mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
+ controller.mImpl->mEventData->mUpdateInputStyle = true;
+ controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ controller.mImpl->NotifyInputMethodContextMultiLineStatus();
+ if(controller.mImpl->IsShowingPlaceholderText())
+ {
+ // Show alternative placeholder-text when editing
+ PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
+ }
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+void Controller::EventHandler::KeyboardFocusLostEvent(Controller& controller)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected KeyboardFocusLostEvent");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if(EventData::INTERRUPTED != controller.mImpl->mEventData->mState)
+ {
+ // Init selection position
+ if(controller.mImpl->mEventData->mState == EventData::SELECTING)
+ {
+ uint32_t oldStart, oldEnd;
+ oldStart = controller.mImpl->mEventData->mLeftSelectionPosition;
+ oldEnd = controller.mImpl->mEventData->mRightSelectionPosition;
+
+ controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+ controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+
+ if(controller.mImpl->mSelectableControlInterface != nullptr)
+ {
+ controller.mImpl->mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, controller.mImpl->mEventData->mPrimaryCursorPosition, controller.mImpl->mEventData->mPrimaryCursorPosition);
+ }
+ }
+
+ controller.mImpl->ChangeState(EventData::INACTIVE);
+
+ if(!controller.mImpl->IsShowingRealText())
+ {
+ // Revert to regular placeholder-text when not editing
+ PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
+ }
+ }
+ }
+ controller.mImpl->RequestRelayout();
+}
+
+bool Controller::EventHandler::KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected KeyEvent");
+
+ bool textChanged = false;
+ bool relayoutNeeded = false;
+ bool isEditable = controller.IsEditable() && controller.IsUserInteractionEnabled();
+
+ if((NULL != controller.mImpl->mEventData) &&
+ (keyEvent.GetState() == KeyEvent::DOWN))
+ {
+ int keyCode = keyEvent.GetKeyCode();
+ const std::string& keyString = keyEvent.GetKeyString();
+ const std::string keyName = keyEvent.GetKeyName();
+ // Key will produce same logical-key value when ctrl
+ // is down, regardless of language layout
+ const std::string logicalKey = keyEvent.GetLogicalKey();
+
+ const bool isNullKey = (0 == keyCode) && (keyString.empty());
+
+ // Pre-process to separate modifying events from non-modifying input events.
+ if(isNullKey)
+ {
+ // In some platforms arrive key events with no key code.
+ // Do nothing.
+ return false;
+ }
+ else if(Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode)
+ {
+ // Do nothing
+ return false;
+ }
+ else if((Dali::DALI_KEY_CURSOR_LEFT == keyCode) ||
+ (Dali::DALI_KEY_CURSOR_RIGHT == keyCode) ||
+ (Dali::DALI_KEY_CURSOR_UP == keyCode) ||
+ (Dali::DALI_KEY_CURSOR_DOWN == keyCode))
+ {
+ // If don't have any text, do nothing.
+ if(!controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters || !isEditable)
+ {
+ return false;
+ }
+
+ uint32_t cursorPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+ uint32_t numberOfCharacters = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ uint32_t cursorLine = controller.mImpl->mModel->mVisualModel->GetLineOfCharacter(cursorPosition);
+ uint32_t numberOfLines = controller.mImpl->mModel->GetNumberOfLines();
+
+ // Logic to determine whether this text control will lose focus or not.
+ if((Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier()) ||
+ (Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier()) ||
+ (Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines - 1) ||
+ (Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine - 1 == numberOfLines - 1) ||
+ (Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0) ||
+ (Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1))
+ {
+ // Release the active highlight.
+ if(controller.mImpl->mEventData->mState == EventData::SELECTING)
+ {
+ uint32_t oldStart, oldEnd;
+ oldStart = controller.mImpl->mEventData->mLeftSelectionPosition;
+ oldEnd = controller.mImpl->mEventData->mRightSelectionPosition;
+
+ controller.mImpl->ChangeState(EventData::EDITING);
+
+ // Update selection position.
+ controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+ controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+ controller.mImpl->mEventData->mUpdateCursorPosition = true;
+
+ if(controller.mImpl->mSelectableControlInterface != nullptr)
+ {
+ controller.mImpl->mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, controller.mImpl->mEventData->mLeftSelectionPosition, controller.mImpl->mEventData->mRightSelectionPosition);
+ }
+
+ controller.mImpl->RequestRelayout();
+ }
+ return false;
+ }
+
+ controller.mImpl->mEventData->mCheckScrollAmount = true;
+ Event event(Event::CURSOR_KEY_EVENT);
+ event.p1.mInt = keyCode;
+ event.p2.mBool = keyEvent.IsShiftModifier();
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+
+ // Will request for relayout.
+ relayoutNeeded = true;
+ }
+ else if(Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode)
+ {
+ // Left or Right Control key event is received before Ctrl-C/V/X key event is received
+ // If not handle it here, any selected text will be deleted
+
+ // Do nothing
+ return false;
+ }
+ else if(keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier() && isEditable)
+ {
+ bool consumed = false;
+ if(keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME || logicalKey == KEY_C_NAME || logicalKey == KEY_INSERT_NAME)
+ {
+ // Ctrl-C or Ctrl+Insert to copy the selected text
+ controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::COPY);
+ consumed = true;
+ }
+ else if(keyName == KEY_V_NAME || logicalKey == KEY_V_NAME)
+ {
+ // Ctrl-V to paste the copied text
+ controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::PASTE);
+ consumed = true;
+ }
+ else if(keyName == KEY_X_NAME || logicalKey == KEY_X_NAME)
+ {
+ // Ctrl-X to cut the selected text
+ controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::CUT);
+ consumed = true;
+ }
+ else if(keyName == KEY_A_NAME || logicalKey == KEY_A_NAME)
+ {
+ // Ctrl-A to select All the text
+ controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::SELECT_ALL);
+ consumed = true;
+ }
+ return consumed;
+ }
+ else if((Dali::DALI_KEY_BACKSPACE == keyCode) ||
+ (Dali::DevelKey::DALI_KEY_DELETE == keyCode))
+ {
+ textChanged = DeleteEvent(controller, keyCode);
+
+ // Will request for relayout.
+ relayoutNeeded = true;
+ }
+ else if(IsKey(keyEvent, Dali::DALI_KEY_POWER) ||
+ IsKey(keyEvent, Dali::DALI_KEY_MENU) ||
+ IsKey(keyEvent, Dali::DALI_KEY_HOME))
+ {
+ // Power key/Menu/Home key behaviour does not allow edit mode to resume.
+ controller.mImpl->ChangeState(EventData::INACTIVE);
+
+ // Will request for relayout.
+ relayoutNeeded = true;
+
+ // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
+ }
+ else if((Dali::DALI_KEY_SHIFT_LEFT == keyCode) || (Dali::DALI_KEY_SHIFT_RIGHT == keyCode))
+ {
+ // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled
+ // and a character is typed after the type of a upper case latin character.
+
+ // Do nothing.
+ return false;
+ }
+ else if((Dali::DALI_KEY_VOLUME_UP == keyCode) || (Dali::DALI_KEY_VOLUME_DOWN == keyCode))
+ {
+ // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
+ // Do nothing.
+ return false;
+ }
+ else
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", &controller, keyString.c_str());
+ if(!isEditable) return false;
+
+ std::string refinedKey = keyString;
+ if(controller.mImpl->mInputFilter != NULL && !refinedKey.empty())
+ {
+ bool accepted = false;
+ bool rejected = false;
+ accepted = controller.mImpl->mInputFilter->Contains(Toolkit::InputFilter::Property::ACCEPTED, keyString);
+ rejected = controller.mImpl->mInputFilter->Contains(Toolkit::InputFilter::Property::REJECTED, keyString);
+
+ if(!accepted)
+ {
+ // The filtered key is set to empty.
+ refinedKey = "";
+ // Signal emits when the character to be inserted is filtered by the accepted filter.
+ controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::ACCEPTED);
+ }
+ if(rejected)
+ {
+ // The filtered key is set to empty.
+ refinedKey = "";
+ // Signal emits when the character to be inserted is filtered by the rejected filter.
+ controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::REJECTED);
+ }
+ }
+
+ if(!refinedKey.empty())
+ {
+ // InputMethodContext is no longer handling key-events
+ controller.mImpl->ClearPreEditFlag();
+
+ TextUpdater::InsertText(controller, refinedKey, COMMIT);
+
+ textChanged = true;
+
+ // Will request for relayout.
+ relayoutNeeded = true;
+ }
+ }
+
+ if((controller.mImpl->mEventData->mState != EventData::INTERRUPTED) &&
+ (controller.mImpl->mEventData->mState != EventData::INACTIVE) &&
+ (!isNullKey) &&
+ (Dali::DALI_KEY_SHIFT_LEFT != keyCode) &&
+ (Dali::DALI_KEY_SHIFT_RIGHT != keyCode) &&
+ (Dali::DALI_KEY_VOLUME_UP != keyCode) &&
+ (Dali::DALI_KEY_VOLUME_DOWN != keyCode))
+ {
+ // Should not change the state if the key is the shift send by the InputMethodContext.
+ // Otherwise, when the state is SELECTING the text controller can't send the right
+ // surrounding info to the InputMethodContext.
+ controller.mImpl->ChangeState(EventData::EDITING);
+
+ // Will request for relayout.
+ relayoutNeeded = true;
+ }
+
+ if(relayoutNeeded)
+ {
+ controller.mImpl->RequestRelayout();
+ }
+ }
+ else if((NULL != controller.mImpl->mEventData) && (keyEvent.GetState() == KeyEvent::UP))
+ {
+ // Handles specific keys that require event propagation.
+ if(Dali::DALI_KEY_BACK == keyEvent.GetKeyCode())
+ {
+ // Do nothing
+ return false;
+ }
+ }
+
+ if(textChanged &&
+ (NULL != controller.mImpl->mEditableControlInterface))
+ {
+ // Do this last since it provides callbacks into application code
+ controller.mImpl->mEditableControlInterface->TextChanged(false);
+ }
+
+ return true;
+}
+
+void Controller::EventHandler::AnchorEvent(Controller& controller, float x, float y)
+{
+ if(!controller.mImpl->mMarkupProcessorEnabled ||
+ !controller.mImpl->mModel->mLogicalModel->mAnchors.Count() ||
+ !controller.mImpl->IsShowingRealText())
+ {
+ return;
+ }
+
+ CharacterIndex cursorPosition = 0u;
+
+ // Convert from control's coords to text's coords.
+ const float xPosition = x - controller.mImpl->mModel->mScrollPosition.x;
+ const float yPosition = y - controller.mImpl->mModel->mScrollPosition.y;
+
+ // Whether to touch point hits on a glyph.
+ bool matchedCharacter = false;
+ cursorPosition = Text::GetClosestCursorIndex(controller.mImpl->mModel->mVisualModel,
+ controller.mImpl->mModel->mLogicalModel,
+ controller.mImpl->mMetrics,
+ xPosition,
+ yPosition,
+ CharacterHitTest::TAP,
+ matchedCharacter);
+
+ for(const auto& anchor : controller.mImpl->mModel->mLogicalModel->mAnchors)
+ {
+ // Anchor clicked if the calculated cursor position is within the range of anchor.
+ if(cursorPosition >= anchor.startIndex && cursorPosition < anchor.endIndex)
+ {
+ if(controller.mImpl->mAnchorControlInterface && anchor.href)
+ {
+ std::string href(anchor.href);
+ controller.mImpl->mAnchorControlInterface->AnchorClicked(href);
+ break;
+ }
+ }
+ }
+}
+
+void Controller::EventHandler::TapEvent(Controller& controller, unsigned int tapCount, float x, float y)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected TapEvent");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "TapEvent state:%d \n", controller.mImpl->mEventData->mState);
+ EventData::State state(controller.mImpl->mEventData->mState);
+ bool relayoutNeeded(false); // to avoid unnecessary relayouts when tapping an empty text-field
+
+ if(controller.mImpl->IsClipboardVisible())
+ {
+ if(EventData::INACTIVE == state || EventData::EDITING == state)
+ {
+ controller.mImpl->ChangeState(EventData::EDITING_WITH_GRAB_HANDLE);
+ }
+ relayoutNeeded = true;
+ }
+ else if(1u == tapCount)
+ {
+ if(EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state)
+ {
+ controller.mImpl->ChangeState(EventData::EDITING_WITH_GRAB_HANDLE); // If Popup shown hide it here so can be shown again if required.
+ }
+
+ if(controller.mImpl->IsShowingRealText() && (EventData::INACTIVE != state))
+ {
+ controller.mImpl->ChangeState(EventData::EDITING_WITH_GRAB_HANDLE);
+ relayoutNeeded = true;
+ }
+ else
+ {
+ if(controller.mImpl->IsShowingPlaceholderText() && !controller.mImpl->IsFocusedPlaceholderAvailable())
+ {
+ // Hide placeholder text
+ TextUpdater::ResetText(controller);
+ }
+
+ if(EventData::INACTIVE == state)
+ {
+ controller.mImpl->ChangeState(EventData::EDITING);
+ }
+ else if(!controller.mImpl->IsClipboardEmpty())
+ {
+ controller.mImpl->ChangeState(EventData::EDITING_WITH_POPUP);
+ }
+ relayoutNeeded = true;
+ }
+ }
+ else if(2u == tapCount)
+ {
+ if(controller.mImpl->mEventData->mSelectionEnabled &&
+ controller.mImpl->IsShowingRealText())
+ {
+ relayoutNeeded = true;
+ controller.mImpl->mEventData->mIsLeftHandleSelected = true;
+ controller.mImpl->mEventData->mIsRightHandleSelected = true;
+ }
+ }
+
+ // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
+ if(relayoutNeeded)
+ {
+ Event event(Event::TAP_EVENT);
+ event.p1.mUint = tapCount;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+
+ controller.mImpl->RequestRelayout();
+ }
+ }
+
+ // Reset keyboard as tap event has occurred.
+ controller.mImpl->ResetInputMethodContext();
+}
+
+void Controller::EventHandler::PanEvent(Controller& controller, GestureState state, const Vector2& displacement)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected PanEvent");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ Event event(Event::PAN_EVENT);
+ event.p1.mInt = static_cast<int>(state);
+ event.p2.mFloat = displacement.x;
+ event.p3.mFloat = displacement.y;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+void Controller::EventHandler::LongPressEvent(Controller& controller, GestureState state, float x, float y)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected LongPressEvent");
+
+ if((state == GestureState::STARTED) &&
+ (NULL != controller.mImpl->mEventData))
+ {
+ // The 1st long-press on inactive text-field is treated as tap
+ if(EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ controller.mImpl->ChangeState(EventData::EDITING);
+
+ Event event(Event::TAP_EVENT);
+ event.p1.mUint = 1;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+
+ controller.mImpl->RequestRelayout();
+ }
+ else if(!controller.mImpl->IsShowingRealText())
+ {
+ Event event(Event::LONG_PRESS_EVENT);
+ event.p1.mInt = static_cast<int>(state);
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ controller.mImpl->RequestRelayout();
+ }
+ else if(!controller.mImpl->IsClipboardVisible())
+ {
+ // Reset the InputMethodContext to commit the pre-edit before selecting the text.
+ controller.mImpl->ResetInputMethodContext();
+
+ Event event(Event::LONG_PRESS_EVENT);
+ event.p1.mInt = static_cast<int>(state);
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ controller.mImpl->RequestRelayout();
+
+ controller.mImpl->mEventData->mIsLeftHandleSelected = true;
+ controller.mImpl->mEventData->mIsRightHandleSelected = true;
+ }
+ }
+}
+
+void Controller::EventHandler::SelectEvent(Controller& controller, float x, float y, SelectionType selectType)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SelectEvent\n");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if(selectType == SelectionType::ALL)
+ {
+ Event event(Event::SELECT_ALL);
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ }
+ else if(selectType == SelectionType::NONE)
+ {
+ Event event(Event::SELECT_NONE);
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ }
+ else
+ {
+ Event event(Event::SELECT);
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ }
+
+ controller.mImpl->mEventData->mCheckScrollAmount = true;
+ controller.mImpl->mEventData->mIsLeftHandleSelected = true;
+ controller.mImpl->mEventData->mIsRightHandleSelected = true;
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+void Controller::EventHandler::SelectEvent(Controller& controller, const uint32_t start, const uint32_t end, SelectionType selectType)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SelectEvent\n");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if(selectType == SelectionType::RANGE)
+ {
+ Event event(Event::SELECT_RANGE);
+ event.p2.mUint = start;
+ event.p3.mUint = end;
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ }
+
+ controller.mImpl->mEventData->mCheckScrollAmount = true;
+ controller.mImpl->mEventData->mIsLeftHandleSelected = true;
+ controller.mImpl->mEventData->mIsRightHandleSelected = true;
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+void Controller::EventHandler::ProcessModifyEvents(Controller& controller)
+{
+ Vector<ModifyEvent>& events = controller.mImpl->mModifyEvents;
+
+ if(0u == events.Count())
+ {
+ // Nothing to do.
+ return;
+ }
+
+ for(Vector<ModifyEvent>::ConstIterator it = events.Begin(),
+ endIt = events.End();
+ it != endIt;
+ ++it)
+ {
+ const ModifyEvent& event = *it;
+
+ if(ModifyEvent::TEXT_REPLACED == event.type)
+ {
+ // A (single) replace event should come first, otherwise we wasted time processing NOOP events
+ DALI_ASSERT_DEBUG(it == events.Begin() && "Unexpected TEXT_REPLACED event");
+
+ TextReplacedEvent(controller);
+ }
+ else if(ModifyEvent::TEXT_INSERTED == event.type)
+ {
+ TextInsertedEvent(controller);
+ }
+ else if(ModifyEvent::TEXT_DELETED == event.type)
+ {
+ // Placeholder-text cannot be deleted
+ if(!controller.mImpl->IsShowingPlaceholderText())
+ {
+ TextDeletedEvent(controller);
+ }
+ }
+ }
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ uint32_t oldStart, oldEnd;
+ oldStart = controller.mImpl->mEventData->mLeftSelectionPosition;
+ oldEnd = controller.mImpl->mEventData->mRightSelectionPosition;
+
+ // When the text is being modified, delay cursor blinking
+ controller.mImpl->mEventData->mDecorator->DelayCursorBlink();
+
+ // Update selection position after modifying the text
+ controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+ controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
+
+ if(controller.mImpl->mSelectableControlInterface != nullptr && controller.mImpl->mEventData->mState == EventData::SELECTING)
+ {
+ controller.mImpl->mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, controller.mImpl->mEventData->mLeftSelectionPosition, controller.mImpl->mEventData->mRightSelectionPosition);
+ }
+ }
+
+ // DISCARD temporary text
+ events.Clear();
+}
+
+void Controller::EventHandler::TextReplacedEvent(Controller& controller)
+{
+ // The natural size needs to be re-calculated.
+ controller.mImpl->mRecalculateNaturalSize = true;
+
+ // The text direction needs to be updated.
+ controller.mImpl->mUpdateTextDirection = true;
+
+ // Apply modifications to the model
+ controller.mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+void Controller::EventHandler::TextInsertedEvent(Controller& controller)
+{
+ DALI_ASSERT_DEBUG(NULL != controller.mImpl->mEventData && "Unexpected TextInsertedEvent");
+
+ if(NULL == controller.mImpl->mEventData)
+ {
+ return;
+ }
+
+ controller.mImpl->mEventData->mCheckScrollAmount = true;
+
+ // The natural size needs to be re-calculated.
+ controller.mImpl->mRecalculateNaturalSize = true;
+
+ // The text direction needs to be updated.
+ controller.mImpl->mUpdateTextDirection = true;
+
+ // Apply modifications to the model; TODO - Optimize this
+ controller.mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+void Controller::EventHandler::TextDeletedEvent(Controller& controller)
+{
+ DALI_ASSERT_DEBUG(NULL != controller.mImpl->mEventData && "Unexpected TextDeletedEvent");
+
+ if(NULL == controller.mImpl->mEventData)
+ {
+ return;
+ }
+
+ if(!controller.IsEditable()) return;
+
+ controller.mImpl->mEventData->mCheckScrollAmount = true;
+
+ // The natural size needs to be re-calculated.
+ controller.mImpl->mRecalculateNaturalSize = true;
+
+ // The text direction needs to be updated.
+ controller.mImpl->mUpdateTextDirection = true;
+
+ // Apply modifications to the model; TODO - Optimize this
+ controller.mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+bool Controller::EventHandler::DeleteEvent(Controller& controller, int keyCode)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", &controller, keyCode);
+
+ bool removed = false;
+
+ if(NULL == controller.mImpl->mEventData)
+ {
+ return removed;
+ }
+
+ if(!controller.IsEditable()) return false;
+
+ // InputMethodContext is no longer handling key-events
+ controller.mImpl->ClearPreEditFlag();
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ removed = TextUpdater::RemoveSelectedText(controller);
+ }
+ else if((controller.mImpl->mEventData->mPrimaryCursorPosition > 0) && (keyCode == Dali::DALI_KEY_BACKSPACE))
+ {
+ // Remove the character before the current cursor position
+ removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE);
+ }
+ else if((controller.mImpl->mEventData->mPrimaryCursorPosition < controller.mImpl->mModel->mLogicalModel->mText.Count()) &&
+ (keyCode == Dali::DevelKey::DALI_KEY_DELETE))
+ {
+ // Remove the character after the current cursor position
+ removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE);
+ }
+
+ if(removed)
+ {
+ if((0u != controller.mImpl->mModel->mLogicalModel->mText.Count()) ||
+ !controller.mImpl->IsPlaceholderAvailable())
+ {
+ controller.mImpl->QueueModifyEvent(ModifyEvent::TEXT_DELETED);
+ }
+ else
+ {
+ PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
+ }
+ controller.mImpl->mEventData->mUpdateCursorPosition = true;
+ controller.mImpl->mEventData->mScrollAfterDelete = true;
+ }
+
+ return removed;
+}
+
+InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextEvent(Controller& controller, InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
+{
+ // Whether the text needs to be relaid-out.
+ bool requestRelayout = false;
+
+ // Whether to retrieve the text and cursor position to be sent to the InputMethodContext.
+ bool retrieveText = false;
+ bool retrieveCursor = false;
+
+ switch(inputMethodContextEvent.eventName)
+ {
+ case InputMethodContext::COMMIT:
+ {
+ TextUpdater::InsertText(controller, inputMethodContextEvent.predictiveString, Text::Controller::COMMIT);
+ requestRelayout = true;
+ retrieveCursor = true;
+ break;
+ }
+ case InputMethodContext::PRE_EDIT:
+ {
+ TextUpdater::InsertText(controller, inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT);
+ requestRelayout = true;
+ retrieveCursor = true;
+ break;
+ }
+ case InputMethodContext::DELETE_SURROUNDING:
+ {
+ const bool textDeleted = TextUpdater::RemoveText(controller,
+ inputMethodContextEvent.cursorOffset,
+ inputMethodContextEvent.numberOfChars,
+ DONT_UPDATE_INPUT_STYLE);
+
+ if(textDeleted)
+ {
+ if((0u != controller.mImpl->mModel->mLogicalModel->mText.Count()) ||
+ !controller.mImpl->IsPlaceholderAvailable())
+ {
+ controller.mImpl->QueueModifyEvent(ModifyEvent::TEXT_DELETED);
+ }
+ else
+ {
+ PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
+ }
+ controller.mImpl->mEventData->mUpdateCursorPosition = true;
+ controller.mImpl->mEventData->mScrollAfterDelete = true;
+
+ requestRelayout = true;
+ }
+ break;
+ }
+ case InputMethodContext::GET_SURROUNDING:
+ {
+ retrieveText = true;
+ retrieveCursor = true;
+ break;
+ }
+ case InputMethodContext::PRIVATE_COMMAND:
+ {
+ // PRIVATECOMMAND event is just for getting the private command message
+ retrieveText = true;
+ retrieveCursor = true;
+ break;
+ }
+ case InputMethodContext::SELECTION_SET:
+ {
+ uint32_t start = static_cast<uint32_t>(inputMethodContextEvent.startIndex);
+ uint32_t end = static_cast<uint32_t>(inputMethodContextEvent.endIndex);
+ if(start == end)
+ {
+ controller.SetPrimaryCursorPosition(start, true);
+ }
+ else
+ {
+ controller.SelectText(start, end);
+ }
+
+ break;
+ }
+ case InputMethodContext::VOID:
+ {
+ // do nothing
+ break;
+ }
+ } // end switch
+
+ if(requestRelayout)
+ {
+ controller.mImpl->mOperationsPending = ALL_OPERATIONS;
+ controller.mImpl->RequestRelayout();
+ }
+
+ std::string text;
+ CharacterIndex cursorPosition = 0u;
+ Length numberOfWhiteSpaces = 0u;
+
+ if(retrieveCursor)
+ {
+ numberOfWhiteSpaces = controller.mImpl->GetNumberOfWhiteSpaces(0u);
+
+ cursorPosition = controller.mImpl->GetLogicalCursorPosition();
+
+ if(cursorPosition < numberOfWhiteSpaces)
+ {
+ cursorPosition = 0u;
+ }
+ else
+ {
+ cursorPosition -= numberOfWhiteSpaces;
+ }
+ }
+
+ if(retrieveText)
+ {
+ if(!controller.mImpl->IsShowingPlaceholderText())
+ {
+ // Retrieves the normal text string.
+ controller.mImpl->GetText(numberOfWhiteSpaces, text);
+ }
+ else
+ {
+ // When the current text is Placeholder Text, the surrounding text should be empty string.
+ // It means DALi should send empty string ("") to IME.
+ text = "";
+ }
+ }
+
+ InputMethodContext::CallbackData callbackData((retrieveText || retrieveCursor), cursorPosition, text, false);
+
+ if(requestRelayout &&
+ (NULL != controller.mImpl->mEditableControlInterface))
+ {
+ // Do this last since it provides callbacks into application code
+ controller.mImpl->mEditableControlInterface->TextChanged(false);
+ }
+
+ return callbackData;
+}
+
+void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller)
+{
+ // Retrieve the clipboard contents first
+ ClipboardEventNotifier notifier(ClipboardEventNotifier::Get());
+ std::string stringToPaste(notifier.GetContent());
+
+ // Commit the current pre-edit text; the contents of the clipboard should be appended
+ controller.mImpl->ResetInputMethodContext();
+
+ // Temporary disable hiding clipboard
+ controller.mImpl->SetClipboardHideEnable(false);
+
+ // Paste
+ TextUpdater::PasteText(controller, stringToPaste);
+
+ controller.mImpl->SetClipboardHideEnable(true);
+}
+
+void Controller::EventHandler::DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y)
+{
+ DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected DecorationEvent");
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ switch(handleType)
+ {
+ case GRAB_HANDLE:
+ {
+ Event event(Event::GRAB_HANDLE_EVENT);
+ event.p1.mUint = state;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ break;
+ }
+ case LEFT_SELECTION_HANDLE:
+ {
+ Event event(Event::LEFT_SELECTION_HANDLE_EVENT);
+ event.p1.mUint = state;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ break;
+ }
+ case RIGHT_SELECTION_HANDLE:
+ {
+ Event event(Event::RIGHT_SELECTION_HANDLE_EVENT);
+ event.p1.mUint = state;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+
+ controller.mImpl->mEventData->mEventQueue.push_back(event);
+ break;
+ }
+ case LEFT_SELECTION_HANDLE_MARKER:
+ case RIGHT_SELECTION_HANDLE_MARKER:
+ {
+ // Markers do not move the handles.
+ break;
+ }
+ case HANDLE_TYPE_COUNT:
+ {
+ DALI_ASSERT_DEBUG(!"Controller::HandleEvent. Unexpected handle type");
+ }
+ }
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+void Controller::EventHandler::TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button)
+{
+ if(NULL == controller.mImpl->mEventData)
+ {
+ return;
+ }
+
+ switch(button)
+ {
+ case Toolkit::TextSelectionPopup::CUT:
+ {
+ controller.CutText();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::COPY:
+ {
+ controller.CopyText();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::PASTE:
+ {
+ controller.PasteText();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::SELECT:
+ {
+ const Vector2& currentCursorPosition = controller.mImpl->mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
+
+ if(controller.mImpl->mEventData->mSelectionEnabled)
+ {
+ // Creates a SELECT event.
+ SelectEvent(controller, currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE);
+ }
+ break;
+ }
+ case Toolkit::TextSelectionPopup::SELECT_ALL:
+ {
+ // Creates a SELECT_ALL event
+ SelectEvent(controller, 0.f, 0.f, SelectionType::ALL);
+ break;
+ }
+ case Toolkit::TextSelectionPopup::CLIPBOARD:
+ {
+ controller.mImpl->ShowClipboard();
+ break;
+ }
+ case Toolkit::TextSelectionPopup::NONE:
+ {
+ // Nothing to do.
+ break;
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/public-api/events/gesture-enumerations.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Controller::EventHandler
+{
+ /// @copydoc Text::Controller::KeyboardFocusGainEvent
+ /// @param[in] controller A reference to the controller class
+ static void KeyboardFocusGainEvent(Controller& controller);
+
+ /// @copydoc Text::Controller::KeyboardFocusLostEvent
+ /// @param[in] controller A reference to the controller class
+ static void KeyboardFocusLostEvent(Controller& controller);
+
+ /// @copydoc Text::Controller::KeyEvent
+ /// @param[in] controller A reference to the controller class
+ static bool KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent);
+
+ /// @copydoc Text::Controller::AnchorEvent
+ /// @param[in] controller A reference to the controller class
+ static void AnchorEvent(Controller& controller, float x, float y);
+
+ /// @copydoc Text::Controller::TapEvent
+ /// @param[in] controller A reference to the controller class
+ static void TapEvent(Controller& controller, unsigned int tapCount, float x, float y);
+
+ /// @copydoc Text::Controller::PanEvent
+ /// @param[in] controller A reference to the controller class
+ static void PanEvent(Controller& controller, GestureState state, const Vector2& displacement);
+
+ /// @copydoc Text::Controller::LongPressEvent
+ /// @param[in] controller A reference to the controller class
+ static void LongPressEvent(Controller& controller, GestureState state, float x, float y);
+
+ /// @copydoc Text::Controller::SelectEvent
+ /// @param[in] controller A reference to the controller class
+ static void SelectEvent(Controller& controller, float x, float y, SelectionType selectType);
+
+ /**
+ * @brief Creates a selection event with a selection index.
+ *
+ * It could be called from the SelectText().
+ * The start and end parameters are passed through the event.
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] start The start selection position.
+ * @param[in] end The end selection position.
+ * @param[in] selection type like the range.
+ */
+ static void SelectEvent(Controller& controller, const uint32_t start, const uint32_t end, SelectionType selectType);
+
+ /**
+ * @brief Process queued events which modify the model.
+ * @param[in] controller A reference to the controller class
+ */
+ static void ProcessModifyEvents(Controller& controller);
+
+ /**
+ * @brief Used to process an event queued from SetText()
+ * @param[in] controller A reference to the controller class
+ */
+ static void TextReplacedEvent(Controller& controller);
+
+ /**
+ * @brief Used to process an event queued from key events etc.
+ * @param[in] controller A reference to the controller class
+ */
+ static void TextInsertedEvent(Controller& controller);
+
+ /**
+ * @brief Used to process an event queued from backspace key etc.
+ * @param[in] controller A reference to the controller class
+ */
+ static void TextDeletedEvent(Controller& controller);
+
+ /**
+ * @brief Helper to KeyEvent() to handle the backspace or delete key case.
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] keyCode The keycode for the key pressed
+ * @return True if a character was deleted.
+ */
+ static bool DeleteEvent(Controller& controller, int keyCode);
+
+ static InputMethodContext::CallbackData OnInputMethodContextEvent(Controller& controller,
+ InputMethodContext& inputMethodContext,
+ const InputMethodContext::EventData& inputMethodContextEvent);
+
+ static void PasteClipboardItemEvent(Controller& controller);
+ static void DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y);
+ static void TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button);
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-impl-data-clearer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+
+namespace Dali::Toolkit::Text
+{
+
+void ControllerImplDataClearer::ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations)
+{
+ ModelPtr& model = impl.mModel;
+
+ if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
+ {
+ model->mLogicalModel->mLineBreakInfo.Clear();
+ model->mLogicalModel->mParagraphInfo.Clear();
+ }
+
+ if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations))
+ {
+ model->mLogicalModel->mScriptRuns.Clear();
+ }
+
+ if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations))
+ {
+ model->mLogicalModel->mFontRuns.Clear();
+ }
+
+ if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count())
+ {
+ if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
+ {
+ model->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+ model->mLogicalModel->mCharacterDirections.Clear();
+ }
+
+ if(Controller::NO_OPERATION != (Controller::REORDER & operations))
+ {
+ // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+ for(Vector<BidirectionalLineInfoRun>::Iterator it = model->mLogicalModel->mBidirectionalLineInfo.Begin(),
+ endIt = model->mLogicalModel->mBidirectionalLineInfo.End();
+ it != endIt;
+ ++it)
+ {
+ BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+ free(bidiLineInfo.visualToLogicalMap);
+ bidiLineInfo.visualToLogicalMap = NULL;
+ }
+ model->mLogicalModel->mBidirectionalLineInfo.Clear();
+ }
+ }
+
+ if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
+ {
+ model->mVisualModel->mGlyphs.Clear();
+ model->mVisualModel->mGlyphsToCharacters.Clear();
+ model->mVisualModel->mCharactersToGlyph.Clear();
+ model->mVisualModel->mCharactersPerGlyph.Clear();
+ model->mVisualModel->mGlyphsPerCharacter.Clear();
+ model->mVisualModel->mGlyphPositions.Clear();
+ }
+
+ if(Controller::NO_OPERATION != (Controller::LAYOUT & operations))
+ {
+ model->mVisualModel->mLines.Clear();
+ }
+
+ if(Controller::NO_OPERATION != (Controller::COLOR & operations))
+ {
+ model->mVisualModel->mColorIndices.Clear();
+ model->mVisualModel->mBackgroundColorIndices.Clear();
+ }
+}
+
+void ControllerImplDataClearer::ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
+{
+ const CharacterIndex endIndexPlusOne = endIndex + 1u;
+ ModelPtr& model = impl.mModel;
+
+ if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
+ {
+ // Clear the line break info.
+ LineBreakInfo* lineBreakInfoBuffer = model->mLogicalModel->mLineBreakInfo.Begin();
+
+ model->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
+ lineBreakInfoBuffer + endIndexPlusOne);
+
+ // Clear the paragraphs.
+ ClearCharacterRuns(startIndex,
+ endIndex,
+ model->mLogicalModel->mParagraphInfo);
+ }
+
+ if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations))
+ {
+ // Clear the scripts.
+ ClearCharacterRuns(startIndex,
+ endIndex,
+ model->mLogicalModel->mScriptRuns);
+ }
+
+ if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations))
+ {
+ // Clear the fonts.
+ ClearCharacterRuns(startIndex,
+ endIndex,
+ model->mLogicalModel->mFontRuns);
+ }
+
+ if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count())
+ {
+ if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
+ {
+ // Clear the bidirectional paragraph info.
+ ClearCharacterRuns(startIndex,
+ endIndex,
+ model->mLogicalModel->mBidirectionalParagraphInfo);
+
+ // Clear the character's directions.
+ CharacterDirection* characterDirectionsBuffer = model->mLogicalModel->mCharacterDirections.Begin();
+
+ model->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
+ characterDirectionsBuffer + endIndexPlusOne);
+ }
+
+ if(Controller::NO_OPERATION != (Controller::REORDER & operations))
+ {
+ uint32_t startRemoveIndex = model->mLogicalModel->mBidirectionalLineInfo.Count();
+ uint32_t endRemoveIndex = startRemoveIndex;
+ ClearCharacterRuns(startIndex,
+ endIndex,
+ model->mLogicalModel->mBidirectionalLineInfo,
+ startRemoveIndex,
+ endRemoveIndex);
+
+ BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = model->mLogicalModel->mBidirectionalLineInfo.Begin();
+
+ // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+ for(Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
+ endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
+ it != endIt;
+ ++it)
+ {
+ BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+ free(bidiLineInfo.visualToLogicalMap);
+ bidiLineInfo.visualToLogicalMap = NULL;
+ }
+
+ model->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
+ bidirectionalLineInfoBuffer + endRemoveIndex);
+ }
+ }
+}
+
+void ControllerImplDataClearer::ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
+{
+ const CharacterIndex endIndexPlusOne = endIndex + 1u;
+ const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+ ModelPtr& model = impl.mModel;
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+
+ // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+ GlyphIndex* charactersToGlyphBuffer = model->mVisualModel->mCharactersToGlyph.Begin();
+ Length* glyphsPerCharacterBuffer = model->mVisualModel->mGlyphsPerCharacter.Begin();
+
+ const GlyphIndex endGlyphIndexPlusOne = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
+ const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - textUpdateInfo.mStartGlyphIndex;
+
+ if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
+ {
+ // Update the character to glyph indices.
+ for(Vector<GlyphIndex>::Iterator it = charactersToGlyphBuffer + endIndexPlusOne,
+ endIt = charactersToGlyphBuffer + model->mVisualModel->mCharactersToGlyph.Count();
+ it != endIt;
+ ++it)
+ {
+ CharacterIndex& index = *it;
+ index -= numberOfGlyphsRemoved;
+ }
+
+ // Clear the character to glyph conversion table.
+ model->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
+ charactersToGlyphBuffer + endIndexPlusOne);
+
+ // Clear the glyphs per character table.
+ model->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
+ glyphsPerCharacterBuffer + endIndexPlusOne);
+
+ // Clear the glyphs buffer.
+ GlyphInfo* glyphsBuffer = model->mVisualModel->mGlyphs.Begin();
+ model->mVisualModel->mGlyphs.Erase(glyphsBuffer + textUpdateInfo.mStartGlyphIndex,
+ glyphsBuffer + endGlyphIndexPlusOne);
+
+ CharacterIndex* glyphsToCharactersBuffer = model->mVisualModel->mGlyphsToCharacters.Begin();
+
+ // Update the glyph to character indices.
+ for(Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+ endIt = glyphsToCharactersBuffer + model->mVisualModel->mGlyphsToCharacters.Count();
+ it != endIt;
+ ++it)
+ {
+ CharacterIndex& index = *it;
+ index -= numberOfCharactersRemoved;
+ }
+
+ // Clear the glyphs to characters buffer.
+ model->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + textUpdateInfo.mStartGlyphIndex,
+ glyphsToCharactersBuffer + endGlyphIndexPlusOne);
+
+ // Clear the characters per glyph buffer.
+ Length* charactersPerGlyphBuffer = model->mVisualModel->mCharactersPerGlyph.Begin();
+ model->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + textUpdateInfo.mStartGlyphIndex,
+ charactersPerGlyphBuffer + endGlyphIndexPlusOne);
+
+ // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
+ if(0u != model->mVisualModel->mGlyphPositions.Count())
+ {
+ // Clear the positions buffer.
+ Vector2* positionsBuffer = model->mVisualModel->mGlyphPositions.Begin();
+ model->mVisualModel->mGlyphPositions.Erase(positionsBuffer + textUpdateInfo.mStartGlyphIndex,
+ positionsBuffer + endGlyphIndexPlusOne);
+ }
+ }
+
+ if(Controller::NO_OPERATION != (Controller::LAYOUT & operations))
+ {
+ // Clear the lines.
+ uint32_t startRemoveIndex = model->mVisualModel->mLines.Count();
+ uint32_t endRemoveIndex = startRemoveIndex;
+ ClearCharacterRuns(startIndex,
+ endIndex,
+ model->mVisualModel->mLines,
+ startRemoveIndex,
+ endRemoveIndex);
+
+ // Will update the glyph runs.
+ startRemoveIndex = model->mVisualModel->mLines.Count();
+ endRemoveIndex = startRemoveIndex;
+ ClearGlyphRuns(textUpdateInfo.mStartGlyphIndex,
+ endGlyphIndexPlusOne - 1u,
+ model->mVisualModel->mLines,
+ startRemoveIndex,
+ endRemoveIndex);
+
+ // Set the line index from where to insert the new laid-out lines.
+ textUpdateInfo.mStartLineIndex = startRemoveIndex;
+
+ LineRun* linesBuffer = model->mVisualModel->mLines.Begin();
+ model->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
+ linesBuffer + endRemoveIndex);
+ }
+
+ if(Controller::NO_OPERATION != (Controller::COLOR & operations))
+ {
+ if(0u != model->mVisualModel->mColorIndices.Count())
+ {
+ ColorIndex* colorIndexBuffer = model->mVisualModel->mColorIndices.Begin();
+ model->mVisualModel->mColorIndices.Erase(colorIndexBuffer + textUpdateInfo.mStartGlyphIndex,
+ colorIndexBuffer + endGlyphIndexPlusOne);
+ }
+
+ if(0u != model->mVisualModel->mBackgroundColorIndices.Count())
+ {
+ ColorIndex* backgroundColorIndexBuffer = model->mVisualModel->mBackgroundColorIndices.Begin();
+ model->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + textUpdateInfo.mStartGlyphIndex,
+ backgroundColorIndexBuffer + endGlyphIndexPlusOne);
+ }
+ }
+}
+
+void ControllerImplDataClearer::ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
+{
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+ if(textUpdateInfo.mClearAll ||
+ ((0u == startIndex) &&
+ (textUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
+ {
+ ClearFullModelData(impl, operations);
+ }
+ else
+ {
+ // Clear the model data related with characters.
+ ClearCharacterModelData(impl, startIndex, endIndex, operations);
+
+ // Clear the model data related with glyphs.
+ ClearGlyphModelData(impl, startIndex, endIndex, operations);
+ }
+
+ ModelPtr& model = impl.mModel;
+
+ // The estimated number of lines. Used to avoid reallocations when layouting.
+ textUpdateInfo.mEstimatedNumberOfLines = std::max(model->mVisualModel->mLines.Count(), model->mLogicalModel->mParagraphInfo.Count());
+
+ model->mVisualModel->ClearCaches();
+}
+
+} // namespace Dali::Toolkit::Text
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+
+namespace Dali::Toolkit::Text
+{
+
+/// Provides methods to clear some of the model data in the Text::Controller::Impl
+struct ControllerImplDataClearer
+{
+
+ /**
+ * @brief Helper to clear completely the parts of the model specified by the given @p operations.
+ *
+ * @note It never clears the text stored in utf32.
+ *
+ * @param[in] impl The text controller impl.
+ * @param[in] operations The operations required.
+ */
+ static void ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations);
+
+ /**
+ * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations.
+ *
+ * @note It never clears the text stored in utf32.
+ *
+ * @param[in] impl The text controller impl.
+ * @param[in] startIndex Index to the first character to be cleared.
+ * @param[in] endIndex Index to the last character to be cleared.
+ * @param[in] operations The operations required.
+ */
+ static void ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
+
+ /**
+ * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations.
+ *
+ * @note It never clears the text stored in utf32.
+ * @note Character indices are transformed to glyph indices.
+ *
+ * @param[in] impl The text controller impl.
+ * @param[in] startIndex Index to the first character to be cleared.
+ * @param[in] endIndex Index to the last character to be cleared.
+ * @param[in] operations The operations required.
+ */
+ static void ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
+
+ /**
+ * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
+ *
+ * @note It never clears the text stored in utf32.
+ *
+ * @param[in] impl The text controller impl.
+ * @param[in] startIndex Index to the first character to be cleared.
+ * @param[in] endIndex Index to the last character to be cleared.
+ * @param[in] operations The operations required.
+ */
+ static void ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
+};
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-impl-event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/adaptor-framework/key.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+
+using namespace Dali;
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+bool ControllerImplEventHandler::ProcessInputEvents(Controller::Impl& impl)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n");
+
+ EventData*& eventData = impl.mEventData;
+ if(NULL == eventData)
+ {
+ // Nothing to do if there is no text input.
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n");
+ return false;
+ }
+
+ unsigned int oldPos = eventData->mPrimaryCursorPosition;
+
+ if(eventData->mDecorator)
+ {
+ for(std::vector<Event>::iterator iter = eventData->mEventQueue.begin();
+ iter != eventData->mEventQueue.end();
+ ++iter)
+ {
+ switch(iter->type)
+ {
+ case Event::CURSOR_KEY_EVENT:
+ {
+ OnCursorKeyEvent(impl, *iter);
+ break;
+ }
+ case Event::TAP_EVENT:
+ {
+ OnTapEvent(impl, *iter);
+ break;
+ }
+ case Event::LONG_PRESS_EVENT:
+ {
+ OnLongPressEvent(impl, *iter);
+ break;
+ }
+ case Event::PAN_EVENT:
+ {
+ OnPanEvent(impl, *iter);
+ break;
+ }
+ case Event::GRAB_HANDLE_EVENT:
+ case Event::LEFT_SELECTION_HANDLE_EVENT:
+ case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
+ {
+ OnHandleEvent(impl, *iter);
+ break;
+ }
+ case Event::SELECT:
+ {
+ OnSelectEvent(impl, *iter);
+ break;
+ }
+ case Event::SELECT_ALL:
+ {
+ OnSelectAllEvent(impl);
+ break;
+ }
+ case Event::SELECT_NONE:
+ {
+ OnSelectNoneEvent(impl);
+ break;
+ }
+ case Event::SELECT_RANGE:
+ {
+ OnSelectRangeEvent(impl, *iter);
+ break;
+ }
+ }
+ }
+ }
+
+ if(eventData->mUpdateCursorPosition ||
+ eventData->mUpdateHighlightBox)
+ {
+ impl.NotifyInputMethodContext();
+ }
+
+ // The cursor must also be repositioned after inserts into the model
+ if(eventData->mUpdateCursorPosition)
+ {
+ // Updates the cursor position and scrolls the text to make it visible.
+ CursorInfo cursorInfo;
+
+ // Calculate the cursor position from the new cursor index.
+ impl.GetCursorPosition(eventData->mPrimaryCursorPosition, cursorInfo);
+
+ //only emit the event if the cursor is moved in current function.
+ if(nullptr != impl.mEditableControlInterface && eventData->mEventQueue.size() > 0)
+ {
+ impl.mEditableControlInterface->CursorPositionChanged(oldPos, eventData->mPrimaryCursorPosition);
+ }
+
+ if(eventData->mUpdateCursorHookPosition)
+ {
+ // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
+ eventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
+ eventData->mUpdateCursorHookPosition = false;
+ }
+
+ // Scroll first the text after delete ...
+ if(eventData->mScrollAfterDelete)
+ {
+ impl.ScrollTextToMatchCursor(cursorInfo);
+ }
+
+ // ... then, text can be scrolled to make the cursor visible.
+ if(eventData->mScrollAfterUpdatePosition)
+ {
+ const Vector2 currentCursorPosition(cursorInfo.primaryPosition.x, cursorInfo.lineOffset);
+ impl.ScrollToMakePositionVisible(currentCursorPosition, cursorInfo.lineHeight);
+ }
+ eventData->mScrollAfterUpdatePosition = false;
+ eventData->mScrollAfterDelete = false;
+
+ impl.UpdateCursorPosition(cursorInfo);
+
+ eventData->mDecoratorUpdated = true;
+ eventData->mUpdateCursorPosition = false;
+ eventData->mUpdateGrabHandlePosition = false;
+ }
+
+ if(eventData->mUpdateHighlightBox ||
+ eventData->mUpdateLeftSelectionPosition ||
+ eventData->mUpdateRightSelectionPosition)
+ {
+ CursorInfo leftHandleInfo;
+ CursorInfo rightHandleInfo;
+
+ if(eventData->mUpdateHighlightBox)
+ {
+ impl.GetCursorPosition(eventData->mLeftSelectionPosition, leftHandleInfo);
+
+ impl.GetCursorPosition(eventData->mRightSelectionPosition, rightHandleInfo);
+
+ if(eventData->mScrollAfterUpdatePosition && (eventData->mIsLeftHandleSelected ? eventData->mUpdateLeftSelectionPosition : eventData->mUpdateRightSelectionPosition))
+ {
+ if(eventData->mIsLeftHandleSelected && eventData->mIsRightHandleSelected)
+ {
+ CursorInfo& infoLeft = leftHandleInfo;
+
+ const Vector2 currentCursorPositionLeft(infoLeft.primaryPosition.x, infoLeft.lineOffset);
+ impl.ScrollToMakePositionVisible(currentCursorPositionLeft, infoLeft.lineHeight);
+
+ CursorInfo& infoRight = rightHandleInfo;
+
+ const Vector2 currentCursorPositionRight(infoRight.primaryPosition.x, infoRight.lineOffset);
+ impl.ScrollToMakePositionVisible(currentCursorPositionRight, infoRight.lineHeight);
+ }
+ else
+ {
+ CursorInfo& info = eventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
+
+ const Vector2 currentCursorPosition(info.primaryPosition.x, info.lineOffset);
+ impl.ScrollToMakePositionVisible(currentCursorPosition, info.lineHeight);
+ }
+ }
+ }
+
+ if(eventData->mUpdateLeftSelectionPosition)
+ {
+ impl.UpdateSelectionHandle(LEFT_SELECTION_HANDLE, leftHandleInfo);
+
+ impl.SetPopupButtons();
+ eventData->mDecoratorUpdated = true;
+ eventData->mUpdateLeftSelectionPosition = false;
+ }
+
+ if(eventData->mUpdateRightSelectionPosition)
+ {
+ impl.UpdateSelectionHandle(RIGHT_SELECTION_HANDLE, rightHandleInfo);
+
+ impl.SetPopupButtons();
+ eventData->mDecoratorUpdated = true;
+ eventData->mUpdateRightSelectionPosition = false;
+ }
+
+ if(eventData->mUpdateHighlightBox)
+ {
+ impl.RepositionSelectionHandles();
+
+ eventData->mUpdateLeftSelectionPosition = false;
+ eventData->mUpdateRightSelectionPosition = false;
+ eventData->mUpdateHighlightBox = false;
+ eventData->mIsLeftHandleSelected = false;
+ eventData->mIsRightHandleSelected = false;
+ }
+
+ eventData->mScrollAfterUpdatePosition = false;
+ }
+
+ if(eventData->mUpdateInputStyle)
+ {
+ // Keep a copy of the current input style.
+ InputStyle currentInputStyle;
+ currentInputStyle.Copy(eventData->mInputStyle);
+
+ // Set the default style first.
+ impl.RetrieveDefaultInputStyle(eventData->mInputStyle);
+
+ // Get the character index from the cursor index.
+ const CharacterIndex styleIndex = (eventData->mPrimaryCursorPosition > 0u) ? eventData->mPrimaryCursorPosition - 1u : 0u;
+
+ // Retrieve the style from the style runs stored in the logical model.
+ impl.mModel->mLogicalModel->RetrieveStyle(styleIndex, eventData->mInputStyle);
+
+ // Compare if the input style has changed.
+ const bool hasInputStyleChanged = !currentInputStyle.Equal(eventData->mInputStyle);
+
+ if(hasInputStyleChanged)
+ {
+ const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(eventData->mInputStyle);
+ // Queue the input style changed signal.
+ eventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
+ }
+
+ eventData->mUpdateInputStyle = false;
+ }
+
+ eventData->mEventQueue.clear();
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n");
+
+ const bool decoratorUpdated = eventData->mDecoratorUpdated;
+ eventData->mDecoratorUpdated = false;
+
+ return decoratorUpdated;
+}
+
+void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const Event& event)
+{
+ if(NULL == impl.mEventData || !impl.IsShowingRealText())
+ {
+ // Nothing to do if there is no text input.
+ return;
+ }
+
+ int keyCode = event.p1.mInt;
+ bool isShiftModifier = event.p2.mBool;
+ EventData& eventData = *impl.mEventData;
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+ uint32_t oldSelStart = eventData.mLeftSelectionPosition;
+ uint32_t oldSelEnd = eventData.mRightSelectionPosition;
+
+ CharacterIndex& primaryCursorPosition = eventData.mPrimaryCursorPosition;
+ CharacterIndex previousPrimaryCursorPosition = primaryCursorPosition;
+
+ if(Dali::DALI_KEY_CURSOR_LEFT == keyCode)
+ {
+ if(primaryCursorPosition > 0u)
+ {
+ if(!isShiftModifier && eventData.mDecorator->IsHighlightVisible())
+ {
+ primaryCursorPosition = std::min(eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ else
+ {
+ primaryCursorPosition = impl.CalculateNewCursorIndex(primaryCursorPosition - 1u);
+ }
+ }
+ }
+ else if(Dali::DALI_KEY_CURSOR_RIGHT == keyCode)
+ {
+ if(logicalModel->mText.Count() > primaryCursorPosition)
+ {
+ if(!isShiftModifier && eventData.mDecorator->IsHighlightVisible())
+ {
+ primaryCursorPosition = std::max(eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ else
+ {
+ primaryCursorPosition = impl.CalculateNewCursorIndex(primaryCursorPosition);
+ }
+ }
+ }
+ else if(Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier)
+ {
+ // Ignore Shift-Up for text selection for now.
+
+ // Get first the line index of the current cursor position index.
+ CharacterIndex characterIndex = 0u;
+
+ if(primaryCursorPosition > 0u)
+ {
+ characterIndex = primaryCursorPosition - 1u;
+ }
+
+ const LineIndex lineIndex = visualModel->GetLineOfCharacter(characterIndex);
+ const LineIndex previousLineIndex = (lineIndex > 0 ? lineIndex - 1u : lineIndex);
+ const LineIndex lastLineIndex = (visualModel->mLines.Size() > 0 ? visualModel->mLines.Size() - 1u : 0);
+ const bool isLastLine = (previousLineIndex == lastLineIndex);
+
+ // Retrieve the cursor position info.
+ CursorInfo cursorInfo;
+ impl.GetCursorPosition(primaryCursorPosition,
+ cursorInfo);
+
+ // Get the line above.
+ const LineRun& line = *(visualModel->mLines.Begin() + previousLineIndex);
+
+ // Get the next hit 'y' point.
+ const float hitPointY = cursorInfo.lineOffset - 0.5f * GetLineHeight(line, isLastLine);
+
+ // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+ bool matchedCharacter = false;
+ primaryCursorPosition = Text::GetClosestCursorIndex(visualModel,
+ logicalModel,
+ impl.mMetrics,
+ eventData.mCursorHookPositionX,
+ hitPointY,
+ CharacterHitTest::TAP,
+ matchedCharacter);
+ }
+ else if(Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier)
+ {
+ // Ignore Shift-Down for text selection for now.
+
+ // Get first the line index of the current cursor position index.
+ CharacterIndex characterIndex = 0u;
+
+ if(primaryCursorPosition > 0u)
+ {
+ characterIndex = primaryCursorPosition - 1u;
+ }
+
+ const LineIndex lineIndex = visualModel->GetLineOfCharacter(characterIndex);
+
+ if(lineIndex + 1u < visualModel->mLines.Count())
+ {
+ // Retrieve the cursor position info.
+ CursorInfo cursorInfo;
+ impl.GetCursorPosition(primaryCursorPosition, cursorInfo);
+
+ // Get the line below.
+ const LineRun& nextline = *(visualModel->mLines.Begin() + lineIndex + 1u);
+ const LineRun& currline = *(visualModel->mLines.Begin() + lineIndex);
+
+ // Get last line index
+ const LineIndex lastLineIndex = (visualModel->mLines.Size() > 0 ? visualModel->mLines.Size() - 1u : 0);
+ const bool isLastLine = (lineIndex + 1u == lastLineIndex);
+
+ // Get the next hit 'y' point.
+ const float hitPointY = cursorInfo.lineOffset + GetLineHeight(currline, false) + 0.5f * GetLineHeight(nextline, isLastLine);
+
+ // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+ bool matchedCharacter = false;
+ primaryCursorPosition = Text::GetClosestCursorIndex(visualModel,
+ logicalModel,
+ impl.mMetrics,
+ eventData.mCursorHookPositionX,
+ hitPointY,
+ CharacterHitTest::TAP,
+ matchedCharacter);
+ }
+ }
+
+ if(!isShiftModifier && eventData.mState != EventData::SELECTING)
+ {
+ // Update selection position after moving the cursor
+ eventData.mLeftSelectionPosition = primaryCursorPosition;
+ eventData.mRightSelectionPosition = primaryCursorPosition;
+
+ if(impl.mSelectableControlInterface != nullptr && eventData.mDecorator->IsHighlightVisible())
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ }
+
+ if(isShiftModifier && impl.IsShowingRealText() && eventData.mShiftSelectionFlag)
+ {
+ // Handle text selection
+ bool selecting = false;
+
+ if(Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode)
+ {
+ // Shift-Left/Right to select the text
+ int cursorPositionDelta = primaryCursorPosition - previousPrimaryCursorPosition;
+ if(cursorPositionDelta > 0 || eventData.mRightSelectionPosition > 0u) // Check the boundary
+ {
+ eventData.mRightSelectionPosition += cursorPositionDelta;
+ eventData.mPrimaryCursorPosition = eventData.mRightSelectionPosition;
+
+ if(impl.mSelectableControlInterface != nullptr)
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ }
+
+ if(impl.mSelectableControlInterface != nullptr && eventData.mLeftSelectionPosition == eventData.mRightSelectionPosition)
+ {
+ // If left selection position and right selection position are the same, the selection is canceled.
+ selecting = false;
+ }
+ else
+ {
+ selecting = true;
+ }
+ }
+ else if(eventData.mLeftSelectionPosition != eventData.mRightSelectionPosition)
+ {
+ // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
+ selecting = true;
+ }
+
+ if(selecting)
+ {
+ // Notify the cursor position to the InputMethodContext.
+ if(eventData.mInputMethodContext)
+ {
+ eventData.mInputMethodContext.SetCursorPosition(primaryCursorPosition);
+ eventData.mInputMethodContext.NotifyCursorPosition();
+ }
+
+ impl.ChangeState(EventData::SELECTING);
+
+ eventData.mUpdateLeftSelectionPosition = true;
+ eventData.mUpdateRightSelectionPosition = true;
+ eventData.mUpdateGrabHandlePosition = true;
+ eventData.mUpdateHighlightBox = true;
+
+ // Hide the text selection popup if select the text using keyboard instead of moving grab handles
+ if(eventData.mGrabHandlePopupEnabled)
+ {
+ eventData.mDecorator->SetPopupActive(false);
+ }
+ }
+ else
+ {
+ // If no selection, set a normal cursor.
+ impl.ChangeState(EventData::EDITING);
+ eventData.mUpdateCursorPosition = true;
+ }
+ }
+ else
+ {
+ // Handle normal cursor move
+ impl.ChangeState(EventData::EDITING);
+ eventData.mUpdateCursorPosition = true;
+ }
+
+ eventData.mUpdateInputStyle = true;
+ eventData.mScrollAfterUpdatePosition = true;
+}
+
+void ControllerImplEventHandler::OnTapEvent(Controller::Impl& impl, const Event& event)
+{
+ if(impl.mEventData)
+ {
+ const unsigned int tapCount = event.p1.mUint;
+ EventData& eventData = *impl.mEventData;
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+
+ if(1u == tapCount)
+ {
+ if(impl.IsShowingRealText())
+ {
+ // Convert from control's coords to text's coords.
+ const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
+ const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
+ uint32_t oldSelStart = eventData.mLeftSelectionPosition;
+ uint32_t oldSelEnd = eventData.mRightSelectionPosition;
+
+ // Keep the tap 'x' position. Used to move the cursor.
+ eventData.mCursorHookPositionX = xPosition;
+
+ // Whether to touch point hits on a glyph.
+ bool matchedCharacter = false;
+ eventData.mPrimaryCursorPosition = Text::GetClosestCursorIndex(visualModel,
+ logicalModel,
+ impl.mMetrics,
+ xPosition,
+ yPosition,
+ CharacterHitTest::TAP,
+ matchedCharacter);
+
+ if(impl.mSelectableControlInterface != nullptr && eventData.mDecorator->IsHighlightVisible())
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mPrimaryCursorPosition, eventData.mPrimaryCursorPosition);
+ }
+
+ // When the cursor position is changing, delay cursor blinking
+ eventData.mDecorator->DelayCursorBlink();
+ }
+ else
+ {
+ eventData.mPrimaryCursorPosition = 0u;
+ }
+
+ // Update selection position after tapping
+ eventData.mLeftSelectionPosition = eventData.mPrimaryCursorPosition;
+ eventData.mRightSelectionPosition = eventData.mPrimaryCursorPosition;
+
+ eventData.mUpdateCursorPosition = true;
+ eventData.mUpdateGrabHandlePosition = true;
+ eventData.mScrollAfterUpdatePosition = true;
+ eventData.mUpdateInputStyle = true;
+
+ // Notify the cursor position to the InputMethodContext.
+ if(eventData.mInputMethodContext)
+ {
+ eventData.mInputMethodContext.SetCursorPosition(eventData.mPrimaryCursorPosition);
+ eventData.mInputMethodContext.NotifyCursorPosition();
+ }
+ }
+ else if(2u == tapCount)
+ {
+ if(eventData.mSelectionEnabled)
+ {
+ // Convert from control's coords to text's coords.
+ const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
+ const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
+
+ // Calculates the logical position from the x,y coords.
+ impl.RepositionSelectionHandles(xPosition, yPosition, eventData.mDoubleTapAction);
+ }
+ }
+ }
+}
+
+void ControllerImplEventHandler::OnPanEvent(Controller::Impl& impl, const Event& event)
+{
+ if(impl.mEventData)
+ {
+ EventData& eventData = *impl.mEventData;
+ DecoratorPtr& decorator = eventData.mDecorator;
+
+ const bool isHorizontalScrollEnabled = decorator->IsHorizontalScrollEnabled();
+ const bool isVerticalScrollEnabled = decorator->IsVerticalScrollEnabled();
+
+ if(!isHorizontalScrollEnabled && !isVerticalScrollEnabled)
+ {
+ // Nothing to do if scrolling is not enabled.
+ return;
+ }
+
+ const GestureState state = static_cast<GestureState>(event.p1.mInt);
+ switch(state)
+ {
+ case GestureState::STARTED:
+ {
+ // Will remove the cursor, handles or text's popup, ...
+ impl.ChangeState(EventData::TEXT_PANNING);
+ break;
+ }
+ case GestureState::CONTINUING:
+ {
+ ModelPtr& model = impl.mModel;
+
+ const Vector2& layoutSize = model->mVisualModel->GetLayoutSize();
+ Vector2& scrollPosition = model->mScrollPosition;
+ const Vector2 currentScroll = scrollPosition;
+
+ if(isHorizontalScrollEnabled)
+ {
+ const float displacementX = event.p2.mFloat;
+ scrollPosition.x += displacementX;
+
+ impl.ClampHorizontalScroll(layoutSize);
+ }
+
+ if(isVerticalScrollEnabled)
+ {
+ const float displacementY = event.p3.mFloat;
+ scrollPosition.y += displacementY;
+
+ impl.ClampVerticalScroll(layoutSize);
+ }
+
+ decorator->UpdatePositions(scrollPosition - currentScroll);
+ break;
+ }
+ case GestureState::FINISHED:
+ case GestureState::CANCELLED: // FALLTHROUGH
+ {
+ // Will go back to the previous state to show the cursor, handles, the text's popup, ...
+ impl.ChangeState(eventData.mPreviousState);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void ControllerImplEventHandler::OnLongPressEvent(Controller::Impl& impl, const Event& event)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::OnLongPressEvent\n");
+
+ if(impl.mEventData)
+ {
+ EventData& eventData = *impl.mEventData;
+
+ if(!impl.IsShowingRealText() && (EventData::EDITING == eventData.mState))
+ {
+ impl.ChangeState(EventData::EDITING_WITH_POPUP);
+ eventData.mDecoratorUpdated = true;
+ eventData.mUpdateInputStyle = true;
+ }
+ else
+ {
+ if(eventData.mSelectionEnabled)
+ {
+ ModelPtr& model = impl.mModel;
+
+ // Convert from control's coords to text's coords.
+ const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
+ const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
+
+ // Calculates the logical position from the x,y coords.
+ impl.RepositionSelectionHandles(xPosition, yPosition, eventData.mLongPressAction);
+ }
+ }
+ }
+}
+
+void ControllerImplEventHandler::OnHandleEvent(Controller::Impl& impl, const Event& event)
+{
+ if(impl.mEventData)
+ {
+ const unsigned int state = event.p1.mUint;
+ const bool handleStopScrolling = (HANDLE_STOP_SCROLLING == state);
+ const bool isSmoothHandlePanEnabled = impl.mEventData->mDecorator->IsSmoothHandlePanEnabled();
+
+ if(HANDLE_PRESSED == state)
+ {
+ OnHandlePressed(impl, event, isSmoothHandlePanEnabled);
+ } // end ( HANDLE_PRESSED == state )
+ else if((HANDLE_RELEASED == state) ||
+ handleStopScrolling)
+ {
+ OnHandleReleased(impl, event, isSmoothHandlePanEnabled, handleStopScrolling);
+ } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
+ else if(HANDLE_SCROLLING == state)
+ {
+ OnHandleScrolling(impl, event, isSmoothHandlePanEnabled);
+ } // end ( HANDLE_SCROLLING == state )
+ }
+}
+
+void ControllerImplEventHandler::OnSelectEvent(Controller::Impl& impl, const Event& event)
+{
+ if(impl.mEventData && impl.mEventData->mSelectionEnabled)
+ {
+ ModelPtr& model = impl.mModel;
+ const Vector2& scrollPosition = model->mScrollPosition;
+
+ // Convert from control's coords to text's coords.
+ const float xPosition = event.p2.mFloat - scrollPosition.x;
+ const float yPosition = event.p3.mFloat - scrollPosition.y;
+
+ // Calculates the logical position from the x,y coords.
+ impl.RepositionSelectionHandles(xPosition, yPosition, Controller::NoTextTap::HIGHLIGHT);
+ }
+}
+
+void ControllerImplEventHandler::OnSelectAllEvent(Controller::Impl& impl)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", impl.mEventData->mSelectionEnabled ? "true" : "false");
+
+ if(impl.mEventData)
+ {
+ EventData& eventData = *impl.mEventData;
+ if(eventData.mSelectionEnabled && eventData.mState != EventData::INACTIVE)
+ {
+ ModelPtr& model = impl.mModel;
+ const Vector2& scrollPosition = model->mScrollPosition;
+
+ // Calculates the logical position from the start.
+ impl.RepositionSelectionHandles(0.f - scrollPosition.x,
+ 0.f - scrollPosition.y,
+ Controller::NoTextTap::HIGHLIGHT);
+
+ uint32_t oldStart = eventData.mLeftSelectionPosition;
+ uint32_t oldEnd = eventData.mRightSelectionPosition;
+
+ eventData.mLeftSelectionPosition = 0u;
+ eventData.mRightSelectionPosition = model->mLogicalModel->mText.Count();
+ eventData.mPrimaryCursorPosition = eventData.mRightSelectionPosition;
+
+ if(impl.mSelectableControlInterface != nullptr)
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ }
+ }
+}
+
+void ControllerImplEventHandler::OnSelectNoneEvent(Controller::Impl& impl)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "OnSelectNoneEvent mEventData->mSelectionEnabled%s \n", impl.mEventData->mSelectionEnabled ? "true" : "false");
+
+ if(impl.mEventData)
+ {
+ EventData& eventData = *impl.mEventData;
+ if(eventData.mSelectionEnabled && eventData.mState == EventData::SELECTING)
+ {
+ uint32_t oldStart = eventData.mLeftSelectionPosition;
+ uint32_t oldEnd = eventData.mRightSelectionPosition;
+
+ eventData.mLeftSelectionPosition = eventData.mRightSelectionPosition = eventData.mPrimaryCursorPosition;
+ impl.ChangeState(EventData::EDITING);
+ eventData.mUpdateCursorPosition = true;
+ eventData.mUpdateInputStyle = true;
+ eventData.mScrollAfterUpdatePosition = true;
+
+ if(impl.mSelectableControlInterface != nullptr)
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ }
+ }
+}
+
+void ControllerImplEventHandler::OnSelectRangeEvent(Controller::Impl& impl, const Event& event)
+{
+ if(impl.mEventData && impl.mEventData->mSelectionEnabled && impl.mEventData->mState != EventData::INACTIVE)
+ {
+ ModelPtr& model = impl.mModel;
+ const Vector2& scrollPosition = model->mScrollPosition;
+
+ // Calculate the selection index.
+ const uint32_t length = static_cast<uint32_t>(model->mLogicalModel->mText.Count());
+ const uint32_t start = std::min(event.p2.mUint, length);
+ const uint32_t end = std::min(event.p3.mUint, length);
+
+ if(start != end)
+ {
+ uint32_t oldStart = impl.mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = impl.mEventData->mRightSelectionPosition;
+
+ // Calculates the logical position from the x,y coords.
+ impl.RepositionSelectionHandles(0.f - scrollPosition.x, 0.f - scrollPosition.y, Controller::NoTextTap::HIGHLIGHT);
+
+ impl.mEventData->mLeftSelectionPosition = start;
+ impl.mEventData->mRightSelectionPosition = end;
+ impl.mEventData->mPrimaryCursorPosition = end;
+
+ if(impl.mSelectableControlInterface != nullptr)
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
+ }
+ }
+ }
+}
+
+void ControllerImplEventHandler::OnHandlePressed(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled)
+{
+ ModelPtr& model = impl.mModel;
+ const Vector2& scrollPosition = model->mScrollPosition;
+
+ // Convert from decorator's coords to text's coords.
+ const float xPosition = event.p2.mFloat - scrollPosition.x;
+ const float yPosition = event.p3.mFloat - scrollPosition.y;
+
+ // Need to calculate the handle's new position.
+ bool matchedCharacter = false;
+ const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex(model->mVisualModel,
+ model->mLogicalModel,
+ impl.mMetrics,
+ xPosition,
+ yPosition,
+ CharacterHitTest::SCROLL,
+ matchedCharacter);
+
+ EventData& eventData = *impl.mEventData;
+ uint32_t oldStart = eventData.mLeftSelectionPosition;
+ uint32_t oldEnd = eventData.mRightSelectionPosition;
+
+ if(Event::GRAB_HANDLE_EVENT == event.type)
+ {
+ impl.ChangeState(EventData::GRAB_HANDLE_PANNING);
+
+ if(handleNewPosition != eventData.mPrimaryCursorPosition)
+ {
+ // Updates the cursor position if the handle's new position is different than the current one.
+ eventData.mUpdateCursorPosition = true;
+ // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
+ eventData.mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
+ eventData.mPrimaryCursorPosition = handleNewPosition;
+ }
+
+ // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
+ eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
+ }
+ else if(Event::LEFT_SELECTION_HANDLE_EVENT == event.type)
+ {
+ impl.ChangeState(EventData::SELECTION_HANDLE_PANNING);
+
+ if((handleNewPosition != eventData.mLeftSelectionPosition) &&
+ (handleNewPosition != eventData.mRightSelectionPosition))
+ {
+ // Updates the highlight box if the handle's new position is different than the current one.
+ eventData.mUpdateHighlightBox = true;
+ // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
+ eventData.mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
+ eventData.mLeftSelectionPosition = handleNewPosition;
+ }
+
+ // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
+ eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
+
+ // Will define the order to scroll the text to match the handle position.
+ eventData.mIsLeftHandleSelected = true;
+ eventData.mIsRightHandleSelected = false;
+ }
+ else if(Event::RIGHT_SELECTION_HANDLE_EVENT == event.type)
+ {
+ impl.ChangeState(EventData::SELECTION_HANDLE_PANNING);
+
+ if((handleNewPosition != eventData.mRightSelectionPosition) &&
+ (handleNewPosition != eventData.mLeftSelectionPosition))
+ {
+ // Updates the highlight box if the handle's new position is different than the current one.
+ eventData.mUpdateHighlightBox = true;
+ // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
+ eventData.mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
+ eventData.mRightSelectionPosition = handleNewPosition;
+ }
+
+ // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
+ eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
+
+ // Will define the order to scroll the text to match the handle position.
+ eventData.mIsLeftHandleSelected = false;
+ eventData.mIsRightHandleSelected = true;
+ }
+
+ if((impl.mSelectableControlInterface != nullptr) && ((oldStart != eventData.mLeftSelectionPosition) || (oldEnd != eventData.mRightSelectionPosition)))
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+}
+
+void ControllerImplEventHandler::OnHandleReleased(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled, const bool handleStopScrolling)
+{
+ CharacterIndex handlePosition = 0u;
+ if(handleStopScrolling || isSmoothHandlePanEnabled)
+ {
+ ModelPtr& model = impl.mModel;
+ const Vector2& scrollPosition = model->mScrollPosition;
+
+ // Convert from decorator's coords to text's coords.
+ const float xPosition = event.p2.mFloat - scrollPosition.x;
+ const float yPosition = event.p3.mFloat - scrollPosition.y;
+
+ bool matchedCharacter = false;
+ handlePosition = Text::GetClosestCursorIndex(model->mVisualModel,
+ model->mLogicalModel,
+ impl.mMetrics,
+ xPosition,
+ yPosition,
+ CharacterHitTest::SCROLL,
+ matchedCharacter);
+ }
+
+ EventData& eventData = *impl.mEventData;
+ uint32_t oldStart = eventData.mLeftSelectionPosition;
+ uint32_t oldEnd = eventData.mRightSelectionPosition;
+
+ if(Event::GRAB_HANDLE_EVENT == event.type)
+ {
+ eventData.mUpdateCursorPosition = true;
+ eventData.mUpdateGrabHandlePosition = true;
+ eventData.mUpdateInputStyle = true;
+
+ if(!impl.IsClipboardEmpty())
+ {
+ impl.ChangeState(EventData::EDITING_WITH_PASTE_POPUP); // Moving grabhandle will show Paste Popup
+ }
+
+ if(handleStopScrolling || isSmoothHandlePanEnabled)
+ {
+ eventData.mScrollAfterUpdatePosition = true;
+ eventData.mPrimaryCursorPosition = handlePosition;
+ }
+ }
+ else if(Event::LEFT_SELECTION_HANDLE_EVENT == event.type)
+ {
+ impl.ChangeState(EventData::SELECTING);
+
+ eventData.mUpdateHighlightBox = true;
+ eventData.mUpdateLeftSelectionPosition = true;
+ eventData.mUpdateRightSelectionPosition = true;
+
+ if(handleStopScrolling || isSmoothHandlePanEnabled)
+ {
+ eventData.mScrollAfterUpdatePosition = true;
+
+ if((handlePosition != eventData.mRightSelectionPosition) &&
+ (handlePosition != eventData.mLeftSelectionPosition))
+ {
+ eventData.mLeftSelectionPosition = handlePosition;
+ }
+ }
+ }
+ else if(Event::RIGHT_SELECTION_HANDLE_EVENT == event.type)
+ {
+ impl.ChangeState(EventData::SELECTING);
+
+ eventData.mUpdateHighlightBox = true;
+ eventData.mUpdateRightSelectionPosition = true;
+ eventData.mUpdateLeftSelectionPosition = true;
+
+ if(handleStopScrolling || isSmoothHandlePanEnabled)
+ {
+ eventData.mScrollAfterUpdatePosition = true;
+ if((handlePosition != eventData.mRightSelectionPosition) &&
+ (handlePosition != eventData.mLeftSelectionPosition))
+ {
+ eventData.mRightSelectionPosition = handlePosition;
+ }
+ }
+ }
+
+ if((impl.mSelectableControlInterface != nullptr) && ((oldStart != eventData.mLeftSelectionPosition) || (oldEnd != eventData.mRightSelectionPosition)))
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+
+ eventData.mDecoratorUpdated = true;
+}
+
+void ControllerImplEventHandler::OnHandleScrolling(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled)
+{
+ ModelPtr& model = impl.mModel;
+ Vector2& scrollPosition = model->mScrollPosition;
+ VisualModelPtr& visualModel = model->mVisualModel;
+
+ const float xSpeed = event.p2.mFloat;
+ const float ySpeed = event.p3.mFloat;
+ const Vector2& layoutSize = visualModel->GetLayoutSize();
+ const Vector2 currentScrollPosition = scrollPosition;
+
+ scrollPosition.x += xSpeed;
+ scrollPosition.y += ySpeed;
+
+ impl.ClampHorizontalScroll(layoutSize);
+ impl.ClampVerticalScroll(layoutSize);
+
+ EventData& eventData = *impl.mEventData;
+ DecoratorPtr& decorator = eventData.mDecorator;
+
+ bool endOfScroll = false;
+ if(Vector2::ZERO == (currentScrollPosition - scrollPosition))
+ {
+ // Notify the decorator there is no more text to scroll.
+ // The decorator won't send more scroll events.
+ decorator->NotifyEndOfScroll();
+ // Still need to set the position of the handle.
+ endOfScroll = true;
+ }
+
+ // Set the position of the handle.
+ const bool scrollRightDirection = xSpeed > 0.f;
+ const bool scrollBottomDirection = ySpeed > 0.f;
+ const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
+ const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
+
+ if(Event::GRAB_HANDLE_EVENT == event.type)
+ {
+ impl.ChangeState(EventData::GRAB_HANDLE_PANNING);
+
+ // Get the grab handle position in decorator coords.
+ Vector2 position = decorator->GetPosition(GRAB_HANDLE);
+
+ if(decorator->IsHorizontalScrollEnabled())
+ {
+ // Position the grag handle close to either the left or right edge.
+ position.x = scrollRightDirection ? 0.f : visualModel->mControlSize.width;
+ }
+
+ if(decorator->IsVerticalScrollEnabled())
+ {
+ position.x = eventData.mCursorHookPositionX;
+
+ // Position the grag handle close to either the top or bottom edge.
+ position.y = scrollBottomDirection ? 0.f : visualModel->mControlSize.height;
+ }
+
+ // Get the new handle position.
+ // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
+ bool matchedCharacter = false;
+ const CharacterIndex handlePosition = Text::GetClosestCursorIndex(visualModel,
+ impl.mModel->mLogicalModel,
+ impl.mMetrics,
+ position.x - scrollPosition.x,
+ position.y - scrollPosition.y,
+ CharacterHitTest::SCROLL,
+ matchedCharacter);
+
+ if(eventData.mPrimaryCursorPosition != handlePosition)
+ {
+ eventData.mUpdateCursorPosition = true;
+ eventData.mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
+ eventData.mScrollAfterUpdatePosition = true;
+ eventData.mPrimaryCursorPosition = handlePosition;
+ }
+ eventData.mUpdateInputStyle = eventData.mUpdateCursorPosition;
+
+ // Updates the decorator if the soft handle panning is enabled.
+ eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
+ }
+ else if(leftSelectionHandleEvent || rightSelectionHandleEvent)
+ {
+ impl.ChangeState(EventData::SELECTION_HANDLE_PANNING);
+
+ // Get the selection handle position in decorator coords.
+ Vector2 position = decorator->GetPosition(leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE);
+
+ if(decorator->IsHorizontalScrollEnabled())
+ {
+ // Position the selection handle close to either the left or right edge.
+ position.x = scrollRightDirection ? 0.f : visualModel->mControlSize.width;
+ }
+
+ if(decorator->IsVerticalScrollEnabled())
+ {
+ position.x = eventData.mCursorHookPositionX;
+
+ // Position the grag handle close to either the top or bottom edge.
+ position.y = scrollBottomDirection ? 0.f : visualModel->mControlSize.height;
+ }
+
+ // Get the new handle position.
+ // The selection handle's position is in decorator's coords. Need to transform to text's coords.
+ bool matchedCharacter = false;
+ const CharacterIndex handlePosition = Text::GetClosestCursorIndex(visualModel,
+ impl.mModel->mLogicalModel,
+ impl.mMetrics,
+ position.x - scrollPosition.x,
+ position.y - scrollPosition.y,
+ CharacterHitTest::SCROLL,
+ matchedCharacter);
+ uint32_t oldStart = eventData.mLeftSelectionPosition;
+ uint32_t oldEnd = eventData.mRightSelectionPosition;
+
+ if(leftSelectionHandleEvent)
+ {
+ const bool differentHandles = (eventData.mLeftSelectionPosition != handlePosition) && (eventData.mRightSelectionPosition != handlePosition);
+
+ if(differentHandles || endOfScroll)
+ {
+ eventData.mUpdateHighlightBox = true;
+ eventData.mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
+ eventData.mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
+ eventData.mLeftSelectionPosition = handlePosition;
+ }
+ }
+ else
+ {
+ const bool differentHandles = (eventData.mRightSelectionPosition != handlePosition) && (eventData.mLeftSelectionPosition != handlePosition);
+ if(differentHandles || endOfScroll)
+ {
+ eventData.mUpdateHighlightBox = true;
+ eventData.mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
+ eventData.mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
+ eventData.mRightSelectionPosition = handlePosition;
+ }
+ }
+
+ if(eventData.mUpdateLeftSelectionPosition || eventData.mUpdateRightSelectionPosition)
+ {
+ impl.RepositionSelectionHandles();
+
+ eventData.mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
+
+ if(impl.mSelectableControlInterface != nullptr)
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+ }
+ }
+ }
+ eventData.mDecoratorUpdated = true;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_EVENT_HANDLER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_EVENT_HANDLER_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * Contains all the event handling methods for Text::Controller::Impl
+ */
+struct ControllerImplEventHandler
+{
+ /**
+ * @brief Processes input events
+ *
+ * @param[in] impl A reference to Controller::Impl
+ * @return True if the decorator has been updated
+ */
+ static bool ProcessInputEvents(Controller::Impl& impl);
+
+ /**
+ * @brief Called by Controller::Impl when a cursor key event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnCursorKeyEvent(Controller::Impl& controllerImpl, const Event& event);
+
+ /**
+ * @brief Called by Controller::Impl when a tap event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnTapEvent(Controller::Impl& controllerImpl, const Event& event);
+
+ /**
+ * @brief Called by Controller::Impl when a pan event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnPanEvent(Controller::Impl& controllerImpl, const Event& event);
+
+ /**
+ * @brief Called by Controller::Impl when a long press event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnLongPressEvent(Controller::Impl& controllerImpl, const Event& event);
+
+ /**
+ * @brief Called by Controller::Impl when a handle event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnHandleEvent(Controller::Impl& controllerImpl, const Event& event);
+
+ /**
+ * @brief Called by Controller::Impl when a select event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnSelectEvent(Controller::Impl& controllerImpl, const Event& event);
+
+ /**
+ * @brief Called by Controller::Impl when a select all event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnSelectAllEvent(Controller::Impl& controllerImpl);
+
+ /**
+ * @brief Called by Controller::Impl when a select none event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnSelectNoneEvent(Controller::Impl& controllerImpl);
+
+ /**
+ * @brief Called by Controller::Impl when a select range event is received.
+ *
+ * @param controllerImpl A reference to Controller::Impl
+ * @param event The event
+ */
+ static void OnSelectRangeEvent(Controller::Impl& controllerImpl, const Event& event);
+
+private:
+ /**
+ * @brief Called by OnHandleEvent when we are in the Pressed state.
+ *
+ * @param impl A reference to Controller::Impl
+ * @param event The event
+ * @param isSmoothHandlePanEnabled Whether smooth handle pan is enabled
+ */
+ static void OnHandlePressed(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled);
+
+ /**
+ * @brief Called by OnHandleEvent when we are in the Released state.
+ *
+ * @param impl A reference to Controller::Impl
+ * @param event The event
+ * @param isSmoothHandlePanEnabled Whether smooth handle pan is enabled
+ * @param handleStopScrolling Whether we should handle stop scrolling or not
+ */
+ static void OnHandleReleased(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled, const bool handleStopScrolling);
+
+ /**
+ * @brief Called by OnHandleEvent when we are in the Scrolling state.
+ *
+ * @param impl A reference to Controller::Impl
+ * @param event The event
+ * @param isSmoothHandlePanEnabled Whether smooth handle pan is enabled
+ */
+ static void OnHandleScrolling(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled);
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_EVENT_HANDLER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-impl-model-updater.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/color-segmentation.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+
+namespace Dali::Toolkit::Text
+{
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+// The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
+// based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
+constexpr float BRIGHTNESS_THRESHOLD = 0.179f;
+constexpr float CONSTANT_R = 0.2126f;
+constexpr float CONSTANT_G = 0.7152f;
+constexpr float CONSTANT_B = 0.0722f;
+constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
+constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
+constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
+} // namespace
+
+bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
+
+ // Calculate the operations to be done.
+ const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
+
+ if(Controller::NO_OPERATION == operations)
+ {
+ // Nothing to do if no operations are pending and required.
+ return false;
+ }
+
+ Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
+ Vector<Character> displayCharacters;
+ bool useHiddenText = false;
+ if(impl.mHiddenInput && impl.mEventData != nullptr && !impl.mEventData->mIsShowingPlaceholderText)
+ {
+ impl.mHiddenInput->Substitute(srcCharacters, displayCharacters);
+ useHiddenText = true;
+ }
+
+ Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
+ const Length numberOfCharacters = utf32Characters.Count();
+
+ // Index to the first character of the first paragraph to be updated.
+ CharacterIndex startIndex = 0u;
+ // Number of characters of the paragraphs to be removed.
+ Length paragraphCharacters = 0u;
+
+ impl.CalculateTextUpdateIndices(paragraphCharacters);
+
+ // Check whether the indices for updating the text is valid
+ if(numberOfCharacters > 0u &&
+ (impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
+ impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
+ {
+ std::string currentText;
+ Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
+
+ DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
+ DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
+
+ // Dump mTextUpdateInfo
+ DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
+ DALI_LOG_ERROR(" mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
+ DALI_LOG_ERROR(" mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
+
+ return false;
+ }
+
+ startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
+
+ if(impl.mTextUpdateInfo.mClearAll ||
+ (0u != paragraphCharacters))
+ {
+ impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
+ }
+
+ impl.mTextUpdateInfo.mClearAll = false;
+
+ // Whether the model is updated.
+ bool updated = false;
+
+ Vector<LineBreakInfo>& lineBreakInfo = impl.mModel->mLogicalModel->mLineBreakInfo;
+ const Length requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
+
+ if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
+ {
+ // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
+ // calculate the bidirectional info for each 'paragraph'.
+ // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
+ // is not shaped together).
+ lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
+
+ SetLineBreakInfo(utf32Characters,
+ startIndex,
+ requestedNumberOfCharacters,
+ lineBreakInfo);
+
+ if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+ {
+ CharacterIndex end = startIndex + requestedNumberOfCharacters;
+ LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ for(CharacterIndex index = startIndex; index < end; index++)
+ {
+ CharacterIndex wordEnd = index;
+ while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+ {
+ wordEnd++;
+ }
+
+ if((wordEnd + 1) == end) // add last char
+ {
+ wordEnd++;
+ }
+
+ Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+ for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+ {
+ if(hyphens[i])
+ {
+ *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+ }
+ }
+
+ index = wordEnd;
+ }
+ }
+
+ // Create the paragraph info.
+ impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
+ requestedNumberOfCharacters);
+ updated = true;
+ }
+
+ const bool getScripts = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
+ const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
+
+ Vector<ScriptRun>& scripts = impl.mModel->mLogicalModel->mScriptRuns;
+ Vector<FontRun>& validFonts = impl.mModel->mLogicalModel->mFontRuns;
+
+ if(getScripts || validateFonts)
+ {
+ // Validates the fonts assigned by the application or assigns default ones.
+ // It makes sure all the characters are going to be rendered by the correct font.
+ MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+ if(getScripts)
+ {
+ // Retrieves the scripts used in the text.
+ multilanguageSupport.SetScripts(utf32Characters,
+ startIndex,
+ requestedNumberOfCharacters,
+ scripts);
+ }
+
+ if(validateFonts)
+ {
+ // Validate the fonts set through the mark-up string.
+ Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
+
+ // Get the default font's description.
+ TextAbstraction::FontDescription defaultFontDescription;
+ TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.GetFontSizeScale();
+
+ //Get the number of points per one unit of point-size
+ uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
+
+ if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
+ {
+ // If the placeholder font is set specifically, only placeholder font is changed.
+ defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
+ if(impl.mEventData->mPlaceholderFont->sizeDefined)
+ {
+ defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
+ }
+ }
+ else if(nullptr != impl.mFontDefaults)
+ {
+ // Set the normal font and the placeholder font.
+ defaultFontDescription = impl.mFontDefaults->mFontDescription;
+
+ if(impl.mTextFitEnabled)
+ {
+ defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
+ }
+ else
+ {
+ defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
+ }
+ }
+
+ // Validates the fonts. If there is a character with no assigned font it sets a default one.
+ // After this call, fonts are validated.
+ multilanguageSupport.ValidateFonts(utf32Characters,
+ scripts,
+ fontDescriptionRuns,
+ defaultFontDescription,
+ defaultPointSize,
+ startIndex,
+ requestedNumberOfCharacters,
+ validFonts);
+ }
+ updated = true;
+ }
+
+ Vector<Character> mirroredUtf32Characters;
+ bool textMirrored = false;
+ const Length numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
+ if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
+ {
+ Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
+ bidirectionalInfo.Reserve(numberOfParagraphs);
+
+ // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+ SetBidirectionalInfo(utf32Characters,
+ scripts,
+ lineBreakInfo,
+ startIndex,
+ requestedNumberOfCharacters,
+ bidirectionalInfo,
+ (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
+ impl.mLayoutDirection);
+
+ if(0u != bidirectionalInfo.Count())
+ {
+ // Only set the character directions if there is right to left characters.
+ Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
+ GetCharactersDirection(bidirectionalInfo,
+ numberOfCharacters,
+ startIndex,
+ requestedNumberOfCharacters,
+ directions);
+
+ // This paragraph has right to left text. Some characters may need to be mirrored.
+ // TODO: consider if the mirrored string can be stored as well.
+
+ textMirrored = GetMirroredText(utf32Characters,
+ directions,
+ bidirectionalInfo,
+ startIndex,
+ requestedNumberOfCharacters,
+ mirroredUtf32Characters);
+ }
+ else
+ {
+ // There is no right to left characters. Clear the directions vector.
+ impl.mModel->mLogicalModel->mCharacterDirections.Clear();
+ }
+ updated = true;
+ }
+
+ Vector<GlyphInfo>& glyphs = impl.mModel->mVisualModel->mGlyphs;
+ Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
+ Vector<Length>& charactersPerGlyph = impl.mModel->mVisualModel->mCharactersPerGlyph;
+ Vector<GlyphIndex> newParagraphGlyphs;
+ newParagraphGlyphs.Reserve(numberOfParagraphs);
+
+ const Length currentNumberOfGlyphs = glyphs.Count();
+ if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
+ {
+ const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+ // Shapes the text.
+ ShapeText(textToShape,
+ lineBreakInfo,
+ scripts,
+ validFonts,
+ startIndex,
+ impl.mTextUpdateInfo.mStartGlyphIndex,
+ requestedNumberOfCharacters,
+ glyphs,
+ glyphsToCharactersMap,
+ charactersPerGlyph,
+ newParagraphGlyphs);
+
+ // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+ impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
+ impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
+
+ updated = true;
+ }
+
+ const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+
+ if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
+ {
+ GlyphInfo* glyphsBuffer = glyphs.Begin();
+ impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
+
+ // Update the width and advance of all new paragraph characters.
+ for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
+ {
+ const GlyphIndex index = *it;
+ GlyphInfo& glyph = *(glyphsBuffer + index);
+
+ glyph.xBearing = 0.f;
+ glyph.width = 0.f;
+ glyph.advance = 0.f;
+ }
+ updated = true;
+ }
+
+ if((nullptr != impl.mEventData) &&
+ impl.mEventData->mPreEditFlag &&
+ (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
+ {
+ Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
+ impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
+ Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
+
+ // Check the type of preedit and run it.
+ for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
+ {
+ Dali::InputMethodContext::PreeditAttributeData attrData = *it;
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
+ type = attrData.preeditType;
+
+ // Check the number of commit characters for the start position.
+ unsigned int numberOfCommit = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
+ Length numberOfIndices = attrData.endIndex - attrData.startIndex;
+
+ switch(type)
+ {
+ case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
+ {
+ // Add the underline for the pre-edit text.
+ UnderlinedGlyphRun underlineRun;
+ underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
+ underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
+ impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::REVERSE:
+ {
+ Vector4 textColor = impl.mModel->mVisualModel->GetTextColor();
+ ColorRun backgroundColorRun;
+ backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+ backgroundColorRun.color = textColor;
+ impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
+ if(backgroundColor.a == 0) // There is no text background color.
+ {
+ // Try use the control's background color.
+ if(nullptr != impl.mEditableControlInterface)
+ {
+ impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
+ if(backgroundColor.a == 0) // There is no control background color.
+ {
+ // Determines black or white color according to text color.
+ // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
+ float L = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
+ backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
+ }
+ }
+ }
+
+ Vector<ColorRun> colorRuns;
+ colorRuns.Resize(1u);
+ ColorRun& colorRun = *(colorRuns.Begin());
+ colorRun.color = backgroundColor;
+ colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ colorRun.characterRun.numberOfCharacters = numberOfIndices;
+ impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
+ {
+ ColorRun backgroundColorRun;
+ backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+ backgroundColorRun.color = LIGHT_BLUE;
+ impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
+ {
+ // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
+ ColorRun backgroundColorRun;
+ backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+ backgroundColorRun.color = BACKGROUND_SUB4;
+ impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ UnderlinedGlyphRun underlineRun;
+ underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
+ underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
+ impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
+ {
+ // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
+ ColorRun backgroundColorRun;
+ backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+ backgroundColorRun.color = BACKGROUND_SUB5;
+ impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ UnderlinedGlyphRun underlineRun;
+ underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
+ underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
+ impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
+ {
+ // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
+ ColorRun backgroundColorRun;
+ backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+ backgroundColorRun.color = BACKGROUND_SUB6;
+ impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ UnderlinedGlyphRun underlineRun;
+ underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
+ underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
+ impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
+ {
+ // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
+ ColorRun backgroundColorRun;
+ backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+ backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+ backgroundColorRun.color = BACKGROUND_SUB7;
+ impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ UnderlinedGlyphRun underlineRun;
+ underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
+ underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
+ impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(false);
+ }
+ break;
+ }
+ case Dali::InputMethodContext::PreeditStyle::NONE:
+ default:
+ {
+ break;
+ }
+ }
+ }
+ attrs.Clear();
+ updated = true;
+ }
+
+ if(Controller::NO_OPERATION != (Controller::COLOR & operations))
+ {
+ // Set the color runs in glyphs.
+ SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
+ impl.mModel->mVisualModel->mCharactersToGlyph,
+ impl.mModel->mVisualModel->mGlyphsPerCharacter,
+ startIndex,
+ impl.mTextUpdateInfo.mStartGlyphIndex,
+ requestedNumberOfCharacters,
+ impl.mModel->mVisualModel->mColors,
+ impl.mModel->mVisualModel->mColorIndices);
+
+ // Set the background color runs in glyphs.
+ SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
+ impl.mModel->mVisualModel->mCharactersToGlyph,
+ impl.mModel->mVisualModel->mGlyphsPerCharacter,
+ startIndex,
+ impl.mTextUpdateInfo.mStartGlyphIndex,
+ requestedNumberOfCharacters,
+ impl.mModel->mVisualModel->mBackgroundColors,
+ impl.mModel->mVisualModel->mBackgroundColorIndices);
+
+ updated = true;
+ }
+
+ if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
+ !((nullptr != impl.mEventData) &&
+ impl.mEventData->mPreEditFlag &&
+ (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
+ {
+ //Mark-up processor case
+ if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ impl.CopyUnderlinedFromLogicalToVisualModels(true);
+ impl.CopyStrikethroughFromLogicalToVisualModels();
+ impl.CopyCharacterSpacingFromLogicalToVisualModels();
+ }
+
+ updated = true;
+ }
+
+ // The estimated number of lines. Used to avoid reallocations when layouting.
+ impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
+
+ // Set the previous number of characters for the next time the text is updated.
+ impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
+
+ return updated;
+}
+
+} // namespace Dali::Toolkit::Text
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+
+namespace Dali::Toolkit::Text
+{
+
+/**
+ * Contains methods for updating the models in the TextController
+ */
+struct ControllerImplModelUpdater
+{
+ using OperationsMask = Controller::OperationsMask;
+
+ /**
+ * @brief Updates the logical and visual models. Updates the style runs in the visual model when the text's styles changes.
+ *
+ * @param[in] impl A reference to the Controller::Impl class
+ * @param[in] operationsRequired The operations required
+ * @return true if mode has been modified.
+ */
+ static bool Update(Controller::Impl& impl, OperationsMask operationsRequired);
+};
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <cmath>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl-data-clearer.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl-event-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl-model-updater.h>
+#include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-relayouter.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
+
+using namespace Dali;
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
+
+const std::string EMPTY_STRING("");
+
+} // namespace
+
+namespace Dali::Toolkit::Text
+{
+namespace
+{
+void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const fontDefaults, const Vector4& textColor)
+{
+ // Sets the default text's color.
+ inputStyle.textColor = textColor;
+ inputStyle.isDefaultColor = true;
+
+ inputStyle.familyName.clear();
+ inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
+ inputStyle.width = TextAbstraction::FontWidth::NORMAL;
+ inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
+ inputStyle.size = 0.f;
+
+ inputStyle.lineSpacing = 0.f;
+
+ inputStyle.underlineProperties.clear();
+ inputStyle.shadowProperties.clear();
+ inputStyle.embossProperties.clear();
+ inputStyle.outlineProperties.clear();
+
+ inputStyle.isFamilyDefined = false;
+ inputStyle.isWeightDefined = false;
+ inputStyle.isWidthDefined = false;
+ inputStyle.isSlantDefined = false;
+ inputStyle.isSizeDefined = false;
+
+ inputStyle.isLineSpacingDefined = false;
+
+ inputStyle.isUnderlineDefined = false;
+ inputStyle.isShadowDefined = false;
+ inputStyle.isEmbossDefined = false;
+ inputStyle.isOutlineDefined = false;
+
+ // Sets the default font's family name, weight, width, slant and size.
+ if(fontDefaults)
+ {
+ if(fontDefaults->familyDefined)
+ {
+ inputStyle.familyName = fontDefaults->mFontDescription.family;
+ inputStyle.isFamilyDefined = true;
+ }
+
+ if(fontDefaults->weightDefined)
+ {
+ inputStyle.weight = fontDefaults->mFontDescription.weight;
+ inputStyle.isWeightDefined = true;
+ }
+
+ if(fontDefaults->widthDefined)
+ {
+ inputStyle.width = fontDefaults->mFontDescription.width;
+ inputStyle.isWidthDefined = true;
+ }
+
+ if(fontDefaults->slantDefined)
+ {
+ inputStyle.slant = fontDefaults->mFontDescription.slant;
+ inputStyle.isSlantDefined = true;
+ }
+
+ if(fontDefaults->sizeDefined)
+ {
+ inputStyle.size = fontDefaults->mDefaultPointSize;
+ inputStyle.isSizeDefined = true;
+ }
+ }
+}
+
+void ChangeTextControllerState(Controller::Impl& impl, EventData::State newState)
+{
+ EventData* eventData = impl.mEventData;
+
+ if(nullptr == eventData)
+ {
+ // Nothing to do if there is no text input.
+ return;
+ }
+
+ DecoratorPtr& decorator = eventData->mDecorator;
+ if(!decorator)
+ {
+ // Nothing to do if there is no decorator.
+ return;
+ }
+
+ DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d newstate:%d\n", eventData->mState, newState);
+
+ if(eventData->mState != newState)
+ {
+ eventData->mPreviousState = eventData->mState;
+ eventData->mState = newState;
+
+ switch(eventData->mState)
+ {
+ case EventData::INACTIVE:
+ {
+ decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+ decorator->StopCursorBlink();
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+ decorator->SetPopupActive(false);
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::INTERRUPTED:
+ {
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+ decorator->SetPopupActive(false);
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::SELECTING:
+ {
+ decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+ decorator->StopCursorBlink();
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ if(eventData->mGrabHandleEnabled)
+ {
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
+ }
+ decorator->SetHighlightActive(true);
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ impl.SetPopupButtons();
+ decorator->SetPopupActive(true);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::EDITING:
+ {
+ decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+ if(eventData->mCursorBlinkEnabled)
+ {
+ decorator->StartCursorBlink();
+ }
+ // Grab handle is not shown until a tap is received whilst EDITING
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ decorator->SetPopupActive(false);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+ case EventData::EDITING_WITH_POPUP:
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
+
+ decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+ if(eventData->mCursorBlinkEnabled)
+ {
+ decorator->StartCursorBlink();
+ }
+ if(eventData->mSelectionEnabled)
+ {
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+ }
+ else if(eventData->mGrabHandleEnabled)
+ {
+ decorator->SetHandleActive(GRAB_HANDLE, true);
+ }
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ impl.SetPopupButtons();
+ decorator->SetPopupActive(true);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+ case EventData::EDITING_WITH_GRAB_HANDLE:
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
+
+ decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+ if(eventData->mCursorBlinkEnabled)
+ {
+ decorator->StartCursorBlink();
+ }
+ // Grab handle is not shown until a tap is received whilst EDITING
+ if(eventData->mGrabHandleEnabled)
+ {
+ decorator->SetHandleActive(GRAB_HANDLE, true);
+ }
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ decorator->SetPopupActive(false);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::SELECTION_HANDLE_PANNING:
+ {
+ decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+ decorator->StopCursorBlink();
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ if(eventData->mGrabHandleEnabled)
+ {
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
+ }
+ decorator->SetHighlightActive(true);
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ decorator->SetPopupActive(false);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::GRAB_HANDLE_PANNING:
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
+
+ decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+ if(eventData->mCursorBlinkEnabled)
+ {
+ decorator->StartCursorBlink();
+ }
+ if(eventData->mGrabHandleEnabled)
+ {
+ decorator->SetHandleActive(GRAB_HANDLE, true);
+ }
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ decorator->SetPopupActive(false);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::EDITING_WITH_PASTE_POPUP:
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
+
+ decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+ if(eventData->mCursorBlinkEnabled)
+ {
+ decorator->StartCursorBlink();
+ }
+
+ if(eventData->mGrabHandleEnabled)
+ {
+ decorator->SetHandleActive(GRAB_HANDLE, true);
+ }
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(false);
+
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ impl.SetPopupButtons();
+ decorator->SetPopupActive(true);
+ }
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+
+ case EventData::TEXT_PANNING:
+ {
+ decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+ decorator->StopCursorBlink();
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ if(eventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
+ decorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
+ {
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ decorator->SetHighlightActive(true);
+ }
+
+ if(eventData->mGrabHandlePopupEnabled)
+ {
+ decorator->SetPopupActive(false);
+ }
+
+ eventData->mDecoratorUpdated = true;
+ break;
+ }
+ }
+ }
+}
+
+void UpdateCursorPositionForAlignment(Controller::Impl& impl, bool needFullAlignment)
+{
+ EventData* eventData = impl.mEventData;
+
+ // Set the flag to redo the alignment operation
+ impl.mOperationsPending = static_cast<Controller::OperationsMask>(impl.mOperationsPending | Controller::OperationsMask::ALIGN);
+
+ if(eventData)
+ {
+ // Note: mUpdateAlignment is currently only needed for horizontal alignment
+ eventData->mUpdateAlignment = needFullAlignment;
+
+ // Update the cursor if it's in editing mode
+ if(EventData::IsEditingState(eventData->mState))
+ {
+ impl.ChangeState(EventData::EDITING);
+ eventData->mUpdateCursorPosition = true;
+ }
+ }
+}
+
+} // unnamed Namespace
+
+EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
+: mDecorator(decorator),
+ mInputMethodContext(inputMethodContext),
+ mPlaceholderFont(nullptr),
+ mPlaceholderTextActive(),
+ mPlaceholderTextInactive(),
+ mPlaceholderTextColor(0.8f, 0.8f, 0.8f, 0.8f), // This color has been published in the Public API (placeholder-properties.h).
+ mEventQueue(),
+ mInputStyleChangedQueue(),
+ mPreviousState(INACTIVE),
+ mState(INACTIVE),
+ mPrimaryCursorPosition(0u),
+ mLeftSelectionPosition(0u),
+ mRightSelectionPosition(0u),
+ mPreEditStartPosition(0u),
+ mPreEditLength(0u),
+ mCursorHookPositionX(0.f),
+ mDoubleTapAction(Controller::NoTextTap::NO_ACTION),
+ mLongPressAction(Controller::NoTextTap::SHOW_SELECTION_POPUP),
+ mIsShowingPlaceholderText(false),
+ mPreEditFlag(false),
+ mDecoratorUpdated(false),
+ mCursorBlinkEnabled(true),
+ mGrabHandleEnabled(true),
+ mGrabHandlePopupEnabled(true),
+ mSelectionEnabled(true),
+ mUpdateCursorHookPosition(false),
+ mUpdateCursorPosition(false),
+ mUpdateGrabHandlePosition(false),
+ mUpdateLeftSelectionPosition(false),
+ mUpdateRightSelectionPosition(false),
+ mIsLeftHandleSelected(false),
+ mIsRightHandleSelected(false),
+ mUpdateHighlightBox(false),
+ mScrollAfterUpdatePosition(false),
+ mScrollAfterDelete(false),
+ mAllTextSelected(false),
+ mUpdateInputStyle(false),
+ mPasswordInput(false),
+ mCheckScrollAmount(false),
+ mIsPlaceholderPixelSize(false),
+ mIsPlaceholderElideEnabled(false),
+ mPlaceholderEllipsisFlag(false),
+ mShiftSelectionFlag(true),
+ mUpdateAlignment(false),
+ mEditingEnabled(true)
+{
+}
+
+bool Controller::Impl::ProcessInputEvents()
+{
+ return ControllerImplEventHandler::ProcessInputEvents(*this);
+}
+
+void Controller::Impl::NotifyInputMethodContext()
+{
+ if(mEventData && mEventData->mInputMethodContext)
+ {
+ CharacterIndex cursorPosition = GetLogicalCursorPosition();
+
+ const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces(0u);
+
+ // Update the cursor position by removing the initial white spaces.
+ if(cursorPosition < numberOfWhiteSpaces)
+ {
+ cursorPosition = 0u;
+ }
+ else
+ {
+ cursorPosition -= numberOfWhiteSpaces;
+ }
+
+ mEventData->mInputMethodContext.SetCursorPosition(cursorPosition);
+ mEventData->mInputMethodContext.NotifyCursorPosition();
+ }
+}
+
+void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
+{
+ if(mEventData && mEventData->mInputMethodContext)
+ {
+ Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
+ mEventData->mInputMethodContext.NotifyTextInputMultiLine(layout == Text::Layout::Engine::MULTI_LINE_BOX);
+ }
+}
+
+CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
+{
+ CharacterIndex cursorPosition = 0u;
+
+ if(mEventData)
+ {
+ if((EventData::SELECTING == mEventData->mState) ||
+ (EventData::SELECTION_HANDLE_PANNING == mEventData->mState))
+ {
+ cursorPosition = std::min(mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition);
+ }
+ else
+ {
+ cursorPosition = mEventData->mPrimaryCursorPosition;
+ }
+ }
+
+ return cursorPosition;
+}
+
+Length Controller::Impl::GetNumberOfWhiteSpaces(CharacterIndex index) const
+{
+ Length numberOfWhiteSpaces = 0u;
+
+ // Get the buffer to the text.
+ Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
+
+ const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
+ for(; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces)
+ {
+ if(!TextAbstraction::IsWhiteSpace(*(utf32CharacterBuffer + index)))
+ {
+ break;
+ }
+ }
+
+ return numberOfWhiteSpaces;
+}
+
+void Controller::Impl::GetText(std::string& text) const
+{
+ if(!IsShowingPlaceholderText())
+ {
+ // Retrieves the text string.
+ GetText(0u, text);
+ }
+ else
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this);
+ }
+}
+
+void Controller::Impl::GetText(CharacterIndex index, std::string& text) const
+{
+ // Get the total number of characters.
+ Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
+
+ // Retrieve the text.
+ if(0u != numberOfCharacters)
+ {
+ Utf32ToUtf8(mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text);
+ }
+}
+
+Dali::LayoutDirection::Type Controller::Impl::GetLayoutDirection(Dali::Actor& actor) const
+{
+ if(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
+ (mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mIsLayoutDirectionChanged))
+ {
+ Window window = DevelWindow::Get(actor);
+ return static_cast<Dali::LayoutDirection::Type>(window ? window.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>() : LayoutDirection::LEFT_TO_RIGHT);
+ }
+ else
+ {
+ return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+ }
+}
+
+Toolkit::DevelText::TextDirection::Type Controller::Impl::GetTextDirection()
+{
+ if(mUpdateTextDirection)
+ {
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
+ GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS);
+
+ // Set the update info to relayout the whole text.
+ mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ mTextUpdateInfo.mRequestedNumberOfCharacters = mModel->mLogicalModel->mText.Count();
+
+ // Make sure the model is up-to-date before layouting
+ UpdateModel(onlyOnceOperations);
+
+ Vector3 naturalSize;
+ Relayouter::DoRelayout(*this,
+ Size(MAX_FLOAT, MAX_FLOAT),
+ static_cast<OperationsMask>(onlyOnceOperations |
+ LAYOUT | REORDER | UPDATE_DIRECTION),
+ naturalSize.GetVectorXY());
+
+ // Do not do again the only once operations.
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending & ~onlyOnceOperations);
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ mTextUpdateInfo.Clear();
+
+ // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+ mTextUpdateInfo.mFullRelayoutNeeded = true;
+
+ mUpdateTextDirection = false;
+ }
+
+ return mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
+}
+
+void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
+{
+ mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ mTextUpdateInfo.mStartGlyphIndex = 0u;
+ mTextUpdateInfo.mStartLineIndex = 0u;
+ numberOfCharacters = 0u;
+
+ const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
+ if(0u == numberOfParagraphs)
+ {
+ mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ numberOfCharacters = 0u;
+
+ mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+ // Nothing else to do if there are no paragraphs.
+ return;
+ }
+
+ // Find the paragraphs to be updated.
+ Vector<ParagraphRunIndex> paragraphsToBeUpdated;
+ if(mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters)
+ {
+ // Text is being added at the end of the current text.
+ if(mTextUpdateInfo.mIsLastCharacterNewParagraph)
+ {
+ // Text is being added in a new paragraph after the last character of the text.
+ mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ numberOfCharacters = 0u;
+ mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+ mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
+ mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
+
+ // Nothing else to do;
+ return;
+ }
+
+ paragraphsToBeUpdated.PushBack(numberOfParagraphs - 1u);
+ }
+ else
+ {
+ Length numberOfCharactersToUpdate = 0u;
+ if(mTextUpdateInfo.mFullRelayoutNeeded)
+ {
+ numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ }
+ else
+ {
+ numberOfCharactersToUpdate = (mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
+ }
+ mModel->mLogicalModel->FindParagraphs(mTextUpdateInfo.mCharacterIndex,
+ numberOfCharactersToUpdate,
+ paragraphsToBeUpdated);
+ }
+
+ if(0u != paragraphsToBeUpdated.Count())
+ {
+ const ParagraphRunIndex firstParagraphIndex = *(paragraphsToBeUpdated.Begin());
+ const ParagraphRun& firstParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex);
+ mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
+
+ ParagraphRunIndex lastParagraphIndex = *(paragraphsToBeUpdated.End() - 1u);
+ const ParagraphRun& lastParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex);
+
+ if((mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) && // Some character are removed.
+ (lastParagraphIndex < numberOfParagraphs - 1u) && // There is a next paragraph.
+ ((lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters) == // The last removed character is the new paragraph character.
+ (mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove)))
+ {
+ // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
+ const ParagraphRun& lastParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u);
+
+ numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+ }
+ else
+ {
+ numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+ }
+ }
+
+ mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+ mTextUpdateInfo.mStartGlyphIndex = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex);
+}
+
+void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
+{
+ ControllerImplDataClearer::ClearModelData(*this, startIndex, endIndex, operations);
+}
+
+bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
+{
+ return ControllerImplModelUpdater::Update(*this, operationsRequired);
+}
+
+void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
+{
+ SetDefaultInputStyle(inputStyle, mFontDefaults, mTextColor);
+}
+
+float Controller::Impl::GetDefaultFontLineHeight()
+{
+ FontId defaultFontId = 0u;
+ if(nullptr == mFontDefaults)
+ {
+ TextAbstraction::FontDescription fontDescription;
+ defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * GetFontSizeScale());
+ }
+ else
+ {
+ defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * GetFontSizeScale());
+ }
+
+ Text::FontMetrics fontMetrics;
+ mMetrics->GetFontMetrics(defaultFontId, fontMetrics);
+
+ return (fontMetrics.ascender - fontMetrics.descender);
+}
+
+bool Controller::Impl::SetDefaultLineSpacing(float lineSpacing)
+{
+ if(std::fabs(lineSpacing - mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
+ {
+ mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
+
+ RelayoutAllCharacters();
+ return true;
+ }
+ return false;
+}
+
+bool Controller::Impl::SetDefaultLineSize(float lineSize)
+{
+ if(std::fabs(lineSize - mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
+ {
+ mLayoutEngine.SetDefaultLineSize(lineSize);
+
+ RelayoutAllCharacters();
+ return true;
+ }
+ return false;
+}
+
+bool Controller::Impl::SetRelativeLineSize(float relativeLineSize)
+{
+ if(std::fabs(relativeLineSize - GetRelativeLineSize()) > Math::MACHINE_EPSILON_1000)
+ {
+ mLayoutEngine.SetRelativeLineSize(relativeLineSize);
+
+ RelayoutAllCharacters();
+ return true;
+ }
+ return false;
+}
+
+float Controller::Impl::GetRelativeLineSize()
+{
+ return mLayoutEngine.GetRelativeLineSize();
+}
+
+string Controller::Impl::GetSelectedText()
+{
+ string text;
+ if(EventData::SELECTING == mEventData->mState)
+ {
+ RetrieveSelection(text, false);
+ }
+ return text;
+}
+
+string Controller::Impl::CopyText()
+{
+ string text;
+ RetrieveSelection(text, false);
+ SendSelectionToClipboard(false); // Text not modified
+
+ mEventData->mUpdateCursorPosition = true;
+
+ RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
+
+ return text;
+}
+
+string Controller::Impl::CutText()
+{
+ string text;
+ RetrieveSelection(text, false);
+
+ if(!IsEditable())
+ {
+ return EMPTY_STRING;
+ }
+
+ SendSelectionToClipboard(true); // Synchronous call to modify text
+ mOperationsPending = ALL_OPERATIONS;
+
+ if((0u != mModel->mLogicalModel->mText.Count()) ||
+ !IsPlaceholderAvailable())
+ {
+ QueueModifyEvent(ModifyEvent::TEXT_DELETED);
+ }
+ else
+ {
+ PlaceholderHandler::ShowPlaceholderText(*this);
+ }
+
+ mEventData->mUpdateCursorPosition = true;
+ mEventData->mScrollAfterDelete = true;
+
+ RequestRelayout();
+
+ if(nullptr != mEditableControlInterface)
+ {
+ mEditableControlInterface->TextChanged(true);
+ }
+ return text;
+}
+
+void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
+{
+ if(nullptr == mEventData)
+ {
+ // Nothing to do if there is no text.
+ return;
+ }
+
+ if(mEventData->mSelectionEnabled && (pStart || pEnd))
+ {
+ uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+ uint32_t oldStart = mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = mEventData->mRightSelectionPosition;
+
+ if(pStart)
+ {
+ mEventData->mLeftSelectionPosition = std::min(*pStart, length);
+ }
+ if(pEnd)
+ {
+ mEventData->mRightSelectionPosition = std::min(*pEnd, length);
+ }
+
+ if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
+ {
+ ChangeState(EventData::EDITING);
+ mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
+ mEventData->mUpdateCursorPosition = true;
+ }
+ else
+ {
+ ChangeState(EventData::SELECTING);
+ mEventData->mUpdateHighlightBox = true;
+ mEventData->mUpdateLeftSelectionPosition = true;
+ mEventData->mUpdateRightSelectionPosition = true;
+ }
+
+ if(mSelectableControlInterface != nullptr)
+ {
+ mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+ }
+ }
+}
+
+CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
+{
+ if(nullptr == mEventData)
+ {
+ return 0;
+ }
+ return mEventData->mPrimaryCursorPosition;
+}
+
+bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
+{
+ if(nullptr == mEventData)
+ {
+ // Nothing to do if there is no text.
+ return false;
+ }
+
+ if(mEventData->mPrimaryCursorPosition == index && mEventData->mState != EventData::SELECTING)
+ {
+ // Nothing for same cursor position.
+ return false;
+ }
+
+ uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+ uint32_t oldCursorPos = mEventData->mPrimaryCursorPosition;
+ mEventData->mPrimaryCursorPosition = std::min(index, length);
+ // If there is no focus, only the value is updated.
+ if(focused)
+ {
+ bool wasInSelectingState = mEventData->mState == EventData::SELECTING;
+ uint32_t oldStart = mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = mEventData->mRightSelectionPosition;
+ ChangeState(EventData::EDITING);
+ mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+ mEventData->mUpdateCursorPosition = true;
+
+ if(mSelectableControlInterface != nullptr && wasInSelectingState)
+ {
+ mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+ }
+
+ ScrollTextToMatchCursor();
+ }
+
+ if(nullptr != mEditableControlInterface)
+ {
+ mEditableControlInterface->CursorPositionChanged(oldCursorPos, mEventData->mPrimaryCursorPosition);
+ }
+
+ return true;
+}
+
+Uint32Pair Controller::Impl::GetTextSelectionRange() const
+{
+ Uint32Pair range;
+
+ if(mEventData)
+ {
+ range.first = mEventData->mLeftSelectionPosition;
+ range.second = mEventData->mRightSelectionPosition;
+ }
+
+ return range;
+}
+
+bool Controller::Impl::IsEditable() const
+{
+ return mEventData && mEventData->mEditingEnabled;
+}
+
+void Controller::Impl::SetEditable(bool editable)
+{
+ if(mEventData)
+ {
+ mEventData->mEditingEnabled = editable;
+
+ if(mEventData->mDecorator)
+ {
+ bool decoratorEditable = editable && mIsUserInteractionEnabled;
+ mEventData->mDecorator->SetEditable(decoratorEditable);
+ }
+ }
+}
+
+void Controller::Impl::UpdateAfterFontChange(const std::string& newDefaultFont)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
+
+ if(!mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
+ mFontDefaults->mFontDescription.family = newDefaultFont;
+
+ ClearFontData();
+
+ RequestRelayout();
+ }
+}
+
+void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
+{
+ if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
+ {
+ // Nothing to select if handles are in the same place.
+ selectedText.clear();
+ return;
+ }
+
+ const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
+
+ //Get start and end position of selection
+ const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+ const Length lengthOfSelectedText = (handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition) - startOfSelectedText;
+
+ Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
+ const Length numberOfCharacters = utf32Characters.Count();
+
+ // Validate the start and end selection points
+ if((startOfSelectedText + lengthOfSelectedText) <= numberOfCharacters)
+ {
+ //Get text as a UTF8 string
+ Utf32ToUtf8(&utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText);
+
+ if(deleteAfterRetrieval) // Only delete text if copied successfully
+ {
+ // Keep a copy of the current input style.
+ InputStyle currentInputStyle;
+ currentInputStyle.Copy(mEventData->mInputStyle);
+
+ // Set as input style the style of the first deleted character.
+ mModel->mLogicalModel->RetrieveStyle(startOfSelectedText, mEventData->mInputStyle);
+
+ // Compare if the input style has changed.
+ const bool hasInputStyleChanged = !currentInputStyle.Equal(mEventData->mInputStyle);
+
+ if(hasInputStyleChanged)
+ {
+ const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mEventData->mInputStyle);
+ // Queue the input style changed signal.
+ mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
+ }
+
+ mModel->mLogicalModel->UpdateTextStyleRuns(startOfSelectedText, -static_cast<int>(lengthOfSelectedText));
+
+ // Mark the paragraphs to be updated.
+ if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
+ {
+ mTextUpdateInfo.mCharacterIndex = 0;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
+ mTextUpdateInfo.mClearAll = true;
+ }
+ else
+ {
+ mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ }
+
+ // Delete text between handles
+ Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
+ Vector<Character>::Iterator last = first + lengthOfSelectedText;
+ utf32Characters.Erase(first, last);
+
+ // Will show the cursor at the first character of the selection.
+ mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+ }
+ else
+ {
+ // Will show the cursor at the last character of the selection.
+ mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
+ }
+
+ mEventData->mDecoratorUpdated = true;
+ }
+}
+
+void Controller::Impl::SetSelection(int start, int end)
+{
+ uint32_t oldStart = mEventData->mLeftSelectionPosition;
+ uint32_t oldEnd = mEventData->mRightSelectionPosition;
+
+ mEventData->mLeftSelectionPosition = start;
+ mEventData->mRightSelectionPosition = end;
+ mEventData->mUpdateCursorPosition = true;
+
+ if(mSelectableControlInterface != nullptr)
+ {
+ mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
+ }
+}
+
+std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
+{
+ return {mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition};
+}
+
+void Controller::Impl::ShowClipboard()
+{
+ if(mClipboard)
+ {
+ mClipboard.ShowClipboard();
+ }
+}
+
+void Controller::Impl::HideClipboard()
+{
+ if(mClipboard && mClipboardHideEnabled)
+ {
+ mClipboard.HideClipboard();
+ }
+}
+
+void Controller::Impl::SetClipboardHideEnable(bool enable)
+{
+ mClipboardHideEnabled = enable;
+}
+
+bool Controller::Impl::CopyStringToClipboard(const std::string& source)
+{
+ //Send string to clipboard
+ return (mClipboard && mClipboard.SetItem(source));
+}
+
+void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
+{
+ std::string selectedText;
+ RetrieveSelection(selectedText, deleteAfterSending);
+ CopyStringToClipboard(selectedText);
+ ChangeState(EventData::EDITING);
+}
+
+void Controller::Impl::RequestGetTextFromClipboard()
+{
+ if(mClipboard)
+ {
+ mClipboard.RequestItem();
+ }
+}
+
+void Controller::Impl::RepositionSelectionHandles()
+{
+ SelectionHandleController::Reposition(*this);
+}
+void Controller::Impl::RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action)
+{
+ SelectionHandleController::Reposition(*this, visualX, visualY, action);
+}
+
+void Controller::Impl::SetPopupButtons()
+{
+ /**
+ * Sets the Popup buttons to be shown depending on State.
+ *
+ * If SELECTING : CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
+ *
+ * If EDITING_WITH_POPUP : SELECT & SELECT_ALL
+ */
+
+ bool isEditable = IsEditable();
+ TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
+
+ if(EventData::SELECTING == mEventData->mState)
+ {
+ buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::COPY);
+ if(isEditable)
+ {
+ buttonsToShow = TextSelectionPopup::Buttons(buttonsToShow | TextSelectionPopup::CUT);
+ }
+
+ if(!IsClipboardEmpty())
+ {
+ if(isEditable)
+ {
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
+ }
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
+ }
+
+ if(!mEventData->mAllTextSelected)
+ {
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::SELECT_ALL));
+ }
+ }
+ else if(EventData::EDITING_WITH_POPUP == mEventData->mState)
+ {
+ if(mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
+ {
+ buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL);
+ }
+
+ if(!IsClipboardEmpty())
+ {
+ if(isEditable)
+ {
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
+ }
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
+ }
+ }
+ else if(EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState)
+ {
+ if(!IsClipboardEmpty())
+ {
+ if(isEditable)
+ {
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
+ }
+ buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
+ }
+ }
+
+ mEventData->mDecorator->SetEnabledPopupButtons(buttonsToShow);
+}
+
+void Controller::Impl::ChangeState(EventData::State newState)
+{
+ ChangeTextControllerState(*this, newState);
+}
+
+void Controller::Impl::GetCursorPosition(CharacterIndex logical,
+ CursorInfo& cursorInfo)
+{
+ if(!IsShowingRealText())
+ {
+ // Do not want to use the place-holder text to set the cursor position.
+
+ // Use the line's height of the font's family set to set the cursor's size.
+ // If there is no font's family set, use the default font.
+ // Use the current alignment to place the cursor at the beginning, center or end of the box.
+
+ cursorInfo.lineOffset = 0.f;
+ cursorInfo.lineHeight = GetDefaultFontLineHeight();
+ cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
+
+ bool isRTL = false;
+ if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
+ {
+ isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
+ }
+
+ switch(mModel->mHorizontalAlignment)
+ {
+ case Text::HorizontalAlignment::BEGIN:
+ {
+ if(isRTL)
+ {
+ cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+ }
+ else
+ {
+ cursorInfo.primaryPosition.x = 0.f;
+ }
+ break;
+ }
+ case Text::HorizontalAlignment::CENTER:
+ {
+ cursorInfo.primaryPosition.x = floorf(0.5f * mModel->mVisualModel->mControlSize.width);
+ break;
+ }
+ case Text::HorizontalAlignment::END:
+ {
+ if(isRTL)
+ {
+ cursorInfo.primaryPosition.x = 0.f;
+ }
+ else
+ {
+ cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+ }
+ break;
+ }
+ }
+
+ // Nothing else to do.
+ return;
+ }
+
+ const bool isMultiLine = (Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout());
+ GetCursorPositionParameters parameters;
+ parameters.visualModel = mModel->mVisualModel;
+ parameters.logicalModel = mModel->mLogicalModel;
+ parameters.metrics = mMetrics;
+ parameters.logical = logical;
+ parameters.isMultiline = isMultiLine;
+
+ float defaultFontLineHeight = GetDefaultFontLineHeight();
+
+ Text::GetCursorPosition(parameters,
+ defaultFontLineHeight,
+ cursorInfo);
+
+ // Adds Outline offset.
+ const float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
+ cursorInfo.primaryPosition.x += outlineWidth;
+ cursorInfo.primaryPosition.y += outlineWidth;
+ cursorInfo.secondaryPosition.x += outlineWidth;
+ cursorInfo.secondaryPosition.y += outlineWidth;
+
+ if(isMultiLine)
+ {
+ // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
+
+ // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
+ // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
+
+ if(0.f > cursorInfo.primaryPosition.x)
+ {
+ cursorInfo.primaryPosition.x = 0.f;
+ }
+
+ const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>(mEventData->mDecorator->GetCursorWidth());
+ if(cursorInfo.primaryPosition.x > edgeWidth)
+ {
+ cursorInfo.primaryPosition.x = edgeWidth;
+ }
+ }
+}
+
+CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
+{
+ if(nullptr == mEventData)
+ {
+ // Nothing to do if there is no text input.
+ return 0u;
+ }
+
+ CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
+
+ const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
+ const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
+
+ GlyphIndex glyphIndex = *(charactersToGlyphBuffer + index);
+ Length numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
+
+ if(numberOfCharacters > 1u)
+ {
+ const Script script = mModel->mLogicalModel->GetScript(index);
+ if(HasLigatureMustBreak(script))
+ {
+ // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
+ numberOfCharacters = 1u;
+ }
+ }
+ else
+ {
+ while(0u == numberOfCharacters)
+ {
+ ++glyphIndex;
+ numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
+ }
+ }
+
+ if(index < mEventData->mPrimaryCursorPosition)
+ {
+ cursorIndex -= numberOfCharacters;
+ }
+ else
+ {
+ cursorIndex += numberOfCharacters;
+ }
+
+ // Will update the cursor hook position.
+ mEventData->mUpdateCursorHookPosition = true;
+
+ return cursorIndex;
+}
+
+void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
+ if(nullptr == mEventData)
+ {
+ // Nothing to do if there is no text input.
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
+ return;
+ }
+
+ const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
+
+ mEventData->mDecorator->SetGlyphOffset(PRIMARY_CURSOR, cursorInfo.glyphOffset);
+
+ // Sets the cursor position.
+ mEventData->mDecorator->SetPosition(PRIMARY_CURSOR,
+ cursorPosition.x,
+ cursorPosition.y,
+ cursorInfo.primaryCursorHeight,
+ cursorInfo.lineHeight);
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y);
+
+ if(mEventData->mUpdateGrabHandlePosition)
+ {
+ // Sets the grab handle position.
+ mEventData->mDecorator->SetPosition(GRAB_HANDLE,
+ cursorPosition.x,
+ cursorInfo.lineOffset + mModel->mScrollPosition.y,
+ cursorInfo.lineHeight);
+ }
+
+ if(cursorInfo.isSecondaryCursor)
+ {
+ mEventData->mDecorator->SetPosition(SECONDARY_CURSOR,
+ cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
+ cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
+ cursorInfo.secondaryCursorHeight,
+ cursorInfo.lineHeight);
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y);
+ }
+
+ // Set which cursors are active according the state.
+ if(EventData::IsEditingState(mEventData->mState) || (EventData::GRAB_HANDLE_PANNING == mEventData->mState))
+ {
+ if(cursorInfo.isSecondaryCursor)
+ {
+ mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_BOTH);
+ }
+ else
+ {
+ mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+ }
+ }
+ else
+ {
+ mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+ }
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n");
+}
+
+void Controller::Impl::UpdateSelectionHandle(HandleType handleType,
+ const CursorInfo& cursorInfo)
+{
+ SelectionHandleController::Update(*this, handleType, cursorInfo);
+}
+
+void Controller::Impl::ClampHorizontalScroll(const Vector2& layoutSize)
+{
+ // Clamp between -space & -alignment offset.
+
+ if(layoutSize.width > mModel->mVisualModel->mControlSize.width)
+ {
+ const float space = (layoutSize.width - mModel->mVisualModel->mControlSize.width) + mModel->mAlignmentOffset;
+ mModel->mScrollPosition.x = (mModel->mScrollPosition.x < -space) ? -space : mModel->mScrollPosition.x;
+ mModel->mScrollPosition.x = (mModel->mScrollPosition.x > -mModel->mAlignmentOffset) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
+
+ mEventData->mDecoratorUpdated = true;
+ }
+ else
+ {
+ mModel->mScrollPosition.x = 0.f;
+ }
+}
+
+void Controller::Impl::ClampVerticalScroll(const Vector2& layoutSize)
+{
+ if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
+ {
+ // Nothing to do if the text is single line.
+ return;
+ }
+
+ // Clamp between -space & 0.
+ if(layoutSize.height > mModel->mVisualModel->mControlSize.height)
+ {
+ const float space = (layoutSize.height - mModel->mVisualModel->mControlSize.height);
+ mModel->mScrollPosition.y = (mModel->mScrollPosition.y < -space) ? -space : mModel->mScrollPosition.y;
+ mModel->mScrollPosition.y = (mModel->mScrollPosition.y > 0.f) ? 0.f : mModel->mScrollPosition.y;
+
+ mEventData->mDecoratorUpdated = true;
+ }
+ else
+ {
+ mModel->mScrollPosition.y = 0.f;
+ }
+}
+
+void Controller::Impl::ScrollToMakePositionVisible(const Vector2& position, float lineHeight)
+{
+ const float cursorWidth = mEventData->mDecorator ? static_cast<float>(mEventData->mDecorator->GetCursorWidth()) : 0.f;
+
+ // position is in actor's coords.
+ const float positionEndX = position.x + cursorWidth;
+ const float positionEndY = position.y + lineHeight;
+
+ // Transform the position to decorator coords.
+ const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
+ const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
+
+ const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
+ const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
+
+ if(decoratorPositionBeginX < 0.f)
+ {
+ mModel->mScrollPosition.x = -position.x;
+ }
+ else if(decoratorPositionEndX > mModel->mVisualModel->mControlSize.width)
+ {
+ mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
+ }
+
+ if(Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout())
+ {
+ if(decoratorPositionBeginY < 0.f)
+ {
+ mModel->mScrollPosition.y = -position.y;
+ }
+ else if(decoratorPositionEndY > mModel->mVisualModel->mControlSize.height)
+ {
+ mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
+ }
+ else if(mModel->mLogicalModel->mText.Count() == 0u)
+ {
+ Relayouter::CalculateVerticalOffset(*this, mModel->mVisualModel->mControlSize);
+ }
+ }
+}
+
+void Controller::Impl::ScrollTextToMatchCursor(const CursorInfo& cursorInfo)
+{
+ // Get the current cursor position in decorator coords.
+ const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
+
+ const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter(mEventData->mPrimaryCursorPosition);
+
+ // Calculate the offset to match the cursor position before the character was deleted.
+ mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
+
+ //If text control has more than two lines and current line index is not last, calculate scrollpositionY
+ if(mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() - 1u)
+ {
+ const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset(PRIMARY_CURSOR);
+ mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
+ }
+
+ ClampHorizontalScroll(mModel->mVisualModel->GetLayoutSize());
+ ClampVerticalScroll(mModel->mVisualModel->GetLayoutSize());
+
+ // Makes the new cursor position visible if needed.
+ ScrollToMakePositionVisible(cursorInfo.primaryPosition, cursorInfo.lineHeight);
+}
+
+void Controller::Impl::ScrollTextToMatchCursor()
+{
+ CursorInfo cursorInfo;
+ GetCursorPosition(mEventData->mPrimaryCursorPosition, cursorInfo);
+ ScrollTextToMatchCursor(cursorInfo);
+}
+
+void Controller::Impl::RequestRelayout()
+{
+ if(nullptr != mControlInterface)
+ {
+ mControlInterface->RequestTextRelayout();
+ }
+}
+
+void Controller::Impl::RelayoutAllCharacters()
+{
+ // relayout all characters
+ mTextUpdateInfo.mCharacterIndex = 0;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count();
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending | LAYOUT);
+
+ mTextUpdateInfo.mFullRelayoutNeeded = true;
+
+ // Need to recalculate natural size
+ mRecalculateNaturalSize = true;
+
+ //remove selection
+ if((mEventData != nullptr) && (mEventData->mState == EventData::SELECTING))
+ {
+ ChangeState(EventData::EDITING);
+ }
+
+ RequestRelayout();
+}
+
+bool Controller::Impl::IsInputStyleChangedSignalsQueueEmpty()
+{
+ return (NULL == mEventData) || (0u == mEventData->mInputStyleChangedQueue.Count());
+}
+
+void Controller::Impl::ProcessInputStyleChangedSignals()
+{
+ if(mEventData)
+ {
+ if(mEditableControlInterface)
+ {
+ // Emit the input style changed signal for each mask
+ std::for_each(mEventData->mInputStyleChangedQueue.begin(),
+ mEventData->mInputStyleChangedQueue.end(),
+ [&](const auto mask) { mEditableControlInterface->InputStyleChanged(mask); });
+ }
+
+ mEventData->mInputStyleChangedQueue.Clear();
+ }
+}
+
+void Controller::Impl::ScrollBy(Vector2 scroll)
+{
+ if(mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
+ {
+ const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
+ const Vector2 currentScroll = mModel->mScrollPosition;
+
+ scroll.x = -scroll.x;
+ scroll.y = -scroll.y;
+
+ if(fabs(scroll.x) > Math::MACHINE_EPSILON_0)
+ {
+ mModel->mScrollPosition.x += scroll.x;
+ ClampHorizontalScroll(layoutSize);
+ }
+
+ if(fabs(scroll.y) > Math::MACHINE_EPSILON_0)
+ {
+ mModel->mScrollPosition.y += scroll.y;
+ ClampVerticalScroll(layoutSize);
+ }
+
+ if(mModel->mScrollPosition != currentScroll)
+ {
+ mEventData->mDecorator->UpdatePositions(mModel->mScrollPosition - currentScroll);
+ RequestRelayout();
+ }
+ }
+}
+
+bool Controller::Impl::IsScrollable(const Vector2& displacement)
+{
+ bool isScrollable = false;
+ if(mEventData)
+ {
+ const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
+ const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
+ if(isHorizontalScrollEnabled ||isVerticalScrollEnabled)
+ {
+ const Vector2& targetSize = mModel->mVisualModel->mControlSize;
+ const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
+ const Vector2& scrollPosition = mModel->mScrollPosition;
+
+ if(isHorizontalScrollEnabled)
+ {
+ const float displacementX = displacement.x;
+ const float positionX = scrollPosition.x + displacementX;
+ if(layoutSize.width > targetSize.width && -positionX > 0.f && -positionX < layoutSize.width - targetSize.width)
+ {
+ isScrollable = true;
+ }
+ }
+
+ if(isVerticalScrollEnabled)
+ {
+ const float displacementY = displacement.y;
+ const float positionY = scrollPosition.y + displacementY;
+ if(layoutSize.height > targetSize.height && -positionY > 0 && -positionY < layoutSize.height - targetSize.height)
+ {
+ isScrollable = true;
+ }
+ }
+ }
+ }
+ return isScrollable;
+}
+
+float Controller::Impl::GetHorizontalScrollPosition()
+{
+ // Scroll values are negative internally so we convert them to positive numbers
+ return mEventData ? -mModel->mScrollPosition.x : 0.0f;
+}
+
+float Controller::Impl::GetVerticalScrollPosition()
+{
+ // Scroll values are negative internally so we convert them to positive numbers
+ return mEventData ? -mModel->mScrollPosition.y : 0.0f;
+}
+
+Vector3 Controller::Impl::GetAnchorPosition(Anchor anchor) const
+{
+ //TODO
+ return Vector3(10.f, 10.f, 10.f);
+}
+
+Vector2 Controller::Impl::GetAnchorSize(Anchor anchor) const
+{
+ //TODO
+ return Vector2(10.f, 10.f);
+}
+
+Toolkit::TextAnchor Controller::Impl::CreateAnchorActor(Anchor anchor)
+{
+ auto actor = Toolkit::TextAnchor::New();
+ actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ const Vector3 anchorPosition = GetAnchorPosition(anchor);
+ actor.SetProperty(Actor::Property::POSITION, anchorPosition);
+ const Vector2 anchorSize = GetAnchorSize(anchor);
+ actor.SetProperty(Actor::Property::SIZE, anchorSize);
+ std::string anchorText(mModel->mLogicalModel->mText.Begin() + anchor.startIndex, mModel->mLogicalModel->mText.Begin() + anchor.endIndex);
+ actor.SetProperty(Actor::Property::NAME, anchorText);
+ actor.SetProperty(Toolkit::TextAnchor::Property::URI, std::string(anchor.href));
+ actor.SetProperty(Toolkit::TextAnchor::Property::START_CHARACTER_INDEX, static_cast<int>(anchor.startIndex));
+ actor.SetProperty(Toolkit::TextAnchor::Property::END_CHARACTER_INDEX, static_cast<int>(anchor.endIndex));
+ return actor;
+}
+
+void Controller::Impl::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
+{
+ /* TODO: Now actors are created/destroyed in every "RenderText" function call. Even when we add just 1 character,
+ we need to create and destroy potentially many actors. Some optimization can be considered here.
+ Maybe a "dirty" flag in mLogicalModel? */
+ anchorActors.clear();
+ for(auto& anchor : mModel->mLogicalModel->mAnchors)
+ {
+ auto actor = CreateAnchorActor(anchor);
+ anchorActors.push_back(actor);
+ }
+}
+
+int32_t Controller::Impl::GetAnchorIndex(size_t characterOffset) const
+{
+ Vector<Anchor>::Iterator it = mModel->mLogicalModel->mAnchors.Begin();
+
+ while(it != mModel->mLogicalModel->mAnchors.End() && (it->startIndex > characterOffset || it->endIndex <= characterOffset))
+ {
+ it++;
+ }
+
+ return it == mModel->mLogicalModel->mAnchors.End() ? -1 : it - mModel->mLogicalModel->mAnchors.Begin();
+}
+
+void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
+{
+ //Underlined character runs for markup-processor
+ const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ if(shouldClearPreUnderlineRuns)
+ {
+ mModel->mVisualModel->mUnderlineRuns.Clear();
+ }
+
+ for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+ {
+ CharacterIndex characterIndex = it->characterRun.characterIndex;
+ Length numberOfCharacters = it->characterRun.numberOfCharacters;
+
+ if(numberOfCharacters == 0)
+ {
+ continue;
+ }
+
+ // Create one run for all glyphs of all run's characters that has same properties
+ // This enhance performance and reduce the needed memory to store glyphs-runs
+ UnderlinedGlyphRun underlineGlyphRun;
+ underlineGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
+ underlineGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+ //Copy properties (attributes)
+ underlineGlyphRun.properties = it->properties;
+
+ for(Length index = 1u; index < numberOfCharacters; index++)
+ {
+ underlineGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
+ }
+
+ mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+ }
+}
+
+void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels()
+{
+ //Strikethrough character runs from markup-processor
+ const Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns = mModel->mLogicalModel->mStrikethroughCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ mModel->mVisualModel->mStrikethroughRuns.Clear();
+
+ for(Vector<StrikethroughCharacterRun>::ConstIterator it = strikethroughCharacterRuns.Begin(), endIt = strikethroughCharacterRuns.End(); it != endIt; ++it)
+ {
+ CharacterIndex characterIndex = it->characterRun.characterIndex;
+ Length numberOfCharacters = it->characterRun.numberOfCharacters;
+
+ if(numberOfCharacters == 0)
+ {
+ continue;
+ }
+
+ StrikethroughGlyphRun strikethroughGlyphRun;
+ strikethroughGlyphRun.properties = it->properties;
+ strikethroughGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
+ strikethroughGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+
+ for(Length index = 1u; index < numberOfCharacters; index++)
+ {
+ strikethroughGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
+ }
+
+ mModel->mVisualModel->mStrikethroughRuns.PushBack(strikethroughGlyphRun);
+ }
+}
+
+void Controller::Impl::CopyCharacterSpacingFromLogicalToVisualModels()
+{
+ //CharacterSpacing character runs from markup-processor
+ const Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns = mModel->mLogicalModel->mCharacterSpacingCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ mModel->mVisualModel->mCharacterSpacingRuns.Clear();
+
+ for(Vector<CharacterSpacingCharacterRun>::ConstIterator it = characterSpacingCharacterRuns.Begin(), endIt = characterSpacingCharacterRuns.End(); it != endIt; ++it)
+ {
+ const CharacterIndex& characterIndex = it->characterRun.characterIndex;
+ const Length& numberOfCharacters = it->characterRun.numberOfCharacters;
+
+ if(numberOfCharacters == 0)
+ {
+ continue;
+ }
+
+ CharacterSpacingGlyphRun characterSpacingGlyphRun;
+ characterSpacingGlyphRun.value = it->value;
+ characterSpacingGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
+ characterSpacingGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+
+ for(Length index = 1u; index < numberOfCharacters; index++)
+ {
+ characterSpacingGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
+ }
+
+ mModel->mVisualModel->mCharacterSpacingRuns.PushBack(characterSpacingGlyphRun);
+ }
+}
+
+void Controller::Impl::SetAutoScrollEnabled(bool enable)
+{
+ if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
+ {
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+ LAYOUT |
+ ALIGN |
+ UPDATE_LAYOUT_SIZE |
+ REORDER);
+
+ if(enable)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending | UPDATE_DIRECTION);
+ }
+ else
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
+ }
+
+ mIsAutoScrollEnabled = enable;
+ RequestRelayout();
+ }
+ else
+ {
+ DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
+ mIsAutoScrollEnabled = false;
+ }
+}
+
+void Controller::Impl::SetEnableCursorBlink(bool enable)
+{
+ DALI_ASSERT_DEBUG(NULL != mEventData && "TextInput disabled");
+
+ if(mEventData)
+ {
+ mEventData->mCursorBlinkEnabled = enable;
+
+ if(!enable && mEventData->mDecorator)
+ {
+ mEventData->mDecorator->StopCursorBlink();
+ }
+ }
+}
+
+void Controller::Impl::SetMultiLineEnabled(bool enable)
+{
+ const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
+
+ if(layout != mLayoutEngine.GetLayout())
+ {
+ // Set the layout type.
+ mLayoutEngine.SetLayout(layout);
+
+ // Set the flags to redo the layout operations
+ const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ ALIGN |
+ REORDER);
+
+ mTextUpdateInfo.mFullRelayoutNeeded = true;
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending | layoutOperations);
+
+ // Need to recalculate natural size
+ mRecalculateNaturalSize = true;
+
+ RequestRelayout();
+ }
+}
+
+void Controller::Impl::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
+{
+ if(alignment != mModel->mHorizontalAlignment)
+ {
+ // Set the alignment.
+ mModel->mHorizontalAlignment = alignment;
+ UpdateCursorPositionForAlignment(*this, true);
+ RequestRelayout();
+ }
+}
+
+void Controller::Impl::SetVerticalAlignment(VerticalAlignment::Type alignment)
+{
+ if(alignment != mModel->mVerticalAlignment)
+ {
+ // Set the alignment.
+ mModel->mVerticalAlignment = alignment;
+ UpdateCursorPositionForAlignment(*this, false);
+ RequestRelayout();
+ }
+}
+
+void Controller::Impl::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
+{
+ if(lineWrapMode != mModel->mLineWrapMode)
+ {
+ // Update Text layout for applying wrap mode
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+ ALIGN |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER);
+
+ if((mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ (mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
+ {
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending | GET_LINE_BREAKS);
+ }
+
+ // Set the text wrap mode.
+ mModel->mLineWrapMode = lineWrapMode;
+
+ mTextUpdateInfo.mCharacterIndex = 0u;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count();
+
+ // Request relayout
+ RequestRelayout();
+ }
+}
+
+void Controller::Impl::SetDefaultColor(const Vector4& color)
+{
+ mTextColor = color;
+
+ if(!IsShowingPlaceholderText())
+ {
+ mModel->mVisualModel->SetTextColor(color);
+ mModel->mLogicalModel->mColorRuns.Clear();
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending | COLOR);
+ RequestRelayout();
+ }
+}
+
+void Controller::Impl::SetUserInteractionEnabled(bool enabled)
+{
+ mIsUserInteractionEnabled = enabled;
+
+ if(mEventData && mEventData->mDecorator)
+ {
+ bool editable = mEventData->mEditingEnabled && enabled;
+ mEventData->mDecorator->SetEditable(editable);
+ }
+}
+
+void Controller::Impl::ClearFontData()
+{
+ if(mFontDefaults)
+ {
+ mFontDefaults->mFontId = 0u; // Remove old font ID
+ }
+
+ // Set flags to update the model.
+ mTextUpdateInfo.mCharacterIndex = 0u;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count();
+
+ mTextUpdateInfo.mClearAll = true;
+ mTextUpdateInfo.mFullRelayoutNeeded = true;
+ mRecalculateNaturalSize = true;
+
+ mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ BIDI_INFO |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN);
+}
+
+void Controller::Impl::ClearStyleData()
+{
+ mModel->mLogicalModel->mColorRuns.Clear();
+ mModel->mLogicalModel->ClearFontDescriptionRuns();
+ mModel->mLogicalModel->ClearStrikethroughRuns();
+}
+
+void Controller::Impl::ResetScrollPosition()
+{
+ if(mEventData)
+ {
+ // Reset the scroll position.
+ mModel->mScrollPosition = Vector2::ZERO;
+ mEventData->mScrollAfterUpdatePosition = true;
+ }
+}
+
+} // namespace Dali::Toolkit::Text
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/clipboard.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
+#include <dali-toolkit/internal/text/input-style.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/text-model.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+const float DEFAULT_TEXTFIT_MIN = 10.f;
+const float DEFAULT_TEXTFIT_MAX = 100.f;
+const float DEFAULT_TEXTFIT_STEP = 1.f;
+const float DEFAULT_FONT_SIZE_SCALE = 1.f;
+const float DEFAULT_DISABLED_COLOR_OPACITY = 0.3f;
+
+//Forward declarations
+struct CursorInfo;
+struct FontDefaults;
+struct ControllerImplEventHandler;
+struct ControllerImplModelUpdater;
+struct SelectionHandleController;
+
+class SelectableControlInterface;
+class AnchorControlInterface;
+
+struct Event
+{
+ // Used to queue input events until DoRelayout()
+ enum Type
+ {
+ CURSOR_KEY_EVENT,
+ TAP_EVENT,
+ PAN_EVENT,
+ LONG_PRESS_EVENT,
+ GRAB_HANDLE_EVENT,
+ LEFT_SELECTION_HANDLE_EVENT,
+ RIGHT_SELECTION_HANDLE_EVENT,
+ SELECT,
+ SELECT_ALL,
+ SELECT_NONE,
+ SELECT_RANGE,
+ };
+
+ union Param
+ {
+ int mInt;
+ unsigned int mUint;
+ float mFloat;
+ bool mBool;
+ };
+
+ Event(Type eventType)
+ : type(eventType)
+ {
+ p1.mInt = 0;
+ p2.mInt = 0;
+ p3.mInt = 0;
+ }
+
+ Type type;
+ Param p1;
+ Param p2;
+ Param p3;
+};
+
+struct EventData
+{
+ enum State
+ {
+ INACTIVE,
+ INTERRUPTED,
+ SELECTING,
+ EDITING,
+ EDITING_WITH_POPUP,
+ EDITING_WITH_GRAB_HANDLE,
+ EDITING_WITH_PASTE_POPUP,
+ GRAB_HANDLE_PANNING,
+ SELECTION_HANDLE_PANNING,
+ TEXT_PANNING
+ };
+
+ EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext);
+
+ ~EventData() = default;
+
+ static bool IsEditingState(State stateToCheck)
+ {
+ return (stateToCheck == EDITING || stateToCheck == EDITING_WITH_POPUP || stateToCheck == EDITING_WITH_GRAB_HANDLE || stateToCheck == EDITING_WITH_PASTE_POPUP);
+ }
+
+ DecoratorPtr mDecorator; ///< Pointer to the decorator.
+ InputMethodContext mInputMethodContext; ///< The Input Method Framework Manager.
+ std::unique_ptr<FontDefaults> mPlaceholderFont; ///< The placeholder default font.
+ std::string mPlaceholderTextActive; ///< The text to display when the TextField is empty with key-input focus.
+ std::string mPlaceholderTextInactive; ///< The text to display when the TextField is empty and inactive.
+ Vector4 mPlaceholderTextColor; ///< The in/active placeholder text color.
+
+ /**
+ * This is used to delay handling events until after the model has been updated.
+ * The number of updates to the model is minimized to improve performance.
+ */
+ std::vector<Event> mEventQueue; ///< The queue of touch events etc.
+
+ Vector<InputStyle::Mask> mInputStyleChangedQueue; ///< Queue of changes in the input style. Used to emit the signal in the iddle callback.
+
+ InputStyle mInputStyle; ///< The style to be set to the new inputed text.
+
+ State mPreviousState; ///< Stores the current state before it's updated with the new one.
+ State mState; ///< Selection mode, edit mode etc.
+
+ CharacterIndex mPrimaryCursorPosition; ///< Index into logical model for primary cursor.
+ CharacterIndex mLeftSelectionPosition; ///< Index into logical model for left selection handle.
+ CharacterIndex mRightSelectionPosition; ///< Index into logical model for right selection handle.
+
+ CharacterIndex mPreEditStartPosition; ///< Used to remove the pre-edit text if necessary.
+ Length mPreEditLength; ///< Used to remove the pre-edit text if necessary.
+
+ float mCursorHookPositionX; ///< Used to move the cursor with the keys or when scrolling the text vertically with the handles.
+
+ Controller::NoTextTap::Action mDoubleTapAction; ///< Action to be done when there is a double tap on top of 'no text'
+ Controller::NoTextTap::Action mLongPressAction; ///< Action to be done when there is a long press on top of 'no text'
+
+ bool mIsShowingPlaceholderText : 1; ///< True if the place-holder text is being displayed.
+ bool mPreEditFlag : 1; ///< True if the model contains text in pre-edit state.
+ bool mDecoratorUpdated : 1; ///< True if the decorator was updated during event processing.
+ bool mCursorBlinkEnabled : 1; ///< True if cursor should blink when active.
+ bool mGrabHandleEnabled : 1; ///< True if grab handle is enabled.
+ bool mGrabHandlePopupEnabled : 1; ///< True if the grab handle popu-up should be shown.
+ bool mSelectionEnabled : 1; ///< True if selection handles, highlight etc. are enabled.
+ bool mUpdateCursorHookPosition : 1; ///< True if the cursor hook position must be updated. Used to move the cursor with the keys 'up' and 'down'.
+ bool mUpdateCursorPosition : 1; ///< True if the visual position of the cursor must be recalculated.
+ bool mUpdateGrabHandlePosition : 1; ///< True if the visual position of the grab handle must be recalculated.
+ bool mUpdateLeftSelectionPosition : 1; ///< True if the visual position of the left selection handle must be recalculated.
+ bool mUpdateRightSelectionPosition : 1; ///< True if the visual position of the right selection handle must be recalculated.
+ bool mIsLeftHandleSelected : 1; ///< Whether is the left handle the one which is selected.
+ bool mIsRightHandleSelected : 1; ///< Whether is the right handle the one which is selected.
+ bool mUpdateHighlightBox : 1; ///< True if the text selection high light box must be updated.
+ bool mScrollAfterUpdatePosition : 1; ///< Whether to scroll after the cursor position is updated.
+ bool mScrollAfterDelete : 1; ///< Whether to scroll after delete characters.
+ bool mAllTextSelected : 1; ///< True if the selection handles are selecting all the text.
+ bool mUpdateInputStyle : 1; ///< Whether to update the input style after moving the cursor.
+ bool mPasswordInput : 1; ///< True if password input is enabled.
+ bool mCheckScrollAmount : 1; ///< Whether to check scrolled amount after updating the position
+ bool mIsPlaceholderPixelSize : 1; ///< True if the placeholder font size is set as pixel size.
+ bool mIsPlaceholderElideEnabled : 1; ///< True if the placeholder text's elide is enabled.
+ bool mPlaceholderEllipsisFlag : 1; ///< True if the text controller sets the placeholder ellipsis.
+ bool mShiftSelectionFlag : 1; ///< True if the text selection using Shift key is enabled.
+ bool mUpdateAlignment : 1; ///< True if the whole text needs to be full aligned..
+ bool mEditingEnabled : 1; ///< True if the editing is enabled, false otherwise.
+};
+
+struct ModifyEvent
+{
+ enum Type
+ {
+ TEXT_REPLACED, ///< The entire text was replaced
+ TEXT_INSERTED, ///< Insert characters at the current cursor position
+ TEXT_DELETED ///< Characters were deleted
+ };
+
+ Type type;
+};
+
+struct FontDefaults
+{
+ FontDefaults()
+ : mFontDescription(),
+ mDefaultPointSize(0.f),
+ mFitPointSize(0.f),
+ mFontId(0u),
+ familyDefined(false),
+ weightDefined(false),
+ widthDefined(false),
+ slantDefined(false),
+ sizeDefined(false)
+ {
+ // Initially use the default platform font
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.GetDefaultPlatformFontDescription(mFontDescription);
+ }
+
+ FontId GetFontId(TextAbstraction::FontClient& fontClient, float fontPointSize)
+ {
+ if(!mFontId)
+ {
+ const PointSize26Dot6 pointSize = static_cast<PointSize26Dot6>(fontPointSize * 64.f);
+ mFontId = fontClient.GetFontId(mFontDescription, pointSize);
+ }
+
+ return mFontId;
+ }
+
+ TextAbstraction::FontDescription mFontDescription; ///< The default font's description.
+ float mDefaultPointSize; ///< The default font's point size.
+ float mFitPointSize; ///< The fit font's point size.
+ FontId mFontId; ///< The font's id of the default font.
+ bool familyDefined : 1; ///< Whether the default font's family name is defined.
+ bool weightDefined : 1; ///< Whether the default font's weight is defined.
+ bool widthDefined : 1; ///< Whether the default font's width is defined.
+ bool slantDefined : 1; ///< Whether the default font's slant is defined.
+ bool sizeDefined : 1; ///< Whether the default font's point size is defined.
+};
+
+/**
+ * @brief Stores indices used to update the text.
+ * Stores the character index where the text is updated and the number of characters removed and added.
+ * Stores as well indices to the first and the last paragraphs to be updated.
+ */
+struct TextUpdateInfo
+{
+ TextUpdateInfo()
+ : mCharacterIndex(0u),
+ mNumberOfCharactersToRemove(0u),
+ mNumberOfCharactersToAdd(0u),
+ mPreviousNumberOfCharacters(0u),
+ mParagraphCharacterIndex(0u),
+ mRequestedNumberOfCharacters(0u),
+ mStartGlyphIndex(0u),
+ mStartLineIndex(0u),
+ mEstimatedNumberOfLines(0u),
+ mClearAll(true),
+ mFullRelayoutNeeded(true),
+ mIsLastCharacterNewParagraph(false)
+ {
+ }
+
+ ~TextUpdateInfo()
+ {
+ }
+
+ CharacterIndex mCharacterIndex; ///< Index to the first character to be updated.
+ Length mNumberOfCharactersToRemove; ///< The number of characters to be removed.
+ Length mNumberOfCharactersToAdd; ///< The number of characters to be added.
+ Length mPreviousNumberOfCharacters; ///< The number of characters before the text update.
+
+ CharacterIndex mParagraphCharacterIndex; ///< Index of the first character of the first paragraph to be updated.
+ Length mRequestedNumberOfCharacters; ///< The requested number of characters.
+ GlyphIndex mStartGlyphIndex;
+ LineIndex mStartLineIndex;
+ Length mEstimatedNumberOfLines; ///< The estimated number of lines. Used to avoid reallocations when layouting.
+
+ bool mClearAll : 1; ///< Whether the whole text is cleared. i.e. when the text is reset.
+ bool mFullRelayoutNeeded : 1; ///< Whether a full re-layout is needed. i.e. when a new size is set to the text control.
+ bool mIsLastCharacterNewParagraph : 1; ///< Whether the last character is a new paragraph character.
+
+ void Clear()
+ {
+ // Clear all info except the mPreviousNumberOfCharacters member.
+ mCharacterIndex = static_cast<CharacterIndex>(-1);
+ mNumberOfCharactersToRemove = 0u;
+ mNumberOfCharactersToAdd = 0u;
+ mParagraphCharacterIndex = 0u;
+ mRequestedNumberOfCharacters = 0u;
+ mStartGlyphIndex = 0u;
+ mStartLineIndex = 0u;
+ mEstimatedNumberOfLines = 0u;
+ mClearAll = false;
+ mFullRelayoutNeeded = false;
+ mIsLastCharacterNewParagraph = false;
+ }
+};
+
+struct UnderlineDefaults
+{
+ std::string properties;
+ // TODO: complete with underline parameters.
+};
+
+struct ShadowDefaults
+{
+ std::string properties;
+ // TODO: complete with shadow parameters.
+};
+
+struct EmbossDefaults
+{
+ std::string properties;
+ // TODO: complete with emboss parameters.
+};
+
+struct OutlineDefaults
+{
+ std::string properties;
+ // TODO: complete with outline parameters.
+};
+
+struct Controller::Impl
+{
+ Impl(ControlInterface* controlInterface,
+ EditableControlInterface* editableControlInterface,
+ SelectableControlInterface* selectableControlInterface,
+ AnchorControlInterface* anchorControlInterface)
+ : mControlInterface(controlInterface),
+ mEditableControlInterface(editableControlInterface),
+ mSelectableControlInterface(selectableControlInterface),
+ mAnchorControlInterface(anchorControlInterface),
+ mModel(),
+ mFontDefaults(NULL),
+ mUnderlineDefaults(NULL),
+ mShadowDefaults(NULL),
+ mEmbossDefaults(NULL),
+ mOutlineDefaults(NULL),
+ mEventData(NULL),
+ mFontClient(),
+ mClipboard(),
+ mView(),
+ mMetrics(),
+ mModifyEvents(),
+ mTextColor(Color::BLACK),
+ mTextUpdateInfo(),
+ mOperationsPending(NO_OPERATION),
+ mMaximumNumberOfCharacters(50u),
+ mHiddenInput(NULL),
+ mInputFilter(nullptr),
+ mRecalculateNaturalSize(true),
+ mMarkupProcessorEnabled(false),
+ mClipboardHideEnabled(true),
+ mIsAutoScrollEnabled(false),
+ mIsAutoScrollMaxTextureExceeded(false),
+ mUpdateTextDirection(true),
+ mIsTextDirectionRTL(false),
+ mUnderlineSetByString(false),
+ mShadowSetByString(false),
+ mOutlineSetByString(false),
+ mFontStyleSetByString(false),
+ mStrikethroughSetByString(false),
+ mShouldClearFocusOnEscape(true),
+ mLayoutDirection(LayoutDirection::LEFT_TO_RIGHT),
+ mTextFitMinSize(DEFAULT_TEXTFIT_MIN),
+ mTextFitMaxSize(DEFAULT_TEXTFIT_MAX),
+ mTextFitStepSize(DEFAULT_TEXTFIT_STEP),
+ mFontSizeScale(DEFAULT_FONT_SIZE_SCALE),
+ mDisabledColorOpacity(DEFAULT_DISABLED_COLOR_OPACITY),
+ mFontSizeScaleEnabled(true),
+ mTextFitEnabled(false),
+ mTextFitChanged(false),
+ mIsLayoutDirectionChanged(false),
+ mIsUserInteractionEnabled(true)
+ {
+ mModel = Model::New();
+
+ mFontClient = TextAbstraction::FontClient::Get();
+ mClipboard = Clipboard::Get();
+
+ mView.SetVisualModel(mModel->mVisualModel);
+ mView.SetLogicalModel(mModel->mLogicalModel);
+
+ // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
+ mMetrics = Metrics::New(mFontClient);
+ mLayoutEngine.SetMetrics(mMetrics);
+
+ // Set the text properties to default
+ mModel->mVisualModel->SetUnderlineEnabled(false);
+ mModel->mVisualModel->SetUnderlineHeight(0.0f);
+
+ Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+ if(styleManager)
+ {
+ const Property::Map& config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
+ const auto clearFocusOnEscapeValue = config.Find("clearFocusOnEscape", Property::Type::BOOLEAN);
+
+ // Default is true. If config don't have "clearFocusOnEscape" property, make it true.
+ mShouldClearFocusOnEscape = (!clearFocusOnEscapeValue || clearFocusOnEscapeValue->Get<bool>());
+ }
+ }
+
+ ~Impl()
+ {
+ delete mHiddenInput;
+ delete mFontDefaults;
+ delete mUnderlineDefaults;
+ delete mShadowDefaults;
+ delete mEmbossDefaults;
+ delete mOutlineDefaults;
+ delete mEventData;
+ }
+
+ // Text Controller Implementation.
+
+ /**
+ * @copydoc Text::Controller::RequestRelayout()
+ */
+ void RequestRelayout();
+
+ /**
+ * @brief Request a relayout using the ControlInterface.
+ */
+ void QueueModifyEvent(ModifyEvent::Type type)
+ {
+ if(ModifyEvent::TEXT_REPLACED == type)
+ {
+ // Cancel previously queued inserts etc.
+ mModifyEvents.Clear();
+ }
+
+ ModifyEvent event;
+ event.type = type;
+ mModifyEvents.PushBack(event);
+
+ // The event will be processed during relayout
+ RequestRelayout();
+ }
+
+ /**
+ * @brief Helper to move the cursor, grab handle etc.
+ */
+ bool ProcessInputEvents();
+
+ /**
+ * @brief Helper to check whether any place-holder text is available.
+ */
+ bool IsPlaceholderAvailable() const
+ {
+ return (mEventData &&
+ (!mEventData->mPlaceholderTextInactive.empty() ||
+ !mEventData->mPlaceholderTextActive.empty()));
+ }
+
+ bool IsShowingPlaceholderText() const
+ {
+ return (mEventData && mEventData->mIsShowingPlaceholderText);
+ }
+
+ /**
+ * @brief Helper to check whether active place-holder text is available.
+ */
+ bool IsFocusedPlaceholderAvailable() const
+ {
+ return (mEventData && !mEventData->mPlaceholderTextActive.empty());
+ }
+
+ bool IsShowingRealText() const
+ {
+ return (!IsShowingPlaceholderText() &&
+ 0u != mModel->mLogicalModel->mText.Count());
+ }
+
+ /**
+ * @brief Called when placeholder-text is hidden
+ */
+ void PlaceholderCleared()
+ {
+ if(mEventData)
+ {
+ mEventData->mIsShowingPlaceholderText = false;
+
+ // Remove mPlaceholderTextColor
+ mModel->mVisualModel->SetTextColor(mTextColor);
+ }
+ }
+
+ void ClearPreEditFlag()
+ {
+ if(mEventData)
+ {
+ mEventData->mPreEditFlag = false;
+ mEventData->mPreEditStartPosition = 0;
+ mEventData->mPreEditLength = 0;
+ }
+ }
+
+ void ResetInputMethodContext()
+ {
+ if(mEventData)
+ {
+ // Reset incase we are in a pre-edit state.
+ if(mEventData->mInputMethodContext)
+ {
+ mEventData->mInputMethodContext.Reset(); // Will trigger a message ( commit, get surrounding )
+ }
+
+ ClearPreEditFlag();
+ }
+ }
+
+ float GetFontSizeScale()
+ {
+ return mFontSizeScaleEnabled ? mFontSizeScale : 1.0f;
+ }
+
+ /**
+ * @brief Helper to notify InputMethodContext with surrounding text & cursor changes.
+ */
+ void NotifyInputMethodContext();
+
+ /**
+ * @brief Helper to notify InputMethodContext with multi line status.
+ */
+ void NotifyInputMethodContextMultiLineStatus();
+
+ /**
+ * @brief Retrieve the current cursor position.
+ *
+ * @return The cursor position.
+ */
+ CharacterIndex GetLogicalCursorPosition() const;
+
+ /**
+ * @brief Retrieves the number of consecutive white spaces starting from the given @p index.
+ *
+ * @param[in] index The character index from where to count the number of consecutive white spaces.
+ *
+ * @return The number of consecutive white spaces.
+ */
+ Length GetNumberOfWhiteSpaces(CharacterIndex index) const;
+
+ /**
+ * @brief Retrieve any text previously set.
+ *
+ * @param[out] text A string of UTF-8 characters.
+ */
+ void GetText(std::string& text) const;
+
+ /**
+ * @brief Retrieve any text previously set starting from the given @p index.
+ *
+ * @param[in] index The character index from where to retrieve the text.
+ * @param[out] text A string of UTF-8 characters.
+ *
+ * @see Dali::Toolkit::Text::Controller::GetText()
+ */
+ void GetText(CharacterIndex index, std::string& text) const;
+
+ bool IsClipboardEmpty()
+ {
+ bool result(mClipboard && mClipboard.NumberOfItems());
+ return !result; // If NumberOfItems greater than 0, return false
+ }
+
+ bool IsClipboardVisible()
+ {
+ bool result(mClipboard && mClipboard.IsVisible());
+ return result;
+ }
+
+ /**
+ * @copydoc Controller::GetLayoutDirection()
+ */
+ Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
+
+ /**
+ * @brief Checks text direction.
+ * @return The text direction.
+ */
+ Toolkit::DevelText::TextDirection::Type GetTextDirection();
+
+ /**
+ * @brief Calculates the start character index of the first paragraph to be updated and
+ * the end character index of the last paragraph to be updated.
+ *
+ * @param[out] numberOfCharacters The number of characters to be updated.
+ */
+ void CalculateTextUpdateIndices(Length& numberOfCharacters);
+
+ /**
+ * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
+ *
+ * @note It never clears the text stored in utf32.
+ *
+ * @param[in] startIndex Index to the first character to be cleared.
+ * @param[in] endIndex Index to the last character to be cleared.
+ * @param[in] operations The operations required.
+ */
+ void ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations);
+
+ /**
+ * @brief Updates the logical and visual models. Updates the style runs in the visual model when the text's styles changes.
+ *
+ * When text or style changes the model is set with some operations pending.
+ * When i.e. the text's size or a relayout is required this method is called
+ * with a given @p operationsRequired parameter. The operations required are
+ * matched with the operations pending to perform the minimum number of operations.
+ *
+ * @param[in] operationsRequired The operations required.
+ *
+ * @return @e true if the model has been modified.
+ */
+ bool UpdateModel(OperationsMask operationsRequired);
+
+ /**
+ * @brief Retreieves the default style.
+ *
+ * @param[out] inputStyle The default style.
+ */
+ void RetrieveDefaultInputStyle(InputStyle& inputStyle);
+
+ /**
+ * @brief Retrieve the line height of the default font.
+ */
+ float GetDefaultFontLineHeight();
+
+ /**
+ * @copydoc Controller::SetDefaultLineSpacing
+ */
+ bool SetDefaultLineSpacing(float lineSpacing);
+
+ /**
+ * @copydoc Controller::SetDefaultLineSize
+ */
+ bool SetDefaultLineSize(float lineSize);
+
+ /**
+ * @copydoc Controller::SetRelativeLineSize
+ */
+ bool SetRelativeLineSize(float relativeLineSize);
+
+ /**
+ * @copydoc Controller::GetRelativeLineSize
+ */
+ float GetRelativeLineSize();
+
+ /**
+ * @copydoc Text::Controller::GetPrimaryCursorPosition()
+ */
+ CharacterIndex GetPrimaryCursorPosition() const;
+
+ /**
+ * @copydoc Text::Controller::SetPrimaryCursorPosition()
+ */
+ bool SetPrimaryCursorPosition(CharacterIndex index, bool focused);
+
+ /**
+ * @copydoc Text::SelectableControlInterface::GetSelectedText()
+ */
+ string GetSelectedText();
+
+ /**
+ * @copydoc Text::EditableControlInterface::CopyText()
+ */
+ string CopyText();
+
+ /**
+ * @copydoc Text::EditableControlInterface::CutText()
+ */
+ string CutText();
+
+ /**
+ * @copydoc Text::SelectableControlInterface::SetTextSelectionRange()
+ */
+ void SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEndf);
+
+ /**
+ * @copydoc Text::SelectableControlInterface::GetTextSelectionRange()
+ */
+ Uint32Pair GetTextSelectionRange() const;
+
+ /**
+ * @copydoc Text::EditableControlInterface::IsEditable()
+ */
+ bool IsEditable() const;
+
+ /**
+ * @copydoc Text::EditableControlInterface::SetEditable()
+ */
+ void SetEditable(bool editable);
+
+ /**
+ * @copydoc Controller::UpdateAfterFontChange
+ */
+ void UpdateAfterFontChange(const std::string& newDefaultFont);
+
+ /**
+ * @brief Retrieves the selected text. It removes the text if the @p deleteAfterRetrieval parameter is @e true.
+ *
+ * @param[out] selectedText The selected text encoded in utf8.
+ * @param[in] deleteAfterRetrieval Whether the text should be deleted after retrieval.
+ */
+ void RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval);
+
+ void SetSelection(int start, int end);
+
+ std::pair<int, int> GetSelectionIndexes() const;
+
+ void ShowClipboard();
+
+ void HideClipboard();
+
+ void SetClipboardHideEnable(bool enable);
+
+ bool CopyStringToClipboard(const std::string& source);
+
+ void SendSelectionToClipboard(bool deleteAfterSending);
+
+ void RequestGetTextFromClipboard();
+
+ void RepositionSelectionHandles();
+ void RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action);
+
+ void SetPopupButtons();
+
+ void ChangeState(EventData::State newState);
+
+ /**
+ * @brief Calculates the cursor's position for a given character index in the logical order.
+ *
+ * It retrieves as well the line's height and the cursor's height and
+ * if there is a valid alternative cursor, its position and height.
+ *
+ * @param[in] logical The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
+ * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
+ */
+ void GetCursorPosition(CharacterIndex logical,
+ CursorInfo& cursorInfo);
+
+ /**
+ * @brief Calculates the new cursor index.
+ *
+ * It takes into account that in some scripts multiple characters can form a glyph and all of them
+ * need to be jumped with one key event.
+ *
+ * @param[in] index The initial new index.
+ *
+ * @return The new cursor index.
+ */
+ CharacterIndex CalculateNewCursorIndex(CharacterIndex index) const;
+
+ /**
+ * @brief Updates the cursor position.
+ *
+ * Sets the cursor's position into the decorator. It transforms the cursor's position into decorator's coords.
+ * It sets the position of the secondary cursor if it's a valid one.
+ * Sets which cursors are active.
+ *
+ * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
+ *
+ */
+ void UpdateCursorPosition(const CursorInfo& cursorInfo);
+
+ /**
+ * @brief Updates the position of the given selection handle. It transforms the handle's position into decorator's coords.
+ *
+ * @param[in] handleType One of the selection handles.
+ * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
+ */
+ void UpdateSelectionHandle(HandleType handleType,
+ const CursorInfo& cursorInfo);
+
+ /**
+ * @biref Clamps the horizontal scrolling to get the control always filled with text.
+ *
+ * @param[in] layoutSize The size of the laid out text.
+ */
+ void ClampHorizontalScroll(const Vector2& layoutSize);
+
+ /**
+ * @biref Clamps the vertical scrolling to get the control always filled with text.
+ *
+ * @param[in] layoutSize The size of the laid out text.
+ */
+ void ClampVerticalScroll(const Vector2& layoutSize);
+
+ /**
+ * @brief Scrolls the text to make a position visible.
+ *
+ * @pre mEventData must not be NULL. (there is a text-input or selection capabilities).
+ *
+ * @param[in] position A position in text coords.
+ * @param[in] lineHeight The line height for the given position.
+ *
+ * This method is called after inserting text, moving the cursor with the grab handle or the keypad,
+ * or moving the selection handles.
+ */
+ void ScrollToMakePositionVisible(const Vector2& position, float lineHeight);
+
+ /**
+ * @brief Scrolls the text to make the cursor visible.
+ *
+ * This method is called after deleting text.
+ */
+ void ScrollTextToMatchCursor(const CursorInfo& cursorInfo);
+
+ /**
+ * @brief Scrolls the text to make primary cursor visible.
+ */
+ void ScrollTextToMatchCursor();
+
+ /**
+ * @brief Create an actor that renders the text background color
+ *
+ * @return the created actor or an empty handle if no background color needs to be rendered.
+ */
+ Actor CreateBackgroundActor();
+
+ /**
+ * @brief fill needed relayout parameters whenever a property is changed and a re-layout is needed for the entire text.
+ */
+ void RelayoutAllCharacters();
+
+ /**
+ * @copydoc Controller::IsInputStyleChangedSignalsQueueEmpty
+ */
+ bool IsInputStyleChangedSignalsQueueEmpty();
+
+ /**
+ * @copydoc Controller::ProcessInputStyleChangedSignals
+ */
+ void ProcessInputStyleChangedSignals();
+
+ /**
+ * @copydoc Controller::ScrollBy()
+ */
+ void ScrollBy(Vector2 scroll);
+
+ /**
+ * @copydoc Controller::IsScrollable()
+ */
+ bool IsScrollable(const Vector2& displacement);
+
+ /**
+ * @copydoc Controller::GetHorizontalScrollPosition()
+ */
+ float GetHorizontalScrollPosition();
+
+ /**
+ * @copydoc Controller::GetVerticalScrollPosition()
+ */
+ float GetVerticalScrollPosition();
+
+ /**
+ * @copydoc Controller::SetAutoScrollEnabled()
+ */
+ void SetAutoScrollEnabled(bool enable);
+
+ /**
+ * @copydoc Controller::SetEnableCursorBlink()
+ */
+ void SetEnableCursorBlink(bool enable);
+
+ /**
+ * @copydoc Controller::SetMultiLineEnabled()
+ */
+ void SetMultiLineEnabled(bool enable);
+
+ /**
+ * @copydoc Controller::SetHorizontalAlignment()
+ */
+ void SetHorizontalAlignment(HorizontalAlignment::Type alignment);
+
+ /**
+ * @copydoc Controller::SetVerticalAlignment()
+ */
+ void SetVerticalAlignment(VerticalAlignment::Type alignment);
+
+ /**
+ * @copydoc Controller::SetLineWrapMode()
+ */
+ void SetLineWrapMode(Text::LineWrap::Mode textWarpMode);
+
+ /**
+ * @copydoc Controller::SetDefaultColor()
+ */
+ void SetDefaultColor(const Vector4& color);
+
+ /**
+ * @copydoc Controller::SetUserInteractionEnabled()
+ */
+ void SetUserInteractionEnabled(bool enabled);
+
+ /**
+ * @brief Helper to clear font-specific data (only).
+ */
+ void ClearFontData();
+
+ /**
+ * @brief Helper to clear text's style data.
+ */
+ void ClearStyleData();
+
+ /**
+ * @brief Used to reset the scroll position after setting a new text.
+ */
+ void ResetScrollPosition();
+
+ /**
+ * @brief Resets a provided vector with actors that marks the position of anchors in markup enabled text
+ *
+ * @param[out] anchorActors the vector of actor (empty collection if no anchors available).
+ */
+ void GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors);
+
+ /**
+ * @brief Return an index of first anchor in the anchor vector whose boundaries includes given character offset
+ *
+ * @param[in] characterOffset A position in text coords.
+ *
+ * @return the 0-based index in anchor vector (-1 if an anchor not found)
+ */
+ int32_t GetAnchorIndex(size_t characterOffset) const;
+
+ /**
+ * @brief Return the geometrical position of an anchor relative to the parent origin point.
+ *
+ * @param[in] anchor An anchor.
+ *
+ * @return The x, y, z coordinates of an anchor.
+ */
+ Vector3 GetAnchorPosition(Anchor anchor) const;
+
+ /**
+ * @brief Return the size of an anchor expresed as a vector containing anchor's width and height.
+ *
+ * @param[in] anchor An anchor.
+ *
+ * @return The width and height of an anchor.
+ */
+ Vector2 GetAnchorSize(Anchor anchor) const;
+
+ /**
+ * @brief Return the actor representing an anchor.
+ *
+ * @param[in] anchor An anchor.
+ *
+ * @return The actor representing an anchor.
+ */
+ Toolkit::TextAnchor CreateAnchorActor(Anchor anchor);
+
+public:
+ /**
+ * @brief Gets implementation from the controller handle.
+ * @param controller The text controller
+ * @return The implementation of the Controller
+ */
+ static Impl& GetImplementation(Text::Controller& controller)
+ {
+ return *controller.mImpl;
+ }
+
+private:
+ // Declared private and left undefined to avoid copies.
+ Impl(const Impl&);
+ // Declared private and left undefined to avoid copies.
+ Impl& operator=(const Impl&);
+
+ /**
+ * @brief Copy Underlined-Character-Runs from Logical-Model to Underlined-Glyph-Runs in Visual-Model
+ *
+ * @param shouldClearPreUnderlineRuns Whether should clear the existing Underlined-Glyph-Runs in Visual-Model
+ */
+ void CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns);
+
+ /**
+ * @brief Copy strikethrough-Character-Runs from Logical-Model to strikethrough-Glyph-Runs in Visual-Model
+ *
+ */
+ void CopyStrikethroughFromLogicalToVisualModels();
+
+ /**
+ * @brief Copy CharacterSpacing-Character-Runs from Logical-Model to CharacterSpacing-Glyph-Runs in Visual-Model
+ *
+ */
+ void CopyCharacterSpacingFromLogicalToVisualModels();
+
+public:
+ ControlInterface* mControlInterface; ///< Reference to the text controller.
+ EditableControlInterface* mEditableControlInterface; ///< Reference to the editable text controller.
+ SelectableControlInterface* mSelectableControlInterface; ///< Reference to the selectable text controller.
+ AnchorControlInterface* mAnchorControlInterface; ///< Reference to the anchor controller.
+ ModelPtr mModel; ///< Pointer to the text's model.
+ FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
+ UnderlineDefaults* mUnderlineDefaults; ///< Avoid allocating this when the user does not specify underline parameters.
+ ShadowDefaults* mShadowDefaults; ///< Avoid allocating this when the user does not specify shadow parameters.
+ EmbossDefaults* mEmbossDefaults; ///< Avoid allocating this when the user does not specify emboss parameters.
+ OutlineDefaults* mOutlineDefaults; ///< Avoid allocating this when the user does not specify outline parameters.
+ EventData* mEventData; ///< Avoid allocating everything for text input until EnableTextInput().
+ TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
+ Clipboard mClipboard; ///< Handle to the system clipboard
+ View mView; ///< The view interface to the rendering back-end.
+ MetricsPtr mMetrics; ///< A wrapper around FontClient used to get metrics & potentially down-scaled Emoji metrics.
+ Layout::Engine mLayoutEngine; ///< The layout engine.
+ Vector<ModifyEvent> mModifyEvents; ///< Temporary stores the text set until the next relayout.
+ Vector4 mTextColor; ///< The regular text color
+ TextUpdateInfo mTextUpdateInfo; ///< Info of the characters updated.
+ OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
+ Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
+ HiddenText* mHiddenInput; ///< Avoid allocating this when the user does not specify hidden input mode.
+ std::unique_ptr<InputFilter> mInputFilter; ///< Avoid allocating this when the user does not specify input filter mode.
+ Vector2 mTextFitContentSize; ///< Size of Text fit content
+
+ bool mRecalculateNaturalSize : 1; ///< Whether the natural size needs to be recalculated.
+ bool mMarkupProcessorEnabled : 1; ///< Whether the mark-up procesor is enabled.
+ bool mClipboardHideEnabled : 1; ///< Whether the ClipboardHide function work or not
+ bool mIsAutoScrollEnabled : 1; ///< Whether auto text scrolling is enabled.
+ bool mIsAutoScrollMaxTextureExceeded : 1; ///< Whether auto text scrolling is exceed max texture size.
+ bool mUpdateTextDirection : 1; ///< Whether the text direction needs to be updated.
+ CharacterDirection mIsTextDirectionRTL : 1; ///< Whether the text direction is right to left or not
+
+ bool mUnderlineSetByString : 1; ///< Set when underline is set by string (legacy) instead of map
+ bool mShadowSetByString : 1; ///< Set when shadow is set by string (legacy) instead of map
+ bool mOutlineSetByString : 1; ///< Set when outline is set by string (legacy) instead of map
+ bool mFontStyleSetByString : 1; ///< Set when font style is set by string (legacy) instead of map
+ bool mStrikethroughSetByString : 1; ///< Set when strikethrough is set by string (legacy) instead of map
+ bool mShouldClearFocusOnEscape : 1; ///< Whether text control should clear key input focus
+ LayoutDirection::Type mLayoutDirection; ///< Current system language direction
+
+ Shader mShaderBackground; ///< The shader for text background.
+
+ float mTextFitMinSize; ///< Minimum Font Size for text fit. Default 10
+ float mTextFitMaxSize; ///< Maximum Font Size for text fit. Default 100
+ float mTextFitStepSize; ///< Step Size for font intervalse. Default 1
+ float mFontSizeScale; ///< Scale value for Font Size. Default 1.0
+ float mDisabledColorOpacity; ///< Color opacity when disabled.
+ bool mFontSizeScaleEnabled : 1; ///< Whether the font size scale is enabled.
+ bool mTextFitEnabled : 1; ///< Whether the text's fit is enabled.
+ bool mTextFitChanged : 1; ///< Whether the text fit property has changed.
+ bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
+ bool mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled.
+
+private:
+ friend ControllerImplEventHandler;
+ friend ControllerImplModelUpdater;
+ friend SelectionHandleController;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-input-font-handler.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+/**
+ * @brief Adds a new font description run for the selected text.
+ *
+ * The new font parameters are added after the call to this method.
+ *
+ * @param[in] eventData The event data pointer.
+ * @param[in] logicalModel The logical model where to add the new font description run.
+ * @param[out] startOfSelectedText Index to the first selected character.
+ * @param[out] lengthOfSelectedText Number of selected characters.
+ */
+FontDescriptionRun& UpdateSelectionFontStyleRun(EventData* eventData,
+ LogicalModelPtr logicalModel,
+ CharacterIndex& startOfSelectedText,
+ Length& lengthOfSelectedText)
+{
+ const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
+
+ // Get start and end position of selection
+ startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
+ lengthOfSelectedText = (handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition) - startOfSelectedText;
+
+ // Add the font run.
+ const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
+ logicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
+
+ FontDescriptionRun& fontDescriptionRun = *(logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
+
+ fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
+ fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
+
+ // Recalculate the selection highlight as the metrics may have changed.
+ eventData->mUpdateLeftSelectionPosition = true;
+ eventData->mUpdateRightSelectionPosition = true;
+ eventData->mUpdateHighlightBox = true;
+
+ return fontDescriptionRun;
+}
+
+} // unnamed namespace
+
+void Controller::InputFontHandler::SetInputFontFamily(Controller& controller, const std::string& fontFamily)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.familyName = fontFamily;
+ controller.mImpl->mEventData->mInputStyle.isFamilyDefined = true;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
+ controller.mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText);
+
+ fontDescriptionRun.familyLength = fontFamily.size();
+ fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+ memcpy(fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength);
+ fontDescriptionRun.familyDefined = true;
+
+ // The memory allocated for the font family name is freed when the font description is removed from the logical model.
+
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
+ // Request to relayout.
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN);
+ controller.mImpl->mRecalculateNaturalSize = true;
+ controller.mImpl->RequestRelayout();
+
+ // As the font changes, recalculate the handle positions is needed.
+ controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateHighlightBox = true;
+ controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+const std::string& Controller::InputFontHandler::GetInputFontFamily(const Controller& controller)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ return controller.mImpl->mEventData->mInputStyle.familyName;
+ }
+
+ // Return the default font's family if there is no EventData.
+ return controller.GetDefaultFontFamily();
+}
+
+void Controller::InputFontHandler::SetInputFontWeight(const Controller& controller, FontWeight weight)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.weight = weight;
+ controller.mImpl->mEventData->mInputStyle.isWeightDefined = true;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
+ controller.mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText);
+
+ fontDescriptionRun.weight = weight;
+ fontDescriptionRun.weightDefined = true;
+
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
+ // Request to relayout.
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN);
+ controller.mImpl->mRecalculateNaturalSize = true;
+ controller.mImpl->RequestRelayout();
+
+ // As the font might change, recalculate the handle positions is needed.
+ controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateHighlightBox = true;
+ controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+bool Controller::InputFontHandler::IsInputFontWeightDefined(const Controller& controller)
+{
+ bool defined = false;
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ defined = controller.mImpl->mEventData->mInputStyle.isWeightDefined;
+ }
+
+ return defined;
+}
+
+FontWeight Controller::InputFontHandler::GetInputFontWeight(const Controller& controller)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ return controller.mImpl->mEventData->mInputStyle.weight;
+ }
+
+ return controller.GetDefaultFontWeight();
+}
+
+void Controller::InputFontHandler::SetInputFontWidth(Controller& controller, FontWidth width)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.width = width;
+ controller.mImpl->mEventData->mInputStyle.isWidthDefined = true;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
+ controller.mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText);
+
+ fontDescriptionRun.width = width;
+ fontDescriptionRun.widthDefined = true;
+
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
+ // Request to relayout.
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN);
+ controller.mImpl->mRecalculateNaturalSize = true;
+ controller.mImpl->RequestRelayout();
+
+ // As the font might change, recalculate the handle positions is needed.
+ controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateHighlightBox = true;
+ controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+bool Controller::InputFontHandler::IsInputFontWidthDefined(const Controller& controller)
+{
+ bool defined = false;
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ defined = controller.mImpl->mEventData->mInputStyle.isWidthDefined;
+ }
+
+ return defined;
+}
+
+FontWidth Controller::InputFontHandler::GetInputFontWidth(const Controller& controller)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ return controller.mImpl->mEventData->mInputStyle.width;
+ }
+
+ return controller.GetDefaultFontWidth();
+}
+
+void Controller::InputFontHandler::SetInputFontSlant(Controller& controller, FontSlant slant)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.slant = slant;
+ controller.mImpl->mEventData->mInputStyle.isSlantDefined = true;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
+ controller.mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText);
+
+ fontDescriptionRun.slant = slant;
+ fontDescriptionRun.slantDefined = true;
+
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
+ // Request to relayout.
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN);
+ controller.mImpl->mRecalculateNaturalSize = true;
+ controller.mImpl->RequestRelayout();
+
+ // As the font might change, recalculate the handle positions is needed.
+ controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateHighlightBox = true;
+ controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+bool Controller::InputFontHandler::IsInputFontSlantDefined(const Controller& controller)
+{
+ bool defined = false;
+
+ if(NULL != controller.mImpl->mEventData)
+ {
+ defined = controller.mImpl->mEventData->mInputStyle.isSlantDefined;
+ }
+
+ return defined;
+}
+
+FontSlant Controller::InputFontHandler::GetInputFontSlant(const Controller& controller)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ return controller.mImpl->mEventData->mInputStyle.slant;
+ }
+
+ return controller.GetDefaultFontSlant();
+}
+
+void Controller::InputFontHandler::SetInputFontPointSize(Controller& controller, float size)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.size = size;
+ controller.mImpl->mEventData->mInputStyle.isSizeDefined = true;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
+ controller.mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText);
+
+ fontDescriptionRun.size = static_cast<PointSize26Dot6>(size * controller.mImpl->GetFontSizeScale() * 64.f);
+ fontDescriptionRun.sizeDefined = true;
+
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
+ // Request to relayout.
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN);
+ controller.mImpl->mRecalculateNaturalSize = true;
+ controller.mImpl->RequestRelayout();
+
+ // As the font might change, recalculate the handle positions is needed.
+ controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ controller.mImpl->mEventData->mUpdateHighlightBox = true;
+ controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+float Controller::InputFontHandler::GetInputFontPointSize(const Controller& controller)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ return controller.mImpl->mEventData->mInputStyle.size;
+ }
+
+ // Return the default font's point size if there is no EventData.
+ return controller.GetDefaultFontSize(Text::Controller::POINT_SIZE);
+}
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_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 <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Controller::InputFontHandler
+{
+ static void SetInputFontFamily(Controller& controller, const std::string& fontFamily);
+ static const std::string& GetInputFontFamily(const Controller& controller);
+ static void SetInputFontWeight(const Controller& controller, FontWeight weight);
+ static bool IsInputFontWeightDefined(const Controller& controller);
+ static FontWeight GetInputFontWeight(const Controller& controller);
+ static void SetInputFontWidth(Controller& controller, FontWidth width);
+ static bool IsInputFontWidthDefined(const Controller& controller);
+ static FontWidth GetInputFontWidth(const Controller& controller);
+ static void SetInputFontSlant(Controller& controller, FontSlant slant);
+ static bool IsInputFontSlantDefined(const Controller& controller);
+ static FontSlant GetInputFontSlant(const Controller& controller);
+ static void SetInputFontPointSize(Controller& controller, float size);
+ static float GetInputFontPointSize(const Controller& controller);
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-input-properties.h>
+
+// EXTERNAL INCLUDES
+//#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+//#include <dali/devel-api/adaptor-framework/window-devel.h>
+//#include <dali/integration-api/debug.h>
+#include <memory.h>
+#include <cmath>
+#include <limits>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller-input-font-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-relayouter.h>
+#include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+
+namespace
+{
+const std::string EMPTY_STRING("");
+}
+
+namespace Dali::Toolkit::Text
+{
+
+void Controller::InputProperties::SetInputColor(Controller& controller, const Vector4& color)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.textColor = color;
+ controller.mImpl->mEventData->mInputStyle.isDefaultColor = false;
+
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
+ {
+ if(EventData::SELECTING == controller.mImpl->mEventData->mState)
+ {
+ const bool handlesCrossed = controller.mImpl->mEventData->mLeftSelectionPosition > controller.mImpl->mEventData->mRightSelectionPosition;
+
+ // Get start and end position of selection
+ const CharacterIndex startOfSelectedText = handlesCrossed ? controller.mImpl->mEventData->mRightSelectionPosition : controller.mImpl->mEventData->mLeftSelectionPosition;
+ const Length lengthOfSelectedText = (handlesCrossed ? controller.mImpl->mEventData->mLeftSelectionPosition : controller.mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
+
+ // Add the color run.
+ const VectorBase::SizeType numberOfRuns = controller.mImpl->mModel->mLogicalModel->mColorRuns.Count();
+ controller.mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
+
+ ColorRun& colorRun = *(controller.mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
+ colorRun.color = color;
+ colorRun.characterRun.characterIndex = startOfSelectedText;
+ colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
+
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
+ // Request to relayout.
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending | COLOR);
+ controller.mImpl->RequestRelayout();
+ }
+ }
+}
+
+const Vector4& Controller::InputProperties::GetInputColor(const Controller& controller)
+{
+ // Return event text input color if we have it, otherwise just return the default text's color
+ return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.textColor : controller.mImpl->mTextColor;
+}
+
+void Controller::InputProperties::SetInputLineSpacing(Controller& controller, float lineSpacing)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
+ controller.mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
+ }
+}
+
+float Controller::InputProperties::GetInputLineSpacing(const Controller& controller)
+{
+ return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.lineSpacing : 0.0f;
+}
+
+void Controller::InputProperties::SetInputShadowProperties(Controller& controller, const std::string& shadowProperties)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
+ }
+}
+
+const std::string& Controller::InputProperties::GetInputShadowProperties(const Controller& controller)
+{
+ return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.shadowProperties : EMPTY_STRING;
+}
+
+void Controller::InputProperties::SetInputUnderlineProperties(Controller& controller, const std::string& underlineProperties)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
+ }
+}
+
+const std::string& Controller::InputProperties::GetInputUnderlineProperties(const Controller& controller)
+{
+ return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.underlineProperties : EMPTY_STRING;
+}
+
+void Controller::InputProperties::SetInputEmbossProperties(Controller& controller, const std::string& embossProperties)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
+ }
+}
+
+const std::string& Controller::InputProperties::GetInputEmbossProperties(const Controller& controller)
+{
+ return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.embossProperties : controller.GetDefaultEmbossProperties();
+}
+
+void Controller::InputProperties::SetInputOutlineProperties(Controller& controller, const std::string& outlineProperties)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
+ }
+}
+
+const std::string& Controller::InputProperties::GetInputOutlineProperties(const Controller& controller)
+{
+ return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.outlineProperties : controller.GetDefaultOutlineProperties();
+}
+
+void Controller::InputProperties::SetInputModePassword(Controller& controller, bool passwordInput)
+{
+ if(controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mPasswordInput = passwordInput;
+ }
+}
+
+bool Controller::InputProperties::IsInputModePassword(Controller& controller)
+{
+ return controller.mImpl->mEventData && controller.mImpl->mEventData->mPasswordInput;
+}
+
+} // namespace Dali::Toolkit::Text
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_PROPERTIES_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_PROPERTIES_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/public-api/events/gesture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+
+namespace Dali::Toolkit::Text
+{
+struct Controller::InputProperties
+{
+ static void SetInputColor(Controller& controller, const Vector4& color);
+
+ static const Vector4& GetInputColor(const Controller& controller);
+
+ static void SetInputLineSpacing(Controller& controller, float lineSpacing);
+
+ static float GetInputLineSpacing(const Controller& controller);
+
+ static void SetInputShadowProperties(Controller& controller, const std::string& shadowProperties);
+
+ static const std::string& GetInputShadowProperties(const Controller& controller);
+
+ static void SetInputUnderlineProperties(Controller& controller, const std::string& underlineProperties);
+
+ static const std::string& GetInputUnderlineProperties(const Controller& controller);
+
+ static void SetInputEmbossProperties(Controller& controller, const std::string& embossProperties);
+
+ static const std::string& GetInputEmbossProperties(const Controller& controller);
+
+ static void SetInputOutlineProperties(Controller& controller, const std::string& outlineProperties);
+
+ static const std::string& GetInputOutlineProperties(const Controller& controller);
+
+ static void SetInputModePassword(Controller& controller, bool passwordInput);
+
+ static bool IsInputModePassword(Controller& controller);
+};
+
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_PROPERTIES_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const std::string EMPTY_STRING("");
+
+const char* const PLACEHOLDER_TEXT = "text";
+const char* const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
+const char* const PLACEHOLDER_COLOR = "color";
+const char* const PLACEHOLDER_FONT_FAMILY = "fontFamily";
+const char* const PLACEHOLDER_FONT_STYLE = "fontStyle";
+const char* const PLACEHOLDER_POINT_SIZE = "pointSize";
+const char* const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
+const char* const PLACEHOLDER_ELLIPSIS = "ellipsis";
+
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled)
+{
+ controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
+ controller.mImpl->mEventData->mPlaceholderEllipsisFlag = true;
+
+ // Update placeholder if there is no text
+ if(controller.mImpl->IsShowingPlaceholderText() ||
+ (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
+ {
+ ShowPlaceholderText(*controller.mImpl);
+ }
+}
+
+bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller)
+{
+ return controller.mImpl->mEventData->mIsPlaceholderElideEnabled;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if(PLACEHOLDER_TYPE_INACTIVE == type)
+ {
+ controller.mImpl->mEventData->mPlaceholderTextInactive = text;
+ }
+ else
+ {
+ controller.mImpl->mEventData->mPlaceholderTextActive = text;
+ }
+
+ // Update placeholder if there is no text
+ if(controller.mImpl->IsShowingPlaceholderText() ||
+ (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
+ {
+ ShowPlaceholderText(*controller.mImpl);
+ }
+ }
+}
+
+void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if(PLACEHOLDER_TYPE_INACTIVE == type)
+ {
+ text = controller.mImpl->mEventData->mPlaceholderTextInactive;
+ }
+ else
+ {
+ text = controller.mImpl->mEventData->mPlaceholderTextActive;
+ }
+ }
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ // if mPlaceholderFont is null, create an instance.
+ CreatePlaceholderFont(controller);
+
+ controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
+ controller.mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
+ }
+
+ return EMPTY_STRING;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ // if mPlaceholderFont is null, create an instance.
+ CreatePlaceholderFont(controller);
+
+ controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
+ controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true;
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->weightDefined;
+ }
+ return false;
+}
+
+FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
+ }
+
+ return TextAbstraction::FontWeight::NORMAL;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ // if mPlaceholderFont is null, create an instance.
+ CreatePlaceholderFont(controller);
+
+ controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
+ controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true;
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->widthDefined;
+ }
+ return false;
+}
+
+FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
+ }
+
+ return TextAbstraction::FontWidth::NORMAL;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ // if mPlaceholderFont is null, create an instance.
+ CreatePlaceholderFont(controller);
+
+ controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
+ controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true;
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->slantDefined;
+ }
+ return false;
+}
+
+FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller)
+{
+ if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
+ {
+ return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
+ }
+
+ return TextAbstraction::FontSlant::NORMAL;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ // if mPlaceholderFont is null, create an instance.
+ CreatePlaceholderFont(controller);
+
+ switch(type)
+ {
+ case POINT_SIZE:
+ {
+ controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
+ controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
+ controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
+ break;
+ }
+ case PIXEL_SIZE:
+ {
+ // Point size = Pixel size * 72.f / DPI
+ unsigned int horizontalDpi = 0u;
+ unsigned int verticalDpi = 0u;
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.GetDpi(horizontalDpi, verticalDpi);
+
+ controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
+ controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
+ controller.mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
+ break;
+ }
+ }
+
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type)
+{
+ float value = 0.0f;
+ if(NULL != controller.mImpl->mEventData)
+ {
+ switch(type)
+ {
+ case POINT_SIZE:
+ {
+ if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
+ {
+ value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
+ }
+ else
+ {
+ // If the placeholder text font size is not set, then return the default font size.
+ value = controller.GetDefaultFontSize(POINT_SIZE);
+ }
+ break;
+ }
+ case PIXEL_SIZE:
+ {
+ if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
+ {
+ // Pixel size = Point size * DPI / 72.f
+ unsigned int horizontalDpi = 0u;
+ unsigned int verticalDpi = 0u;
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.GetDpi(horizontalDpi, verticalDpi);
+
+ value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
+ }
+ else
+ {
+ // If the placeholder text font size is not set, then return the default font size.
+ value = controller.GetDefaultFontSize(PIXEL_SIZE);
+ }
+ break;
+ }
+ }
+ return value;
+ }
+
+ return value;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ controller.mImpl->mEventData->mPlaceholderTextColor = textColor;
+ }
+
+ if(controller.mImpl->IsShowingPlaceholderText())
+ {
+ controller.mImpl->mModel->mVisualModel->SetTextColor(textColor);
+ controller.mImpl->mModel->mLogicalModel->mColorRuns.Clear();
+ controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending | COLOR);
+ controller.mImpl->RequestRelayout();
+ }
+}
+
+const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ return controller.mImpl->mEventData->mPlaceholderTextColor;
+ }
+
+ return Color::BLACK;
+}
+
+void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map)
+{
+ const Property::Map::SizeType count = map.Count();
+
+ for(Property::Map::SizeType position = 0; position < count; ++position)
+ {
+ KeyValuePair keyValue = map.GetKeyValue(position);
+ Property::Key& key = keyValue.first;
+ Property::Value& value = keyValue.second;
+
+ if(key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT)
+ {
+ std::string text = "";
+ value.Get(text);
+ SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text);
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED)
+ {
+ std::string text = "";
+ value.Get(text);
+ SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text);
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR)
+ {
+ Vector4 textColor;
+ value.Get(textColor);
+ if(GetPlaceholderTextColor(controller) != textColor)
+ {
+ SetPlaceholderTextColor(controller, textColor);
+ }
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY)
+ {
+ std::string fontFamily = "";
+ value.Get(fontFamily);
+ SetPlaceholderFontFamily(controller, fontFamily);
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE)
+ {
+ SetFontStyleProperty(&controller, value, Text::FontStyle::PLACEHOLDER);
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE)
+ {
+ float pointSize;
+ value.Get(pointSize);
+ if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize))
+ {
+ SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE);
+ }
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE)
+ {
+ float pixelSize;
+ value.Get(pixelSize);
+ if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize))
+ {
+ SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE);
+ }
+ }
+ else if(key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS)
+ {
+ bool ellipsis;
+ value.Get(ellipsis);
+ SetPlaceholderTextElideEnabled(controller, ellipsis);
+ }
+ }
+}
+
+void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map)
+{
+ if(NULL != controller.mImpl->mEventData)
+ {
+ if(!controller.mImpl->mEventData->mPlaceholderTextActive.empty())
+ {
+ map[Text::PlaceHolder::Property::TEXT_FOCUSED] = controller.mImpl->mEventData->mPlaceholderTextActive;
+ }
+ if(!controller.mImpl->mEventData->mPlaceholderTextInactive.empty())
+ {
+ map[Text::PlaceHolder::Property::TEXT] = controller.mImpl->mEventData->mPlaceholderTextInactive;
+ }
+
+ map[Text::PlaceHolder::Property::COLOR] = controller.mImpl->mEventData->mPlaceholderTextColor;
+ map[Text::PlaceHolder::Property::FONT_FAMILY] = GetPlaceholderFontFamily(controller);
+
+ Property::Value fontStyleMapGet;
+ GetFontStyleProperty(&controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER);
+ map[Text::PlaceHolder::Property::FONT_STYLE] = fontStyleMapGet;
+
+ // Choose font size : POINT_SIZE or PIXEL_SIZE
+ if(!controller.mImpl->mEventData->mIsPlaceholderPixelSize)
+ {
+ map[Text::PlaceHolder::Property::POINT_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE);
+ }
+ else
+ {
+ map[Text::PlaceHolder::Property::PIXEL_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE);
+ }
+
+ if(controller.mImpl->mEventData->mPlaceholderEllipsisFlag)
+ {
+ map[Text::PlaceHolder::Property::ELLIPSIS] = IsPlaceholderTextElideEnabled(controller);
+ }
+ }
+}
+
+void Controller::PlaceholderHandler::ShowPlaceholderText(Controller::Impl& impl)
+{
+ if(impl.IsPlaceholderAvailable())
+ {
+ EventData*& eventData = impl.mEventData;
+ DALI_ASSERT_DEBUG(eventData && "No placeholder text available");
+
+ if(NULL == eventData)
+ {
+ return;
+ }
+
+ eventData->mIsShowingPlaceholderText = true;
+
+ // Disable handles when showing place-holder text
+ DecoratorPtr& decorator = eventData->mDecorator;
+ decorator->SetHandleActive(GRAB_HANDLE, false);
+ decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+
+ const char* text(NULL);
+ size_t size(0);
+
+ // TODO - Switch Placeholder text when changing state
+ std::string& placeholderTextActive = eventData->mPlaceholderTextActive;
+ if((EventData::INACTIVE != eventData->mState) &&
+ (0u != placeholderTextActive.c_str()))
+ {
+ text = placeholderTextActive.c_str();
+ size = placeholderTextActive.size();
+ }
+ else
+ {
+ std::string& placeholderTextInactive = eventData->mPlaceholderTextInactive;
+ text = placeholderTextInactive.c_str();
+ size = placeholderTextInactive.size();
+ }
+
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+ textUpdateInfo.mCharacterIndex = 0u;
+ textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
+
+ // Reset model for showing placeholder.
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+ logicalModel->mText.Clear();
+ model->mVisualModel->SetTextColor(eventData->mPlaceholderTextColor);
+
+ // Convert text into UTF-32
+ Vector<Character>& utf32Characters = logicalModel->mText;
+ utf32Characters.Resize(size);
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
+
+ // Transform a text array encoded in utf8 into an array encoded in utf32.
+ // It returns the actual number of characters.
+ const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
+ utf32Characters.Resize(characterCount);
+
+ // The characters to be added.
+ textUpdateInfo.mNumberOfCharactersToAdd = characterCount;
+
+ // Reset the cursor position
+ eventData->mPrimaryCursorPosition = 0;
+
+ // The natural size needs to be re-calculated.
+ impl.mRecalculateNaturalSize = true;
+
+ // The text direction needs to be updated.
+ impl.mUpdateTextDirection = true;
+
+ // Apply modifications to the model
+ impl.mOperationsPending = ALL_OPERATIONS;
+
+ // Update the rest of the model during size negotiation
+ impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
+ }
+}
+
+void Controller::PlaceholderHandler::CreatePlaceholderFont(Controller& controller)
+{
+ if(nullptr == controller.mImpl->mEventData->mPlaceholderFont)
+ {
+ controller.mImpl->mEventData->mPlaceholderFont = std::unique_ptr<FontDefaults>(new FontDefaults());
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Controller::PlaceholderHandler
+{
+ static void SetPlaceholderTextElideEnabled(Controller& controller, bool enabled);
+ static bool IsPlaceholderTextElideEnabled(const Controller& controller);
+ static void SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text);
+ static void GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text);
+ static void SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily);
+ static const std::string& GetPlaceholderFontFamily(const Controller& controller);
+ static void SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight);
+ static bool IsPlaceholderTextFontWeightDefined(const Controller& controller);
+ static FontWeight GetPlaceholderTextFontWeight(const Controller& controller);
+ static void SetPlaceholderTextFontWidth(Controller& controller, FontWidth width);
+ static bool IsPlaceholderTextFontWidthDefined(const Controller& controller);
+ static FontWidth GetPlaceholderTextFontWidth(const Controller& controller);
+ static void SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant);
+ static bool IsPlaceholderTextFontSlantDefined(const Controller& controller);
+ static FontSlant GetPlaceholderTextFontSlant(const Controller& controller);
+ static void SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type);
+ static float GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type);
+ static void SetPlaceholderTextColor(Controller& controller, const Vector4& textColor);
+ static const Vector4& GetPlaceholderTextColor(const Controller& controller);
+ static void SetPlaceholderProperty(Controller& controller, const Property::Map& map);
+ static void GetPlaceholderProperty(Controller& controller, Property::Map& map);
+ static void ShowPlaceholderText(Controller::Impl& impl);
+ static void CreatePlaceholderFont(Controller& controller);
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-relayouter.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <limits>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
+
+float ConvertToEven(float value)
+{
+ int intValue(static_cast<int>(value));
+ return static_cast<float>(intValue + (intValue & 1));
+}
+
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->CalculateLayoutSizeOnRequiredControllerSize\n");
+ Size calculatedLayoutSize;
+
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
+ GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS);
+
+ const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT | ALIGN | REORDER);
+
+ // Set the update info to relayout the whole text.
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+ if((0 == textUpdateInfo.mNumberOfCharactersToAdd) &&
+ (0 == textUpdateInfo.mPreviousNumberOfCharacters) &&
+ ((visualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (visualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
+ {
+ textUpdateInfo.mNumberOfCharactersToAdd = model->mLogicalModel->mText.Count();
+ }
+ textUpdateInfo.mParagraphCharacterIndex = 0u;
+ textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
+
+ // Get a reference to the pending operations member
+ OperationsMask& operationsPending = impl.mOperationsPending;
+
+ // Store the actual control's size to restore later.
+ const Size actualControlSize = visualModel->mControlSize;
+
+ // Whether the text control is editable
+ const bool isEditable = NULL != impl.mEventData;
+
+ if(!isEditable)
+ {
+ impl.UpdateModel(onlyOnceOperations);
+
+ // Layout the text for the new width.
+ operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask);
+
+ DoRelayout(impl,
+ requestedControllerSize,
+ static_cast<OperationsMask>(onlyOnceOperations | requestedOperationsMask),
+ calculatedLayoutSize);
+
+ textUpdateInfo.Clear();
+ textUpdateInfo.mClearAll = true;
+
+ // Do not do again the only once operations.
+ operationsPending = static_cast<OperationsMask>(operationsPending & ~onlyOnceOperations);
+ }
+ else
+ {
+ // This is to keep Index to the first character to be updated.
+ // Then restore it after calling Clear method.
+ auto updateInfoCharIndexBackup = textUpdateInfo.mCharacterIndex;
+
+ // Layout the text for the new width.
+ // Apply the pending operations, requested operations and the only once operations.
+ // Then remove onlyOnceOperations
+ operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask | onlyOnceOperations);
+
+ // Make sure the model is up-to-date before layouting
+ impl.UpdateModel(static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE));
+
+ DoRelayout(impl,
+ requestedControllerSize,
+ static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE),
+ calculatedLayoutSize);
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.Clear();
+
+ //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel,
+ //TODO: then calculate GlyphPositions. Lines, Size, Layout for Natural-Size
+ //TODO: and utilize the values in OperationsPending and TextUpdateInfo without changing the original one.
+ //TODO: Also it will improve performance because there is no need todo FullRelyout on the next need for layouting.
+
+ // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+ // By this no need to take backup and restore it.
+ textUpdateInfo.mFullRelayoutNeeded = true;
+
+ // Restore mCharacterIndex. Because "Clear" set it to the maximum integer.
+ // The "CalculateTextUpdateIndices" does not work proprely because the mCharacterIndex will be greater than mPreviousNumberOfCharacters.
+ // Which apply an assumption to update only the last paragraph. That could cause many of out of index crashes.
+ textUpdateInfo.mCharacterIndex = updateInfoCharIndexBackup;
+ }
+
+ // Do the size related operations again.
+ operationsPending = static_cast<OperationsMask>(operationsPending | sizeOperations);
+
+ // Restore the actual control's size.
+ visualModel->mControlSize = actualControlSize;
+
+ return calculatedLayoutSize;
+}
+
+Vector3 Controller::Relayouter::GetNaturalSize(Controller& controller)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
+ Vector3 naturalSizeVec3;
+
+ // Make sure the model is up-to-date before layouting
+ EventHandler::ProcessModifyEvents(controller);
+
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+
+ if(impl.mRecalculateNaturalSize)
+ {
+ Size naturalSize;
+
+ // Layout the text for the new width.
+ OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT | REORDER);
+ Size sizeMaxWidthAndMaxHeight = Size(MAX_FLOAT, MAX_FLOAT);
+
+ naturalSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeMaxWidthAndMaxHeight, requestedOperationsMask);
+
+ // Stores the natural size to avoid recalculate it again
+ // unless the text/style changes.
+ visualModel->SetNaturalSize(naturalSize);
+ naturalSizeVec3 = naturalSize;
+
+ impl.mRecalculateNaturalSize = false;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSizeVec3.x, naturalSizeVec3.y, naturalSizeVec3.z);
+ }
+ else
+ {
+ naturalSizeVec3 = visualModel->GetNaturalSize();
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSizeVec3.x, naturalSizeVec3.y, naturalSizeVec3.z);
+ }
+
+ naturalSizeVec3.x = ConvertToEven(naturalSizeVec3.x);
+ naturalSizeVec3.y = ConvertToEven(naturalSizeVec3.y);
+
+ return naturalSizeVec3;
+}
+
+bool Controller::Relayouter::CheckForTextFit(Controller& controller, float pointSize, const Size& layoutSize)
+{
+ Size textSize;
+ Controller::Impl& impl = *controller.mImpl;
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+ impl.mFontDefaults->mFitPointSize = pointSize;
+ impl.mFontDefaults->sizeDefined = true;
+ impl.ClearFontData();
+
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
+ GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS);
+
+ textUpdateInfo.mParagraphCharacterIndex = 0u;
+ textUpdateInfo.mRequestedNumberOfCharacters = impl.mModel->mLogicalModel->mText.Count();
+
+ // Make sure the model is up-to-date before layouting
+ impl.UpdateModel(onlyOnceOperations);
+
+ DoRelayout(impl,
+ Size(layoutSize.width, MAX_FLOAT),
+ static_cast<OperationsMask>(onlyOnceOperations | LAYOUT),
+ textSize);
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.Clear();
+ textUpdateInfo.mClearAll = true;
+
+ if(textSize.width > layoutSize.width || textSize.height > layoutSize.height)
+ {
+ return false;
+ }
+ return true;
+}
+
+void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const Size& layoutSize)
+{
+ Controller::Impl& impl = *controller.mImpl;
+
+ const OperationsMask operations = impl.mOperationsPending;
+ if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || impl.mTextFitContentSize != layoutSize)
+ {
+ ModelPtr& model = impl.mModel;
+
+ bool actualellipsis = model->mElideEnabled;
+ float minPointSize = impl.mTextFitMinSize;
+ float maxPointSize = impl.mTextFitMaxSize;
+ float pointInterval = impl.mTextFitStepSize;
+ float currentFitPointSize = impl.mFontDefaults->mFitPointSize;
+
+ model->mElideEnabled = false;
+ Vector<float> pointSizeArray;
+
+ // check zero value
+ if(pointInterval < 1.f)
+ {
+ impl.mTextFitStepSize = pointInterval = 1.0f;
+ }
+
+ pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
+
+ for(float i = minPointSize; i < maxPointSize; i += pointInterval)
+ {
+ pointSizeArray.PushBack(i);
+ }
+
+ pointSizeArray.PushBack(maxPointSize);
+
+ int bestSizeIndex = 0;
+ int min = bestSizeIndex + 1;
+ int max = pointSizeArray.Size() - 1;
+ while(min <= max)
+ {
+ int destI = (min + max) / 2;
+
+ if(CheckForTextFit(controller, pointSizeArray[destI], layoutSize))
+ {
+ bestSizeIndex = min;
+ min = destI + 1;
+ }
+ else
+ {
+ max = destI - 1;
+ bestSizeIndex = max;
+ }
+ }
+
+ model->mElideEnabled = actualellipsis;
+ if(currentFitPointSize != pointSizeArray[bestSizeIndex])
+ {
+ impl.mTextFitChanged = true;
+ }
+ impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
+ impl.mFontDefaults->sizeDefined = true;
+ impl.ClearFontData();
+ }
+}
+
+float Controller::Relayouter::GetHeightForWidth(Controller& controller, float width)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", &controller, width);
+
+ // Make sure the model is up-to-date before layouting
+ EventHandler::ProcessModifyEvents(controller);
+
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+ Size layoutSize;
+
+ if(fabsf(width - visualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
+ textUpdateInfo.mFullRelayoutNeeded ||
+ textUpdateInfo.mClearAll)
+ {
+ // Layout the text for the new width.
+ OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT);
+ Size sizeRequestedWidthAndMaxHeight = Size(width, MAX_FLOAT);
+
+ layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask);
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
+ }
+ else
+ {
+ layoutSize = visualModel->GetLayoutSize();
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height);
+ }
+
+ return layoutSize.height;
+}
+
+Controller::UpdateTextType Controller::Relayouter::Relayout(Controller& controller, const Size& size, Dali::LayoutDirection::Type layoutDirection)
+{
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", &controller, size.width, size.height, impl.mIsAutoScrollEnabled ? "true" : "false");
+
+ UpdateTextType updateTextType = NONE_UPDATED;
+
+ if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
+ {
+ if(0u != visualModel->mGlyphPositions.Count())
+ {
+ visualModel->mGlyphPositions.Clear();
+ updateTextType = MODEL_UPDATED;
+ }
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.Clear();
+
+ // Not worth to relayout if width or height is equal to zero.
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n");
+
+ return updateTextType;
+ }
+
+ // Whether a new size has been set.
+ const bool newSize = (size != visualModel->mControlSize);
+
+ // Get a reference to the pending operations member
+ OperationsMask& operationsPending = impl.mOperationsPending;
+
+ if(newSize)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", visualModel->mControlSize.width, visualModel->mControlSize.height);
+
+ if((0 == textUpdateInfo.mNumberOfCharactersToAdd) &&
+ (0 == textUpdateInfo.mPreviousNumberOfCharacters) &&
+ ((visualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (visualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
+ {
+ textUpdateInfo.mNumberOfCharactersToAdd = model->mLogicalModel->mText.Count();
+ }
+
+ // Layout operations that need to be done if the size changes.
+ operationsPending = static_cast<OperationsMask>(operationsPending |
+ LAYOUT |
+ ALIGN |
+ UPDATE_LAYOUT_SIZE |
+ REORDER);
+ // Set the update info to relayout the whole text.
+ textUpdateInfo.mFullRelayoutNeeded = true;
+ textUpdateInfo.mCharacterIndex = 0u;
+
+ // Store the size used to layout the text.
+ visualModel->mControlSize = size;
+ }
+
+ // Whether there are modify events.
+ if(0u != impl.mModifyEvents.Count())
+ {
+ // Style operations that need to be done if the text is modified.
+ operationsPending = static_cast<OperationsMask>(operationsPending | COLOR);
+ }
+
+ // Set the update info to elide the text.
+ if(model->mElideEnabled ||
+ ((NULL != impl.mEventData) && impl.mEventData->mIsPlaceholderElideEnabled))
+ {
+ // Update Text layout for applying elided
+ operationsPending = static_cast<OperationsMask>(operationsPending |
+ ALIGN |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER);
+ textUpdateInfo.mFullRelayoutNeeded = true;
+ textUpdateInfo.mCharacterIndex = 0u;
+ }
+
+ bool layoutDirectionChanged = false;
+ if(impl.mLayoutDirection != layoutDirection)
+ {
+ // Flag to indicate that the layout direction has changed.
+ layoutDirectionChanged = true;
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.mClearAll = true;
+ // Apply modifications to the model
+ // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
+ operationsPending = static_cast<OperationsMask>(operationsPending |
+ GET_GLYPH_METRICS |
+ SHAPE_TEXT |
+ UPDATE_DIRECTION |
+ ALIGN |
+ LAYOUT |
+ BIDI_INFO |
+ REORDER);
+ impl.mLayoutDirection = layoutDirection;
+ }
+
+ // Make sure the model is up-to-date before layouting.
+ EventHandler::ProcessModifyEvents(controller);
+ bool updated = impl.UpdateModel(operationsPending);
+
+ // Layout the text.
+ Size layoutSize;
+ updated = DoRelayout(impl, size, operationsPending, layoutSize) || updated;
+
+ if(updated)
+ {
+ updateTextType = MODEL_UPDATED;
+ }
+
+ // Do not re-do any operation until something changes.
+ operationsPending = NO_OPERATION;
+ model->mScrollPositionLast = model->mScrollPosition;
+
+ // Whether the text control is editable
+ const bool isEditable = NULL != impl.mEventData;
+
+ // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
+ Vector2 offset;
+ if(newSize && isEditable)
+ {
+ offset = model->mScrollPosition;
+ }
+
+ if(!isEditable || !controller.IsMultiLineEnabled())
+ {
+ // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
+ CalculateVerticalOffset(impl, size);
+ }
+ else // TextEditor
+ {
+ // If layoutSize is bigger than size, vertical align has no meaning.
+ if(layoutSize.y < size.y)
+ {
+ CalculateVerticalOffset(impl, size);
+ if(impl.mEventData)
+ {
+ impl.mEventData->mScrollAfterDelete = false;
+ }
+ }
+ }
+
+ if(isEditable)
+ {
+ if(newSize || layoutDirectionChanged)
+ {
+ // If there is a new size or layout direction is changed, the scroll position needs to be clamped.
+ impl.ClampHorizontalScroll(layoutSize);
+
+ // Update the decorator's positions is needed if there is a new size.
+ impl.mEventData->mDecorator->UpdatePositions(model->mScrollPosition - offset);
+
+ // All decorator elements need to be updated.
+ if(EventData::IsEditingState(impl.mEventData->mState))
+ {
+ impl.mEventData->mScrollAfterUpdatePosition = true;
+ impl.mEventData->mUpdateCursorPosition = true;
+ impl.mEventData->mUpdateGrabHandlePosition = true;
+ }
+ else if(impl.mEventData->mState == EventData::SELECTING)
+ {
+ impl.mEventData->mUpdateHighlightBox = true;
+ }
+ }
+
+ // Move the cursor, grab handle etc.
+ if(impl.ProcessInputEvents())
+ {
+ updateTextType = static_cast<UpdateTextType>(updateTextType | DECORATOR_UPDATED);
+ }
+ }
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ textUpdateInfo.Clear();
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout\n");
+
+ return updateTextType;
+}
+
+bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size, OperationsMask operationsRequired, Size& layoutSize)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayouter::DoRelayout %p size %f,%f\n", &impl, size.width, size.height);
+ bool viewUpdated(false);
+
+ // Calculate the operations to be done.
+ const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
+
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+ const CharacterIndex startIndex = textUpdateInfo.mParagraphCharacterIndex;
+ const Length requestedNumberOfCharacters = textUpdateInfo.mRequestedNumberOfCharacters;
+
+ // Get the current layout size.
+ VisualModelPtr& visualModel = impl.mModel->mVisualModel;
+ layoutSize = visualModel->GetLayoutSize();
+
+ if(NO_OPERATION != (LAYOUT & operations))
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
+
+ // Some vectors with data needed to layout and reorder may be void
+ // after the first time the text has been laid out.
+ // Fill the vectors again.
+
+ // Calculate the number of glyphs to layout.
+ const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+ const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
+ const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
+
+ const CharacterIndex lastIndex = startIndex + ((requestedNumberOfCharacters > 0u) ? requestedNumberOfCharacters - 1u : 0u);
+ const GlyphIndex startGlyphIndex = textUpdateInfo.mStartGlyphIndex;
+
+ // Make sure the index is not out of bound
+ if(charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
+ requestedNumberOfCharacters > charactersToGlyph.Count() ||
+ (lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u))
+ {
+ std::string currentText;
+ impl.GetText(currentText);
+
+ DALI_LOG_ERROR("Controller::DoRelayout: Attempting to access invalid buffer\n");
+ DALI_LOG_ERROR("Current text is: %s\n", currentText.c_str());
+ DALI_LOG_ERROR("startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
+
+ return false;
+ }
+
+ const Length numberOfGlyphs = (requestedNumberOfCharacters > 0u) ? *(charactersToGlyphBuffer + lastIndex) + *(glyphsPerCharacterBuffer + lastIndex) - startGlyphIndex : 0u;
+ const Length totalNumberOfGlyphs = visualModel->mGlyphs.Count();
+
+ if(0u == totalNumberOfGlyphs)
+ {
+ if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
+ {
+ visualModel->SetLayoutSize(Size::ZERO);
+ }
+
+ // Nothing else to do if there is no glyphs.
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n");
+ return true;
+ }
+
+ // Set the layout parameters.
+ Layout::Parameters layoutParameters(size, impl.mModel);
+
+ // Resize the vector of positions to have the same size than the vector of glyphs.
+ Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+ glyphPositions.Resize(totalNumberOfGlyphs);
+
+ // Whether the last character is a new paragraph character.
+ const Character* const textBuffer = impl.mModel->mLogicalModel->mText.Begin();
+ textUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph(*(textBuffer + (impl.mModel->mLogicalModel->mText.Count() - 1u)));
+ layoutParameters.isLastNewParagraph = textUpdateInfo.mIsLastCharacterNewParagraph;
+
+ // The initial glyph and the number of glyphs to layout.
+ layoutParameters.startGlyphIndex = startGlyphIndex;
+ layoutParameters.numberOfGlyphs = numberOfGlyphs;
+ layoutParameters.startLineIndex = textUpdateInfo.mStartLineIndex;
+ layoutParameters.estimatedNumberOfLines = textUpdateInfo.mEstimatedNumberOfLines;
+
+ // Update the ellipsis
+ bool elideTextEnabled = impl.mModel->mElideEnabled;
+ auto ellipsisPosition = impl.mModel->mEllipsisPosition;
+
+ if(NULL != impl.mEventData)
+ {
+ if(impl.mEventData->mPlaceholderEllipsisFlag && impl.IsShowingPlaceholderText())
+ {
+ elideTextEnabled = impl.mEventData->mIsPlaceholderElideEnabled;
+ }
+ else if(EventData::INACTIVE != impl.mEventData->mState)
+ {
+ // Disable ellipsis when editing
+ elideTextEnabled = false;
+ }
+
+ // Reset the scroll position in inactive state
+ if(elideTextEnabled && (impl.mEventData->mState == EventData::INACTIVE))
+ {
+ impl.ResetScrollPosition();
+ }
+ }
+
+ // Update the visual model.
+ bool isAutoScrollEnabled = impl.mIsAutoScrollEnabled;
+ bool isAutoScrollMaxTextureExceeded = impl.mIsAutoScrollMaxTextureExceeded;
+
+ Size newLayoutSize;
+ viewUpdated = impl.mLayoutEngine.LayoutText(layoutParameters,
+ newLayoutSize,
+ elideTextEnabled,
+ isAutoScrollEnabled,
+ isAutoScrollMaxTextureExceeded,
+ ellipsisPosition);
+ impl.mIsAutoScrollEnabled = isAutoScrollEnabled;
+
+ viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
+
+ if(viewUpdated)
+ {
+ layoutSize = newLayoutSize;
+
+ if(NO_OPERATION != (UPDATE_DIRECTION & operations))
+ {
+ impl.mIsTextDirectionRTL = false;
+ }
+
+ if((NO_OPERATION != (UPDATE_DIRECTION & operations)) && !visualModel->mLines.Empty())
+ {
+ impl.mIsTextDirectionRTL = visualModel->mLines[0u].direction;
+ }
+
+ // Sets the layout size.
+ if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
+ {
+ visualModel->SetLayoutSize(layoutSize);
+ }
+ } // view updated
+ }
+
+ if(NO_OPERATION != (ALIGN & operations))
+ {
+ 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;
+
+ // The laid-out lines.
+ Vector<LineRun>& lines = visualModel->mLines;
+
+ 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,
+ alignStartIndex,
+ alignRequestedNumberOfCharacters,
+ impl.mModel->mHorizontalAlignment,
+ lines,
+ impl.mModel->mAlignmentOffset,
+ impl.mLayoutDirection,
+ (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS));
+ }
+ else
+ {
+ //Override the controller horizontal-alignment by horizontal-alignment of bounded paragraph.
+ const Length& numberOfBoundedParagraphRuns = impl.mModel->GetNumberOfBoundedParagraphRuns();
+ const Vector<BoundedParagraphRun>& boundedParagraphRuns = impl.mModel->GetBoundedParagraphRuns();
+ const CharacterIndex alignEndIndex = alignStartIndex + alignRequestedNumberOfCharacters - 1u;
+
+ 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));
+ }
+ }
+}
+
+void Controller::Relayouter::CalculateVerticalOffset(Controller::Impl& impl, const Size& controlSize)
+{
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+ Size layoutSize = model->mVisualModel->GetLayoutSize();
+ Size oldLayoutSize = layoutSize;
+ float offsetY = 0.f;
+ bool needRecalc = false;
+ float defaultFontLineHeight = impl.GetDefaultFontLineHeight();
+
+ if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
+ {
+ // Get the line height of the default font.
+ layoutSize.height = defaultFontLineHeight;
+ }
+
+ // Whether the text control is editable
+ const bool isEditable = NULL != impl.mEventData;
+ if(isEditable && layoutSize.height != defaultFontLineHeight && impl.IsShowingPlaceholderText())
+ {
+ // This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
+ // This situation occurs when the size of placeholder text is different from the default text.
+ layoutSize.height = defaultFontLineHeight;
+ needRecalc = true;
+ }
+
+ switch(model->mVerticalAlignment)
+ {
+ case VerticalAlignment::TOP:
+ {
+ model->mScrollPosition.y = 0.f;
+ offsetY = 0.f;
+ break;
+ }
+ case VerticalAlignment::CENTER:
+ {
+ model->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
+ if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
+ break;
+ }
+ case VerticalAlignment::BOTTOM:
+ {
+ model->mScrollPosition.y = controlSize.height - layoutSize.height;
+ if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
+ break;
+ }
+ }
+
+ if(needRecalc)
+ {
+ // Update glyphPositions according to recalculation.
+ const Length positionCount = visualModel->mGlyphPositions.Count();
+ Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+ for(Length index = 0u; index < positionCount; index++)
+ {
+ glyphPositions[index].y += offsetY;
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_RELAYOUTER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_RELAYOUTER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor-enumerations.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector3.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * Contains all the relayouting related methods for Text::Controller
+ */
+struct Controller::Relayouter
+{
+ /**
+ * @brief Called by the Controller to retrieve the natural size.
+ *
+ * @param[in] controller A reference to the controller class
+ * @return
+ */
+ static Vector3 GetNaturalSize(Controller& controller);
+
+ /**
+ * @brief Called by the Controller to check if the text fits.
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] pointSize The point size
+ * @param[in] layoutSize The layout size
+ * @return
+ */
+ static bool CheckForTextFit(Controller& controller, float pointSize, const Size& layoutSize);
+
+ /**
+ * @brief Calculates the point size for text for given layout()
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] layoutSize The layout size
+ */
+ static void FitPointSizeforLayout(Controller& controller, const Size& layoutSize);
+
+ /**
+ * @brief Called by the Controller to get the height for a particular width.
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] width The width we want the height for
+ * @return
+ */
+ static float GetHeightForWidth(Controller& controller, float width);
+
+ /**
+ * @brief Called by the Controller to do the relayout itself.
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] size The size to set
+ * @param[in] layoutDirection The layout direction
+ * @return
+ */
+ static Controller::UpdateTextType Relayout(Controller& controller, const Size& size, Dali::LayoutDirection::Type layoutDirection);
+
+ /**
+ * @brief Called by the Controller to do certain operations when relayouting.
+ *
+ * @param[in] impl A reference to the controller impl class
+ * @param[in] size The size to set
+ * @param[in] operationsRequired The operations we need to do
+ * @param[in/out] layoutSize The Layout size which can be updated depending on the result of the performed operations
+ * @return
+ */
+
+ static bool DoRelayout(Controller::Impl& impl, const Size& size, OperationsMask operationsRequired, Size& layoutSize);
+
+ /**
+ * @brief Called by the Controller to calculate the veritcal offset give the control size.
+ *
+ * @param[in] impl A reference to the controller impl class
+ * @param[in] controlSize The control size
+ */
+ static void CalculateVerticalOffset(Controller::Impl& impl, const Size& controlSize);
+
+ /**
+ * @brief Calculates the layout size of control according to @p requestedControllerSize and @p requestedOperationsMask
+ *
+ * GetNaturalSize() and GetHeightForWidth() calls this method.
+ *
+ * @param[in] controller The controller to calcualte size on it.
+ * @param[in] requestedControllerSize The requested size of controller to calcualte layout size on it.
+ * @param[in] requestedOperationsMask The requested operations-mask to calcualte layout size according to it.
+ *
+ * @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
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_RELAYOUTER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/characters-helper-functions.h>
+#include <dali-toolkit/internal/text/emoji-helper.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void Controller::TextUpdater::SetText(Controller& controller, const std::string& text)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText\n");
+
+ Controller::Impl& impl = *controller.mImpl;
+
+ // Reset keyboard as text changed
+ impl.ResetInputMethodContext();
+
+ // Remove the previously set text and style.
+ ResetText(controller);
+
+ // Remove the style.
+ impl.ClearStyleData();
+
+ CharacterIndex lastCursorIndex = 0u;
+
+ EventData*& eventData = impl.mEventData;
+
+ if(nullptr != eventData)
+ {
+ // If popup shown then hide it by switching to Editing state
+ if((EventData::SELECTING == eventData->mState) ||
+ (EventData::EDITING_WITH_POPUP == eventData->mState) ||
+ (EventData::EDITING_WITH_GRAB_HANDLE == eventData->mState) ||
+ (EventData::EDITING_WITH_PASTE_POPUP == eventData->mState))
+ {
+ if((impl.mSelectableControlInterface != nullptr) && (EventData::SELECTING == eventData->mState))
+ {
+ impl.mSelectableControlInterface->SelectionChanged(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition, eventData->mPrimaryCursorPosition, eventData->mPrimaryCursorPosition);
+ }
+
+ impl.ChangeState(EventData::EDITING);
+ }
+ }
+
+ if(!text.empty())
+ {
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+ model->mVisualModel->SetTextColor(impl.mTextColor);
+
+ MarkupProcessData markupProcessData(logicalModel->mColorRuns,
+ logicalModel->mFontDescriptionRuns,
+ logicalModel->mEmbeddedItems,
+ logicalModel->mAnchors,
+ logicalModel->mUnderlinedCharacterRuns,
+ logicalModel->mBackgroundColorRuns,
+ logicalModel->mStrikethroughCharacterRuns,
+ logicalModel->mBoundedParagraphRuns,
+ logicalModel->mCharacterSpacingCharacterRuns);
+
+ Length textSize = 0u;
+ const uint8_t* utf8 = NULL;
+ if(impl.mMarkupProcessorEnabled)
+ {
+ ProcessMarkupString(text, markupProcessData);
+ textSize = markupProcessData.markupProcessedText.size();
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
+ }
+ else
+ {
+ textSize = text.size();
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
+ }
+
+ // Convert text into UTF-32
+ Vector<Character>& utf32Characters = logicalModel->mText;
+ utf32Characters.Resize(textSize);
+
+ // Transform a text array encoded in utf8 into an array encoded in utf32.
+ // It returns the actual number of characters.
+ Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
+ utf32Characters.Resize(characterCount);
+
+ DALI_ASSERT_DEBUG(textSize >= characterCount && "Invalid UTF32 conversion length");
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", &controller, textSize, logicalModel->mText.Count());
+
+ // The characters to be added.
+ impl.mTextUpdateInfo.mNumberOfCharactersToAdd = logicalModel->mText.Count();
+
+ // To reset the cursor position
+ lastCursorIndex = characterCount;
+
+ // Update the rest of the model during size negotiation
+ impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
+
+ // The natural size needs to be re-calculated.
+ impl.mRecalculateNaturalSize = true;
+
+ // The text direction needs to be updated.
+ impl.mUpdateTextDirection = true;
+
+ // Apply modifications to the model
+ impl.mOperationsPending = ALL_OPERATIONS;
+ }
+ else
+ {
+ PlaceholderHandler::ShowPlaceholderText(impl);
+ }
+
+ unsigned int oldCursorPos = (nullptr != eventData ? eventData->mPrimaryCursorPosition : 0);
+
+ // Resets the cursor position.
+ controller.ResetCursorPosition(lastCursorIndex);
+
+ // Scrolls the text to make the cursor visible.
+ impl.ResetScrollPosition();
+
+ impl.RequestRelayout();
+
+ if(nullptr != eventData)
+ {
+ // Cancel previously queued events
+ eventData->mEventQueue.clear();
+ }
+
+ // Do this last since it provides callbacks into application code.
+ if(NULL != impl.mEditableControlInterface)
+ {
+ impl.mEditableControlInterface->CursorPositionChanged(oldCursorPos, lastCursorIndex);
+ impl.mEditableControlInterface->TextChanged(true);
+ }
+}
+
+void Controller::TextUpdater::InsertText(Controller& controller, const std::string& text, Controller::InsertType type)
+{
+ Controller::Impl& impl = *controller.mImpl;
+ EventData*& eventData = impl.mEventData;
+
+ DALI_ASSERT_DEBUG(nullptr != eventData && "Unexpected InsertText")
+
+ if(NULL == eventData)
+ {
+ return;
+ }
+
+ bool removedPrevious = false;
+ bool removedSelected = false;
+ bool maxLengthReached = false;
+ unsigned int oldCursorPos = eventData->mPrimaryCursorPosition;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n", &controller, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"), eventData->mPrimaryCursorPosition, eventData->mPreEditFlag, eventData->mPreEditStartPosition, eventData->mPreEditLength);
+
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+
+ // TODO: At the moment the underline runs are only for pre-edit.
+ model->mVisualModel->mUnderlineRuns.Clear();
+
+ // Remove the previous InputMethodContext pre-edit.
+ if(eventData->mPreEditFlag && (0u != eventData->mPreEditLength))
+ {
+ removedPrevious = RemoveText(controller,
+ -static_cast<int>(eventData->mPrimaryCursorPosition - eventData->mPreEditStartPosition),
+ eventData->mPreEditLength,
+ DONT_UPDATE_INPUT_STYLE);
+
+ eventData->mPrimaryCursorPosition = eventData->mPreEditStartPosition;
+ eventData->mPreEditLength = 0u;
+ }
+ else
+ {
+ // Remove the previous Selection.
+ removedSelected = RemoveSelectedText(controller);
+ }
+
+ Vector<Character> utf32Characters;
+ Length characterCount = 0u;
+
+ if(!text.empty())
+ {
+ // Convert text into UTF-32
+ utf32Characters.Resize(text.size());
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
+
+ // Transform a text array encoded in utf8 into an array encoded in utf32.
+ // It returns the actual number of characters.
+ characterCount = Utf8ToUtf32(utf8, text.size(), utf32Characters.Begin());
+ utf32Characters.Resize(characterCount);
+
+ DALI_ASSERT_DEBUG(text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count());
+ }
+
+ if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
+ {
+ // The placeholder text is no longer needed
+ if(impl.IsShowingPlaceholderText())
+ {
+ ResetText(controller);
+ }
+
+ impl.ChangeState(EventData::EDITING);
+
+ // Handle the InputMethodContext (predicitive text) state changes
+ if(COMMIT == type)
+ {
+ // InputMethodContext is no longer handling key-events
+ impl.ClearPreEditFlag();
+ }
+ else // PRE_EDIT
+ {
+ if(!eventData->mPreEditFlag)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
+
+ // Record the start of the pre-edit text
+ eventData->mPreEditStartPosition = eventData->mPrimaryCursorPosition;
+ }
+
+ eventData->mPreEditLength = utf32Characters.Count();
+ eventData->mPreEditFlag = true;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", eventData->mPreEditStartPosition, eventData->mPreEditLength);
+ }
+
+ const Length numberOfCharactersInModel = logicalModel->mText.Count();
+
+ // Restrict new text to fit within Maximum characters setting.
+ Length temp_length = (impl.mMaximumNumberOfCharacters > numberOfCharactersInModel ? impl.mMaximumNumberOfCharacters - numberOfCharactersInModel : 0);
+ Length maxSizeOfNewText = std::min(temp_length, characterCount);
+ maxLengthReached = (characterCount > maxSizeOfNewText);
+
+ // The cursor position.
+ CharacterIndex& cursorIndex = eventData->mPrimaryCursorPosition;
+
+ // Update the text's style.
+
+ // Updates the text style runs by adding characters.
+ logicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
+
+ // Get the character index from the cursor index.
+ const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
+
+ // Retrieve the text's style for the given index.
+ InputStyle style;
+ impl.RetrieveDefaultInputStyle(style);
+ logicalModel->RetrieveStyle(styleIndex, style);
+
+ InputStyle& inputStyle = eventData->mInputStyle;
+
+ // Whether to add a new text color run.
+ const bool addColorRun = (style.textColor != inputStyle.textColor) && !inputStyle.isDefaultColor;
+
+ // Whether to add a new font run.
+ const bool addFontNameRun = (style.familyName != inputStyle.familyName) && inputStyle.isFamilyDefined;
+ const bool addFontWeightRun = (style.weight != inputStyle.weight) && inputStyle.isWeightDefined;
+ const bool addFontWidthRun = (style.width != inputStyle.width) && inputStyle.isWidthDefined;
+ const bool addFontSlantRun = (style.slant != inputStyle.slant) && inputStyle.isSlantDefined;
+ const bool addFontSizeRun = (style.size != inputStyle.size) && inputStyle.isSizeDefined;
+
+ // Add style runs.
+ if(addColorRun)
+ {
+ const VectorBase::SizeType numberOfRuns = logicalModel->mColorRuns.Count();
+ logicalModel->mColorRuns.Resize(numberOfRuns + 1u);
+
+ ColorRun& colorRun = *(logicalModel->mColorRuns.Begin() + numberOfRuns);
+ colorRun.color = inputStyle.textColor;
+ colorRun.characterRun.characterIndex = cursorIndex;
+ colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
+ }
+
+ if(addFontNameRun ||
+ addFontWeightRun ||
+ addFontWidthRun ||
+ addFontSlantRun ||
+ addFontSizeRun)
+ {
+ const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
+ logicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
+
+ FontDescriptionRun& fontDescriptionRun = *(logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
+
+ if(addFontNameRun)
+ {
+ fontDescriptionRun.familyLength = inputStyle.familyName.size();
+ fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+ memcpy(fontDescriptionRun.familyName, inputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
+ fontDescriptionRun.familyDefined = true;
+
+ // The memory allocated for the font family name is freed when the font description is removed from the logical model.
+ }
+
+ if(addFontWeightRun)
+ {
+ fontDescriptionRun.weight = inputStyle.weight;
+ fontDescriptionRun.weightDefined = true;
+ }
+
+ if(addFontWidthRun)
+ {
+ fontDescriptionRun.width = inputStyle.width;
+ fontDescriptionRun.widthDefined = true;
+ }
+
+ if(addFontSlantRun)
+ {
+ fontDescriptionRun.slant = inputStyle.slant;
+ fontDescriptionRun.slantDefined = true;
+ }
+
+ if(addFontSizeRun)
+ {
+ fontDescriptionRun.size = static_cast<PointSize26Dot6>(inputStyle.size * impl.GetFontSizeScale() * 64.f);
+ fontDescriptionRun.sizeDefined = true;
+ }
+
+ fontDescriptionRun.characterRun.characterIndex = cursorIndex;
+ fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
+ }
+
+ // Insert at current cursor position.
+ Vector<Character>& modifyText = logicalModel->mText;
+
+ auto pos = modifyText.End();
+ if(cursorIndex < numberOfCharactersInModel)
+ {
+ pos = modifyText.Begin() + cursorIndex;
+ }
+ unsigned int realPos = pos - modifyText.Begin();
+ modifyText.Insert(pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
+
+ if(NULL != impl.mEditableControlInterface)
+ {
+ impl.mEditableControlInterface->TextInserted(realPos, maxSizeOfNewText, text);
+ }
+
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+ // Mark the first paragraph to be updated.
+ if(Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout())
+ {
+ textUpdateInfo.mCharacterIndex = 0;
+ textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
+ textUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
+ textUpdateInfo.mClearAll = true;
+ }
+ else
+ {
+ textUpdateInfo.mCharacterIndex = std::min(cursorIndex, textUpdateInfo.mCharacterIndex);
+ textUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
+ }
+
+ if(impl.mMarkupProcessorEnabled)
+ {
+ InsertTextAnchor(controller, maxSizeOfNewText, cursorIndex);
+ }
+
+ // Update the cursor index.
+ cursorIndex += maxSizeOfNewText;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition);
+ }
+
+ if((0u == logicalModel->mText.Count()) &&
+ impl.IsPlaceholderAvailable())
+ {
+ // Show place-holder if empty after removing the pre-edit text
+ PlaceholderHandler::ShowPlaceholderText(impl);
+ eventData->mUpdateCursorPosition = true;
+ impl.ClearPreEditFlag();
+ }
+ else if(removedPrevious ||
+ removedSelected ||
+ (0 != utf32Characters.Count()))
+ {
+ // Queue an inserted event
+ impl.QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
+
+ eventData->mUpdateCursorPosition = true;
+ if(removedSelected)
+ {
+ eventData->mScrollAfterDelete = true;
+ }
+ else
+ {
+ eventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+
+ if(nullptr != impl.mEditableControlInterface)
+ {
+ impl.mEditableControlInterface->CursorPositionChanged(oldCursorPos, eventData->mPrimaryCursorPosition);
+ }
+
+ if(maxLengthReached)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", logicalModel->mText.Count());
+
+ impl.ResetInputMethodContext();
+
+ if(NULL != impl.mEditableControlInterface)
+ {
+ // Do this last since it provides callbacks into application code
+ impl.mEditableControlInterface->MaxLengthReached();
+ }
+ }
+}
+
+void Controller::TextUpdater::PasteText(Controller& controller, const std::string& stringToPaste)
+{
+ InsertText(controller, stringToPaste, Text::Controller::COMMIT);
+ Controller::Impl& impl = *controller.mImpl;
+ impl.ChangeState(EventData::EDITING);
+ impl.RequestRelayout();
+
+ if(NULL != impl.mEditableControlInterface)
+ {
+ // Do this last since it provides callbacks into application code
+ impl.mEditableControlInterface->TextChanged(true);
+ }
+}
+
+bool Controller::TextUpdater::RemoveText(
+ Controller& controller,
+ int cursorOffset,
+ int numberOfCharacters,
+ UpdateInputStyleType type)
+{
+ bool removed = false;
+ bool removeAll = false;
+
+ Controller::Impl& impl = *controller.mImpl;
+ EventData*& eventData = impl.mEventData;
+
+ if(nullptr == eventData)
+ {
+ return removed;
+ }
+
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", &controller, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters);
+
+ if(!impl.IsShowingPlaceholderText())
+ {
+ // Delete at current cursor position
+ Vector<Character>& currentText = logicalModel->mText;
+ CharacterIndex& previousCursorIndex = eventData->mPrimaryCursorPosition;
+
+ CharacterIndex cursorIndex = 0;
+
+ // Validate the cursor position & number of characters
+ if((static_cast<int>(eventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
+ {
+ cursorIndex = eventData->mPrimaryCursorPosition + cursorOffset;
+ }
+
+ //Handle Emoji clustering for cursor handling
+ // Deletion case: this is handling the deletion cases when the cursor is before or after Emoji
+ // - Before: when use delete key and cursor is before Emoji (cursorOffset = -1)
+ // - After: when use backspace key and cursor is after Emoji (cursorOffset = 0)
+
+ const Script script = logicalModel->GetScript(cursorIndex);
+ if((numberOfCharacters == 1u) &&
+ (IsOneOfEmojiScripts(script)))
+ {
+ //TODO: Use this clustering for Emoji cases only. This needs more testing to generalize to all scripts.
+ CharacterRun emojiClusteredCharacters = RetrieveClusteredCharactersOfCharacterIndex(visualModel, logicalModel, cursorIndex);
+ Length actualNumberOfCharacters = emojiClusteredCharacters.numberOfCharacters;
+
+ //Set cursorIndex at the first characterIndex of clustred Emoji
+ cursorIndex = emojiClusteredCharacters.characterIndex;
+
+ numberOfCharacters = actualNumberOfCharacters;
+ }
+
+ if((cursorIndex + numberOfCharacters) > currentText.Count())
+ {
+ numberOfCharacters = currentText.Count() - cursorIndex;
+ }
+
+ if((cursorIndex == 0) && (currentText.Count() - numberOfCharacters == 0))
+ {
+ removeAll = true;
+ }
+
+ TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+ if(eventData->mPreEditFlag || removeAll || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
+ ((cursorIndex + numberOfCharacters) <= textUpdateInfo.mPreviousNumberOfCharacters))
+ {
+ // Mark the paragraphs to be updated.
+ if(Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout())
+ {
+ textUpdateInfo.mCharacterIndex = 0;
+ textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
+ textUpdateInfo.mNumberOfCharactersToAdd = textUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
+ textUpdateInfo.mClearAll = true;
+ }
+ else
+ {
+ textUpdateInfo.mCharacterIndex = std::min(cursorIndex, textUpdateInfo.mCharacterIndex);
+ textUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
+ }
+
+ // Update the input style and remove the text's style before removing the text.
+
+ if(UPDATE_INPUT_STYLE == type)
+ {
+ InputStyle& eventDataInputStyle = eventData->mInputStyle;
+
+ // Keep a copy of the current input style.
+ InputStyle currentInputStyle;
+ currentInputStyle.Copy(eventDataInputStyle);
+
+ // Set first the default input style.
+ impl.RetrieveDefaultInputStyle(eventDataInputStyle);
+
+ // Update the input style.
+ logicalModel->RetrieveStyle(cursorIndex, eventDataInputStyle);
+
+ // Compare if the input style has changed.
+ const bool hasInputStyleChanged = !currentInputStyle.Equal(eventDataInputStyle);
+
+ if(hasInputStyleChanged)
+ {
+ const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(eventDataInputStyle);
+ // Queue the input style changed signal.
+ eventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
+ }
+ }
+
+ // If the number of current text and the number of characters to be deleted are same,
+ // it means all texts should be removed and all Preedit variables should be initialized.
+ if(removeAll)
+ {
+ impl.ClearPreEditFlag();
+ textUpdateInfo.mNumberOfCharactersToAdd = 0;
+ }
+
+ // Updates the text style runs by removing characters. Runs with no characters are removed.
+ logicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
+
+ // Remove the characters.
+ Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
+ Vector<Character>::Iterator last = first + numberOfCharacters;
+
+ if(NULL != impl.mEditableControlInterface)
+ {
+ std::string utf8;
+ Utf32ToUtf8(first, numberOfCharacters, utf8);
+ impl.mEditableControlInterface->TextDeleted(cursorIndex, numberOfCharacters, utf8);
+ }
+
+ currentText.Erase(first, last);
+
+ if(impl.mMarkupProcessorEnabled)
+ {
+ RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
+ }
+
+ if(nullptr != impl.mEditableControlInterface)
+ {
+ impl.mEditableControlInterface->CursorPositionChanged(previousCursorIndex, cursorIndex);
+ }
+
+ // Cursor position retreat
+ previousCursorIndex = cursorIndex;
+
+ eventData->mScrollAfterDelete = true;
+
+ if(EventData::INACTIVE == eventData->mState)
+ {
+ impl.ChangeState(EventData::EDITING);
+ }
+
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", &controller, numberOfCharacters);
+ removeAll = false;
+ removed = true;
+ }
+ }
+
+ return removed;
+}
+
+bool Controller::TextUpdater::RemoveSelectedText(Controller& controller)
+{
+ bool textRemoved(false);
+
+ Controller::Impl& impl = *controller.mImpl;
+
+ if(EventData::SELECTING == impl.mEventData->mState)
+ {
+ std::string removedString;
+ uint32_t oldSelStart = impl.mEventData->mLeftSelectionPosition;
+ uint32_t oldSelEnd = impl.mEventData->mRightSelectionPosition;
+
+ impl.RetrieveSelection(removedString, true);
+
+ if(!removedString.empty())
+ {
+ textRemoved = true;
+ impl.ChangeState(EventData::EDITING);
+
+ if(impl.mMarkupProcessorEnabled)
+ {
+ int cursorOffset = -1;
+ int numberOfCharacters = removedString.length();
+ CharacterIndex& cursorIndex = impl.mEventData->mPrimaryCursorPosition;
+ CharacterIndex previousCursorIndex = cursorIndex + numberOfCharacters;
+
+ RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
+ }
+
+ if(impl.mSelectableControlInterface != nullptr)
+ {
+ impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, impl.mEventData->mPrimaryCursorPosition, impl.mEventData->mPrimaryCursorPosition);
+ }
+ }
+ }
+
+ return textRemoved;
+}
+
+void Controller::TextUpdater::ResetText(Controller& controller)
+{
+ Controller::Impl& impl = *controller.mImpl;
+ LogicalModelPtr& logicalModel = impl.mModel->mLogicalModel;
+
+ // Reset buffers.
+ logicalModel->mText.Clear();
+
+ // Reset the embedded images buffer.
+ logicalModel->ClearEmbeddedImages();
+
+ // Reset the anchors buffer.
+ logicalModel->ClearAnchors();
+
+ // We have cleared everything including the placeholder-text
+ impl.PlaceholderCleared();
+
+ impl.mTextUpdateInfo.mCharacterIndex = 0u;
+ impl.mTextUpdateInfo.mNumberOfCharactersToRemove = impl.mTextUpdateInfo.mPreviousNumberOfCharacters;
+ impl.mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
+
+ // Clear any previous text.
+ impl.mTextUpdateInfo.mClearAll = true;
+
+ // The natural size needs to be re-calculated.
+ impl.mRecalculateNaturalSize = true;
+
+ // The text direction needs to be updated.
+ impl.mUpdateTextDirection = true;
+
+ // Apply modifications to the model
+ impl.mOperationsPending = ALL_OPERATIONS;
+}
+
+void Controller::TextUpdater::InsertTextAnchor(Controller& controller, int numberOfCharacters, CharacterIndex previousCursorIndex)
+{
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+
+ for(auto& anchor : logicalModel->mAnchors)
+ {
+ if(anchor.endIndex < previousCursorIndex) // [anchor] CUR
+ {
+ continue;
+ }
+ if(anchor.startIndex < previousCursorIndex) // [anCURr]
+ {
+ anchor.endIndex += numberOfCharacters;
+ }
+ else // CUR [anchor]
+ {
+ anchor.startIndex += numberOfCharacters;
+ anchor.endIndex += numberOfCharacters;
+ }
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::InsertTextAnchor[%p] Anchor[%s] start[%d] end[%d]\n", &controller, anchor.href, anchor.startIndex, anchor.endIndex);
+ }
+}
+
+void Controller::TextUpdater::RemoveTextAnchor(Controller& controller, int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex)
+{
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ LogicalModelPtr& logicalModel = model->mLogicalModel;
+ Vector<Anchor>::Iterator it = logicalModel->mAnchors.Begin();
+
+ while(it != logicalModel->mAnchors.End())
+ {
+ Anchor& anchor = *it;
+
+ if(anchor.endIndex <= previousCursorIndex && cursorOffset == 0) // [anchor] CUR >>
+ {
+ // Nothing happens.
+ }
+ else if(anchor.endIndex <= previousCursorIndex && cursorOffset == -1) // [anchor] << CUR
+ {
+ int endIndex = anchor.endIndex;
+ int offset = previousCursorIndex - endIndex;
+ int index = endIndex - (numberOfCharacters - offset);
+
+ if(index < endIndex)
+ {
+ endIndex = index;
+ }
+
+ if((int)anchor.startIndex >= endIndex)
+ {
+ if(anchor.href)
+ {
+ delete[] anchor.href;
+ }
+ it = logicalModel->mAnchors.Erase(it);
+ continue;
+ }
+ else
+ {
+ anchor.endIndex = endIndex;
+ }
+ }
+ else if(anchor.startIndex >= previousCursorIndex && cursorOffset == -1) // << CUR [anchor]
+ {
+ anchor.startIndex -= numberOfCharacters;
+ anchor.endIndex -= numberOfCharacters;
+ }
+ else if(anchor.startIndex >= previousCursorIndex && cursorOffset == 0) // CUR >> [anchor]
+ {
+ int startIndex = anchor.startIndex;
+ int endIndex = anchor.endIndex;
+ int index = previousCursorIndex + numberOfCharacters - 1;
+
+ if(startIndex > index)
+ {
+ anchor.startIndex -= numberOfCharacters;
+ anchor.endIndex -= numberOfCharacters;
+ }
+ else if(endIndex > index + 1)
+ {
+ anchor.endIndex -= numberOfCharacters;
+ }
+ else
+ {
+ if(anchor.href)
+ {
+ delete[] anchor.href;
+ }
+ it = logicalModel->mAnchors.Erase(it);
+ continue;
+ }
+ }
+ else if(cursorOffset == -1) // [<< CUR]
+ {
+ int startIndex = anchor.startIndex;
+ int index = previousCursorIndex - numberOfCharacters;
+
+ if(startIndex >= index)
+ {
+ anchor.startIndex = index;
+ }
+ anchor.endIndex -= numberOfCharacters;
+ }
+ else if(cursorOffset == 0) // [CUR >>]
+ {
+ anchor.endIndex -= numberOfCharacters;
+ }
+ else
+ {
+ // When this condition is reached, someting is wrong.
+ DALI_LOG_ERROR("Controller::RemoveTextAnchor[%p] Invaild state cursorOffset[%d]\n", &controller, cursorOffset);
+ }
+
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveTextAnchor[%p] Anchor[%s] start[%d] end[%d]\n", &controller, anchor.href, anchor.startIndex, anchor.endIndex);
+
+ it++;
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_UPDATER_H
+#define DALI_TOOLKIT_TEXT_UPDATER_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 <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Methods that update the text
+ */
+struct Controller::TextUpdater
+{
+ /// @copydoc Text::Contoller::SetText
+ /// @param[in] controller The controller
+ static void SetText(Controller& controller, const std::string& text);
+
+ /**
+ * @brief Called by editable UI controls when key events are received.
+ *
+ * @param[in] controller The controller
+ * @param[in] text The text to insert.
+ * @param[in] type Used to distinguish between regular key events and InputMethodContext events.
+ */
+ static void InsertText(Controller& controller, const std::string& text, Controller::InsertType type);
+
+ /// @copydoc Text::EditableControlInterface::PasteText()
+ /// @param[in] controller The controller
+ static void PasteText(Controller& controller, const std::string& stringToPaste);
+
+ /**
+ * @brief Remove a given number of characters
+ *
+ * When predictve text is used the pre-edit text is removed and inserted again with the new characters.
+ * The UpdateInputStyleType @type parameter if set to DONT_UPDATE_INPUT_STYLE avoids to update the input
+ * style when pre-edit text is removed.
+ *
+ * @param[in] controller The controller
+ * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
+ * @param[in] numberOfCharacters The number of characters to delete from the cursorOffset.
+ * @param[in] type Whether to update the input style.
+ * @return True if the remove was successful.
+ */
+ static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type);
+
+ /**
+ * @brief Checks if text is selected and if so removes it.
+ * @param[in] controller The controller
+ * @return true if text was removed
+ */
+ static bool RemoveSelectedText(Controller& controller);
+
+ /**
+ * @brief Used to remove the text included the placeholder text.
+ * @param[in] controller The controller
+ */
+ static void ResetText(Controller& controller);
+
+ /**
+ * @brief Update anchor position from given number of inserted characters.
+ *
+ * @param[in] controller The controller
+ * @param[in] numberOfCharacters The number of inserted characters.
+ * @param[in] previousCursorIndex A cursor position before event occurs.
+ */
+ static void InsertTextAnchor(Controller& controller, int numberOfCharacters, CharacterIndex previousCursorIndex);
+
+ /**
+ * @brief Update anchor position from given number of removed characters.
+ *
+ * @param[in] controller The controller
+ * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
+ * @param[in] numberOfCharacters The number of removed characters.
+ * @param[in] previousCursorIndex A cursor position before event occurs.
+ */
+ static void RemoveTextAnchor(Controller& controller, int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex);
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UPDATER_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/controller/text-controller.h>
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/integration-api/debug.h>
+#include <memory.h>
+#include <cmath>
+#include <limits>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/text/controller/text-controller-background-actor.h>
+#include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/controller/text-controller-input-font-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-input-properties.h>
+#include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-relayouter.h>
+#include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-geometry.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const std::string EMPTY_STRING("");
+
+template<typename Type>
+void EnsureCreated(Type*& object)
+{
+ if(!object)
+ {
+ object = new Type();
+ }
+}
+
+template<typename Type>
+void EnsureCreated(std::unique_ptr<Type>& object)
+{
+ if(!object)
+ {
+ object = std::unique_ptr<Type>(new Type());
+ }
+}
+
+template<typename Type, typename Arg1>
+void EnsureCreated(Type*& object, Arg1 arg1)
+{
+ if(!object)
+ {
+ object = new Type(arg1);
+ }
+}
+
+template<typename Type, typename Arg1, typename Arg2>
+void EnsureCreated(Type*& object, Arg1 arg1, Arg2 arg2)
+{
+ if(!object)
+ {
+ object = new Type(arg1, arg2);
+ }
+}
+
+float GetDpi()
+{
+ unsigned int horizontalDpi = 0u;
+ unsigned int verticalDpi = 0u;
+ Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+ fontClient.GetDpi(horizontalDpi, verticalDpi);
+ return static_cast<float>(horizontalDpi);
+}
+
+float ConvertPixelToPoint(float pixel)
+{
+ return pixel * 72.0f / GetDpi();
+}
+
+float ConvertPointToPixel(float point)
+{
+ // Pixel size = Point size * DPI / 72.f
+ return point * GetDpi() / 72.0f;
+}
+
+void UpdateCursorPosition(Dali::Toolkit::Text::EventData* eventData)
+{
+ if(eventData && Dali::Toolkit::Text::EventData::IsEditingState(eventData->mState))
+ {
+ // Update the cursor position if it's in editing mode
+ eventData->mDecoratorUpdated = true;
+ eventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
+ }
+}
+
+} // namespace
+
+namespace Dali::Toolkit::Text
+{
+void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
+{
+ if(!decorator)
+ {
+ delete mImpl->mEventData;
+ mImpl->mEventData = NULL;
+
+ // Nothing else to do.
+ return;
+ }
+
+ EnsureCreated(mImpl->mEventData, decorator, inputMethodContext);
+}
+
+void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
+{
+ // Metrics for bitmap & vector based glyphs are different
+ mImpl->mMetrics->SetGlyphType(glyphType);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+void Controller::SetMarkupProcessorEnabled(bool enable)
+{
+ if(enable != mImpl->mMarkupProcessorEnabled)
+ {
+ //If Text was already set, call the SetText again for enabling or disabling markup
+ mImpl->mMarkupProcessorEnabled = enable;
+ std::string text;
+ GetText(text);
+ SetText(text);
+ }
+
+ mImpl->mModel->mVisualModel->SetMarkupProcessorEnabled(enable);
+}
+
+bool Controller::IsMarkupProcessorEnabled() const
+{
+ return mImpl->mMarkupProcessorEnabled;
+}
+
+bool Controller::HasAnchors() const
+{
+ return (mImpl->mMarkupProcessorEnabled && mImpl->mModel->mLogicalModel->mAnchors.Count() && mImpl->IsShowingRealText());
+}
+
+void Controller::SetAutoScrollEnabled(bool enable)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable) ? "true" : "false", (mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) ? "true" : "false", this);
+ mImpl->SetAutoScrollEnabled(enable);
+}
+
+void Controller::SetAutoScrollMaxTextureExceeded(bool exceed)
+{
+ mImpl->mIsAutoScrollMaxTextureExceeded = exceed;
+}
+
+bool Controller::IsAutoScrollEnabled() const
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
+ return mImpl->mIsAutoScrollEnabled;
+}
+
+CharacterDirection Controller::GetAutoScrollDirection() const
+{
+ return mImpl->mIsTextDirectionRTL;
+}
+
+float Controller::GetAutoScrollLineAlignment() const
+{
+ float offset = 0.f;
+ if(mImpl->mModel->mVisualModel && (0u != mImpl->mModel->mVisualModel->mLines.Count()))
+ {
+ offset = (*mImpl->mModel->mVisualModel->mLines.Begin()).alignmentOffset;
+ }
+ return offset;
+}
+
+void Controller::SetHorizontalScrollEnabled(bool enable)
+{
+ if(mImpl->mEventData && mImpl->mEventData->mDecorator)
+ {
+ mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled(enable);
+ }
+}
+
+bool Controller::IsHorizontalScrollEnabled() const
+{
+ return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
+}
+
+void Controller::SetVerticalScrollEnabled(bool enable)
+{
+ if(mImpl->mEventData && mImpl->mEventData->mDecorator)
+ {
+ mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
+ }
+}
+
+bool Controller::IsVerticalScrollEnabled() const
+{
+ return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
+}
+
+void Controller::SetSmoothHandlePanEnabled(bool enable)
+{
+ if(mImpl->mEventData && mImpl->mEventData->mDecorator)
+ {
+ mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled(enable);
+ }
+}
+
+bool Controller::IsSmoothHandlePanEnabled() const
+{
+ return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
+}
+
+void Controller::SetMaximumNumberOfCharacters(Length maxCharacters)
+{
+ mImpl->mMaximumNumberOfCharacters = maxCharacters;
+}
+
+int Controller::GetMaximumNumberOfCharacters()
+{
+ return mImpl->mMaximumNumberOfCharacters;
+}
+
+void Controller::SetEnableCursorBlink(bool enable)
+{
+ mImpl->SetEnableCursorBlink(enable);
+}
+
+bool Controller::GetEnableCursorBlink() const
+{
+ return mImpl->mEventData && mImpl->mEventData->mCursorBlinkEnabled;
+}
+
+void Controller::SetMultiLineEnabled(bool enable)
+{
+ mImpl->SetMultiLineEnabled(enable);
+}
+
+bool Controller::IsMultiLineEnabled() const
+{
+ return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
+}
+
+void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
+{
+ mImpl->SetHorizontalAlignment(alignment);
+}
+
+Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
+{
+ return mImpl->mModel->mHorizontalAlignment;
+}
+
+void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
+{
+ mImpl->SetVerticalAlignment(alignment);
+}
+
+VerticalAlignment::Type Controller::GetVerticalAlignment() const
+{
+ return mImpl->mModel->mVerticalAlignment;
+}
+
+bool Controller::IsIgnoreSpacesAfterText() const
+{
+ return mImpl->mModel->mIgnoreSpacesAfterText;
+}
+
+void Controller::SetIgnoreSpacesAfterText(bool ignore)
+{
+ mImpl->mModel->mIgnoreSpacesAfterText = ignore;
+}
+
+void Controller::ChangedLayoutDirection()
+{
+ mImpl->mIsLayoutDirectionChanged = true;
+}
+
+void Controller::SetMatchLayoutDirection(DevelText::MatchLayoutDirection type)
+{
+ mImpl->mModel->mMatchLayoutDirection = type;
+}
+
+DevelText::MatchLayoutDirection Controller::GetMatchLayoutDirection() const
+{
+ return mImpl->mModel->mMatchLayoutDirection;
+}
+
+void Controller::SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection)
+{
+ mImpl->mLayoutDirection = layoutDirection;
+}
+
+Dali::LayoutDirection::Type Controller::GetLayoutDirection(Dali::Actor& actor) const
+{
+ return mImpl->GetLayoutDirection(actor);
+}
+
+bool Controller::IsShowingRealText() const
+{
+ return mImpl->IsShowingRealText();
+}
+
+void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
+{
+ mImpl->SetLineWrapMode(lineWrapMode);
+}
+
+Text::LineWrap::Mode Controller::GetLineWrapMode() const
+{
+ return mImpl->mModel->mLineWrapMode;
+}
+
+void Controller::SetTextElideEnabled(bool enabled)
+{
+ mImpl->mModel->mElideEnabled = enabled;
+ mImpl->mModel->mVisualModel->SetTextElideEnabled(enabled);
+}
+
+bool Controller::IsTextElideEnabled() const
+{
+ return mImpl->mModel->mElideEnabled;
+}
+
+void Controller::SetTextFitEnabled(bool enabled)
+{
+ mImpl->mTextFitEnabled = enabled;
+}
+
+bool Controller::IsTextFitEnabled() const
+{
+ return mImpl->mTextFitEnabled;
+}
+
+void Controller::SetTextFitChanged(bool changed)
+{
+ mImpl->mTextFitChanged = changed;
+}
+
+bool Controller::IsTextFitChanged() const
+{
+ return mImpl->mTextFitChanged;
+}
+
+void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
+{
+ mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize);
+}
+
+float Controller::GetTextFitMinSize() const
+{
+ return mImpl->mTextFitMinSize;
+}
+
+void Controller::SetTextFitMaxSize(float maxSize, FontSizeType type)
+{
+ mImpl->mTextFitMaxSize = (type == POINT_SIZE) ? maxSize : ConvertPixelToPoint(maxSize);
+}
+
+float Controller::GetTextFitMaxSize() const
+{
+ return mImpl->mTextFitMaxSize;
+}
+
+void Controller::SetTextFitStepSize(float step, FontSizeType type)
+{
+ mImpl->mTextFitStepSize = (type == POINT_SIZE) ? step : ConvertPixelToPoint(step);
+}
+
+float Controller::GetTextFitStepSize() const
+{
+ return mImpl->mTextFitStepSize;
+}
+
+void Controller::SetTextFitContentSize(Vector2 size)
+{
+ mImpl->mTextFitContentSize = size;
+}
+
+Vector2 Controller::GetTextFitContentSize() const
+{
+ return mImpl->mTextFitContentSize;
+}
+
+float Controller::GetTextFitPointSize() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFitPointSize : 0.0f;
+}
+
+void Controller::SetPlaceholderTextElideEnabled(bool enabled)
+{
+ PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
+}
+
+bool Controller::IsPlaceholderTextElideEnabled() const
+{
+ return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
+}
+
+void Controller::SetSelectionEnabled(bool enabled)
+{
+ mImpl->mEventData->mSelectionEnabled = enabled;
+}
+
+bool Controller::IsSelectionEnabled() const
+{
+ return mImpl->mEventData->mSelectionEnabled;
+}
+
+void Controller::SetShiftSelectionEnabled(bool enabled)
+{
+ mImpl->mEventData->mShiftSelectionFlag = enabled;
+}
+
+bool Controller::IsShiftSelectionEnabled() const
+{
+ return mImpl->mEventData->mShiftSelectionFlag;
+}
+
+void Controller::SetGrabHandleEnabled(bool enabled)
+{
+ mImpl->mEventData->mGrabHandleEnabled = enabled;
+}
+
+bool Controller::IsGrabHandleEnabled() const
+{
+ return mImpl->mEventData->mGrabHandleEnabled;
+}
+
+void Controller::SetGrabHandlePopupEnabled(bool enabled)
+{
+ mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
+}
+
+bool Controller::IsGrabHandlePopupEnabled() const
+{
+ return mImpl->mEventData->mGrabHandlePopupEnabled;
+}
+
+void Controller::SetText(const std::string& text)
+{
+ TextUpdater::SetText(*this, text);
+}
+
+void Controller::GetText(std::string& text) const
+{
+ mImpl->GetText(text);
+}
+
+void Controller::SetPlaceholderText(PlaceholderType type, const std::string& text)
+{
+ PlaceholderHandler::SetPlaceholderText(*this, type, text);
+}
+
+void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) const
+{
+ PlaceholderHandler::GetPlaceholderText(*this, type, text);
+}
+
+void Controller::UpdateAfterFontChange(const std::string& newDefaultFont)
+{
+ mImpl->UpdateAfterFontChange(newDefaultFont);
+}
+
+void Controller::RetrieveSelection(std::string& selectedText) const
+{
+ mImpl->RetrieveSelection(selectedText, false);
+}
+
+void Controller::SetSelection(int start, int end)
+{
+ mImpl->SetSelection(start, end);
+}
+
+std::pair<int, int> Controller::GetSelectionIndexes() const
+{
+ return mImpl->GetSelectionIndexes();
+}
+
+void Controller::CopyStringToClipboard(const std::string& source)
+{
+ mImpl->CopyStringToClipboard(source);
+}
+
+void Controller::SendSelectionToClipboard(bool deleteAfterSending)
+{
+ mImpl->SendSelectionToClipboard(deleteAfterSending);
+}
+
+void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
+{
+ EnsureCreated(mImpl->mFontDefaults);
+
+ mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
+ DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
+ mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+const std::string& Controller::GetDefaultFontFamily() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.family : EMPTY_STRING;
+}
+
+void Controller::SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily)
+{
+ PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
+}
+
+const std::string& Controller::GetPlaceholderFontFamily() const
+{
+ return PlaceholderHandler::GetPlaceholderFontFamily(*this);
+}
+
+void Controller::SetDefaultFontWeight(FontWeight weight)
+{
+ EnsureCreated(mImpl->mFontDefaults);
+
+ mImpl->mFontDefaults->mFontDescription.weight = weight;
+ mImpl->mFontDefaults->weightDefined = true;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsDefaultFontWeightDefined() const
+{
+ return mImpl->mFontDefaults && mImpl->mFontDefaults->weightDefined;
+}
+
+FontWeight Controller::GetDefaultFontWeight() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.weight : TextAbstraction::FontWeight::NORMAL;
+}
+
+void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
+{
+ PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
+}
+
+bool Controller::IsPlaceholderTextFontWeightDefined() const
+{
+ return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);
+}
+
+FontWeight Controller::GetPlaceholderTextFontWeight() const
+{
+ return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
+}
+
+void Controller::SetDefaultFontWidth(FontWidth width)
+{
+ EnsureCreated(mImpl->mFontDefaults);
+
+ mImpl->mFontDefaults->mFontDescription.width = width;
+ mImpl->mFontDefaults->widthDefined = true;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsDefaultFontWidthDefined() const
+{
+ return mImpl->mFontDefaults && mImpl->mFontDefaults->widthDefined;
+}
+
+FontWidth Controller::GetDefaultFontWidth() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.width : TextAbstraction::FontWidth::NORMAL;
+}
+
+void Controller::SetPlaceholderTextFontWidth(FontWidth width)
+{
+ PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
+}
+
+bool Controller::IsPlaceholderTextFontWidthDefined() const
+{
+ return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
+}
+
+FontWidth Controller::GetPlaceholderTextFontWidth() const
+{
+ return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
+}
+
+void Controller::SetDefaultFontSlant(FontSlant slant)
+{
+ EnsureCreated(mImpl->mFontDefaults);
+
+ mImpl->mFontDefaults->mFontDescription.slant = slant;
+ mImpl->mFontDefaults->slantDefined = true;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsDefaultFontSlantDefined() const
+{
+ return mImpl->mFontDefaults && mImpl->mFontDefaults->slantDefined;
+}
+
+FontSlant Controller::GetDefaultFontSlant() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.slant : TextAbstraction::FontSlant::NORMAL;
+}
+
+void Controller::SetPlaceholderTextFontSlant(FontSlant slant)
+{
+ PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
+}
+
+bool Controller::IsPlaceholderTextFontSlantDefined() const
+{
+ return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
+}
+
+FontSlant Controller::GetPlaceholderTextFontSlant() const
+{
+ return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
+}
+
+void Controller::SetFontSizeScale(float scale)
+{
+ mImpl->mFontSizeScale = scale;
+
+ // No relayout is required
+ if(!mImpl->mFontSizeScaleEnabled) return;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetFontSizeScale() const
+{
+ return mImpl->mFontDefaults ? mImpl->mFontSizeScale : 1.0f;
+}
+
+void Controller::SetFontSizeScaleEnabled(bool enabled)
+{
+ mImpl->mFontSizeScaleEnabled = enabled;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsFontSizeScaleEnabled() const
+{
+ return mImpl->mFontSizeScaleEnabled;
+}
+
+void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
+{
+ EnsureCreated(mImpl->mFontDefaults);
+
+ mImpl->mFontDefaults->mDefaultPointSize = (type == POINT_SIZE) ? fontSize : ConvertPixelToPoint(fontSize);
+ mImpl->mFontDefaults->sizeDefined = true;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetDefaultFontSize(FontSizeType type) const
+{
+ if(mImpl->mFontDefaults)
+ {
+ return (type == POINT_SIZE) ? mImpl->mFontDefaults->mDefaultPointSize : ConvertPointToPixel(mImpl->mFontDefaults->mDefaultPointSize);
+ }
+ return 0.0f;
+}
+
+void Controller::SetPlaceholderTextFontSize(float fontSize, FontSizeType type)
+{
+ PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
+}
+
+float Controller::GetPlaceholderTextFontSize(FontSizeType type) const
+{
+ return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
+}
+
+void Controller::SetDefaultColor(const Vector4& color)
+{
+ mImpl->SetDefaultColor(color);
+}
+
+const Vector4& Controller::GetDefaultColor() const
+{
+ return mImpl->mTextColor;
+}
+
+void Controller::SetDisabledColorOpacity(float opacity)
+{
+ mImpl->mDisabledColorOpacity = opacity;
+}
+
+float Controller::GetDisabledColorOpacity() const
+{
+ return mImpl->mDisabledColorOpacity;
+}
+
+void Controller::SetUserInteractionEnabled(bool enabled)
+{
+ mImpl->SetUserInteractionEnabled(enabled);
+}
+
+bool Controller::IsUserInteractionEnabled() const
+{
+ return mImpl->mIsUserInteractionEnabled;
+}
+
+void Controller::SetPlaceholderTextColor(const Vector4& textColor)
+{
+ PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
+}
+
+const Vector4& Controller::GetPlaceholderTextColor() const
+{
+ return PlaceholderHandler::GetPlaceholderTextColor(*this);
+}
+
+void Controller::SetShadowOffset(const Vector2& shadowOffset)
+{
+ mImpl->mModel->mVisualModel->SetShadowOffset(shadowOffset);
+ mImpl->RequestRelayout();
+}
+
+const Vector2& Controller::GetShadowOffset() const
+{
+ return mImpl->mModel->mVisualModel->GetShadowOffset();
+}
+
+void Controller::SetShadowColor(const Vector4& shadowColor)
+{
+ mImpl->mModel->mVisualModel->SetShadowColor(shadowColor);
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetShadowColor() const
+{
+ return mImpl->mModel->mVisualModel->GetShadowColor();
+}
+
+void Controller::SetShadowBlurRadius(const float& shadowBlurRadius)
+{
+ if(fabsf(GetShadowBlurRadius() - shadowBlurRadius) > Math::MACHINE_EPSILON_1)
+ {
+ mImpl->mModel->mVisualModel->SetShadowBlurRadius(shadowBlurRadius);
+ mImpl->RequestRelayout();
+ }
+}
+
+const float& Controller::GetShadowBlurRadius() const
+{
+ return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
+}
+
+void Controller::SetUnderlineColor(const Vector4& color)
+{
+ mImpl->mModel->mVisualModel->SetUnderlineColor(color);
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetUnderlineColor() const
+{
+ return mImpl->mModel->mVisualModel->GetUnderlineColor();
+}
+
+void Controller::SetUnderlineEnabled(bool enabled)
+{
+ mImpl->mModel->mVisualModel->SetUnderlineEnabled(enabled);
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsUnderlineEnabled() const
+{
+ return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
+}
+
+void Controller::SetUnderlineHeight(float height)
+{
+ mImpl->mModel->mVisualModel->SetUnderlineHeight(height);
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetUnderlineHeight() const
+{
+ return mImpl->mModel->mVisualModel->GetUnderlineHeight();
+}
+
+void Controller::SetUnderlineType(Text::Underline::Type type)
+{
+ mImpl->mModel->mVisualModel->SetUnderlineType(type);
+
+ mImpl->RequestRelayout();
+}
+
+Text::Underline::Type Controller::GetUnderlineType() const
+{
+ return mImpl->mModel->mVisualModel->GetUnderlineType();
+}
+
+void Controller::SetDashedUnderlineWidth(float width)
+{
+ mImpl->mModel->mVisualModel->SetDashedUnderlineWidth(width);
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetDashedUnderlineWidth() const
+{
+ return mImpl->mModel->mVisualModel->GetDashedUnderlineWidth();
+}
+
+void Controller::SetDashedUnderlineGap(float gap)
+{
+ mImpl->mModel->mVisualModel->SetDashedUnderlineGap(gap);
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetDashedUnderlineGap() const
+{
+ return mImpl->mModel->mVisualModel->GetDashedUnderlineGap();
+}
+
+void Controller::SetOutlineColor(const Vector4& color)
+{
+ mImpl->mModel->mVisualModel->SetOutlineColor(color);
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetOutlineColor() const
+{
+ return mImpl->mModel->mVisualModel->GetOutlineColor();
+}
+
+void Controller::SetOutlineWidth(uint16_t width)
+{
+ mImpl->mModel->mVisualModel->SetOutlineWidth(width);
+ mImpl->RequestRelayout();
+}
+
+uint16_t Controller::GetOutlineWidth() const
+{
+ return mImpl->mModel->mVisualModel->GetOutlineWidth();
+}
+
+void Controller::SetBackgroundColor(const Vector4& color)
+{
+ mImpl->mModel->mVisualModel->SetBackgroundColor(color);
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetBackgroundColor() const
+{
+ return mImpl->mModel->mVisualModel->GetBackgroundColor();
+}
+
+void Controller::SetBackgroundEnabled(bool enabled)
+{
+ mImpl->mModel->mVisualModel->SetBackgroundEnabled(enabled);
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsBackgroundEnabled() const
+{
+ return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
+}
+
+void Controller::SetDefaultEmbossProperties(const std::string& embossProperties)
+{
+ EnsureCreated(mImpl->mEmbossDefaults);
+ mImpl->mEmbossDefaults->properties = embossProperties;
+}
+
+const std::string& Controller::GetDefaultEmbossProperties() const
+{
+ return mImpl->mEmbossDefaults ? mImpl->mEmbossDefaults->properties : EMPTY_STRING;
+}
+
+void Controller::SetDefaultOutlineProperties(const std::string& outlineProperties)
+{
+ EnsureCreated(mImpl->mOutlineDefaults);
+ mImpl->mOutlineDefaults->properties = outlineProperties;
+}
+
+const std::string& Controller::GetDefaultOutlineProperties() const
+{
+ return mImpl->mOutlineDefaults ? mImpl->mOutlineDefaults->properties : EMPTY_STRING;
+}
+
+bool Controller::SetDefaultLineSpacing(float lineSpacing)
+{
+ return mImpl->SetDefaultLineSpacing(lineSpacing);
+}
+
+float Controller::GetDefaultLineSpacing() const
+{
+ return mImpl->mLayoutEngine.GetDefaultLineSpacing();
+}
+
+bool Controller::SetDefaultLineSize(float lineSize)
+{
+ return mImpl->SetDefaultLineSize(lineSize);
+}
+
+float Controller::GetDefaultLineSize() const
+{
+ return mImpl->mLayoutEngine.GetDefaultLineSize();
+}
+
+bool Controller::SetRelativeLineSize(float relativeLineSize)
+{
+ return mImpl->SetRelativeLineSize(relativeLineSize);
+}
+
+float Controller::GetRelativeLineSize() const
+{
+ return mImpl->GetRelativeLineSize();
+}
+
+void Controller::SetInputColor(const Vector4& color)
+{
+ InputProperties::SetInputColor(*this, color);
+}
+
+const Vector4& Controller::GetInputColor() const
+{
+ return InputProperties::GetInputColor(*this);
+}
+
+void Controller::SetInputFontFamily(const std::string& fontFamily)
+{
+ InputFontHandler::SetInputFontFamily(*this, fontFamily);
+}
+
+const std::string& Controller::GetInputFontFamily() const
+{
+ return InputFontHandler::GetInputFontFamily(*this);
+}
+
+void Controller::SetInputFontWeight(FontWeight weight)
+{
+ InputFontHandler::SetInputFontWeight(*this, weight);
+}
+
+bool Controller::IsInputFontWeightDefined() const
+{
+ return InputFontHandler::IsInputFontWeightDefined(*this);
+}
+
+FontWeight Controller::GetInputFontWeight() const
+{
+ return InputFontHandler::GetInputFontWeight(*this);
+}
+
+void Controller::SetInputFontWidth(FontWidth width)
+{
+ InputFontHandler::SetInputFontWidth(*this, width);
+}
+
+bool Controller::IsInputFontWidthDefined() const
+{
+ return InputFontHandler::IsInputFontWidthDefined(*this);
+}
+
+FontWidth Controller::GetInputFontWidth() const
+{
+ return InputFontHandler::GetInputFontWidth(*this);
+}
+
+void Controller::SetInputFontSlant(FontSlant slant)
+{
+ InputFontHandler::SetInputFontSlant(*this, slant);
+}
+
+bool Controller::IsInputFontSlantDefined() const
+{
+ return InputFontHandler::IsInputFontSlantDefined(*this);
+}
+
+FontSlant Controller::GetInputFontSlant() const
+{
+ return InputFontHandler::GetInputFontSlant(*this);
+}
+
+void Controller::SetInputFontPointSize(float size)
+{
+ InputFontHandler::SetInputFontPointSize(*this, size);
+}
+
+float Controller::GetInputFontPointSize() const
+{
+ return InputFontHandler::GetInputFontPointSize(*this);
+}
+
+void Controller::SetInputLineSpacing(float lineSpacing)
+{
+ InputProperties::SetInputLineSpacing(*this, lineSpacing);
+}
+
+float Controller::GetInputLineSpacing() const
+{
+ return InputProperties::GetInputLineSpacing(*this);
+}
+
+void Controller::SetInputShadowProperties(const std::string& shadowProperties)
+{
+ InputProperties::SetInputShadowProperties(*this, shadowProperties);
+}
+
+const std::string& Controller::GetInputShadowProperties() const
+{
+ return InputProperties::GetInputShadowProperties(*this);
+}
+
+void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
+{
+ InputProperties::SetInputUnderlineProperties(*this, underlineProperties);
+}
+
+const std::string& Controller::GetInputUnderlineProperties() const
+{
+ return InputProperties::GetInputUnderlineProperties(*this);
+}
+
+void Controller::SetInputEmbossProperties(const std::string& embossProperties)
+{
+ InputProperties::SetInputEmbossProperties(*this, embossProperties);
+}
+
+const std::string& Controller::GetInputEmbossProperties() const
+{
+ return InputProperties::GetInputEmbossProperties(*this);
+}
+
+void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
+{
+ InputProperties::SetInputOutlineProperties(*this, outlineProperties);
+}
+
+const std::string& Controller::GetInputOutlineProperties() const
+{
+ return InputProperties::GetInputOutlineProperties(*this);
+}
+
+void Controller::SetInputModePassword(bool passwordInput)
+{
+ InputProperties::SetInputModePassword(*this, passwordInput);
+}
+
+bool Controller::IsInputModePassword()
+{
+ return InputProperties::IsInputModePassword(*this);
+}
+
+void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
+{
+ if(mImpl->mEventData)
+ {
+ mImpl->mEventData->mDoubleTapAction = action;
+ }
+}
+
+Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
+{
+ return mImpl->mEventData ? mImpl->mEventData->mDoubleTapAction : NoTextTap::NO_ACTION;
+}
+
+void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
+{
+ if(mImpl->mEventData)
+ {
+ mImpl->mEventData->mLongPressAction = action;
+ }
+}
+
+Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
+{
+ return mImpl->mEventData ? mImpl->mEventData->mLongPressAction : NoTextTap::NO_ACTION;
+}
+
+bool Controller::IsUnderlineSetByString()
+{
+ return mImpl->mUnderlineSetByString;
+}
+
+void Controller::UnderlineSetByString(bool setByString)
+{
+ mImpl->mUnderlineSetByString = setByString;
+}
+
+bool Controller::IsShadowSetByString()
+{
+ return mImpl->mShadowSetByString;
+}
+
+void Controller::ShadowSetByString(bool setByString)
+{
+ mImpl->mShadowSetByString = setByString;
+}
+
+bool Controller::IsOutlineSetByString()
+{
+ return mImpl->mOutlineSetByString;
+}
+
+void Controller::OutlineSetByString(bool setByString)
+{
+ mImpl->mOutlineSetByString = setByString;
+}
+
+bool Controller::IsFontStyleSetByString()
+{
+ return mImpl->mFontStyleSetByString;
+}
+
+void Controller::FontStyleSetByString(bool setByString)
+{
+ mImpl->mFontStyleSetByString = setByString;
+}
+
+void Controller::SetStrikethroughHeight(float height)
+{
+ mImpl->mModel->mVisualModel->SetStrikethroughHeight(height);
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetStrikethroughHeight() const
+{
+ return mImpl->mModel->mVisualModel->GetStrikethroughHeight();
+}
+
+void Controller::SetStrikethroughColor(const Vector4& color)
+{
+ mImpl->mModel->mVisualModel->SetStrikethroughColor(color);
+
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetStrikethroughColor() const
+{
+ return mImpl->mModel->mVisualModel->GetStrikethroughColor();
+}
+
+void Controller::SetStrikethroughEnabled(bool enabled)
+{
+ mImpl->mModel->mVisualModel->SetStrikethroughEnabled(enabled);
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsStrikethroughEnabled() const
+{
+ return mImpl->mModel->mVisualModel->IsStrikethroughEnabled();
+}
+
+void Controller::SetInputStrikethroughProperties(const std::string& strikethroughProperties)
+{
+ if(NULL != mImpl->mEventData)
+ {
+ mImpl->mEventData->mInputStyle.strikethroughProperties = strikethroughProperties;
+ }
+}
+
+const std::string& Controller::GetInputStrikethroughProperties() const
+{
+ return (NULL != mImpl->mEventData) ? mImpl->mEventData->mInputStyle.strikethroughProperties : EMPTY_STRING;
+}
+
+bool Controller::IsStrikethroughSetByString()
+{
+ return mImpl->mStrikethroughSetByString;
+}
+
+void Controller::StrikethroughSetByString(bool setByString)
+{
+ mImpl->mStrikethroughSetByString = setByString;
+}
+
+Layout::Engine& Controller::GetLayoutEngine()
+{
+ return mImpl->mLayoutEngine;
+}
+
+View& Controller::GetView()
+{
+ return mImpl->mView;
+}
+
+Vector3 Controller::GetNaturalSize()
+{
+ return Relayouter::GetNaturalSize(*this);
+}
+
+bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
+{
+ return Relayouter::CheckForTextFit(*this, pointSize, layoutSize);
+}
+
+void Controller::FitPointSizeforLayout(Size layoutSize)
+{
+ Relayouter::FitPointSizeforLayout(*this, layoutSize);
+}
+
+float Controller::GetHeightForWidth(float width)
+{
+ return Relayouter::GetHeightForWidth(*this, width);
+}
+
+int Controller::GetLineCount(float width)
+{
+ GetHeightForWidth(width);
+ return mImpl->mModel->GetNumberOfLines();
+}
+
+const ModelInterface* const Controller::GetTextModel() const
+{
+ return mImpl->mModel.Get();
+}
+
+float Controller::GetScrollAmountByUserInput()
+{
+ float scrollAmount = 0.0f;
+
+ if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
+ {
+ scrollAmount = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
+ mImpl->mEventData->mCheckScrollAmount = false;
+ }
+ return scrollAmount;
+}
+
+bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
+{
+ const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
+ bool isScrolled;
+
+ controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
+ layoutHeight = layout.height;
+ scrollPosition = mImpl->mModel->mScrollPosition.y;
+ isScrolled = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
+ return isScrolled;
+}
+
+void Controller::SetHiddenInputOption(const Property::Map& options)
+{
+ EnsureCreated<HiddenText, Controller*>(mImpl->mHiddenInput, this);
+ mImpl->mHiddenInput->SetProperties(options);
+}
+
+void Controller::GetHiddenInputOption(Property::Map& options)
+{
+ if(mImpl->mHiddenInput)
+ {
+ mImpl->mHiddenInput->GetProperties(options);
+ }
+}
+
+void Controller::SetInputFilterOption(const Property::Map& options)
+{
+ EnsureCreated(mImpl->mInputFilter);
+ mImpl->mInputFilter->SetProperties(options);
+}
+
+void Controller::GetInputFilterOption(Property::Map& options)
+{
+ if(mImpl->mInputFilter)
+ {
+ mImpl->mInputFilter->GetProperties(options);
+ }
+}
+
+void Controller::SetPlaceholderProperty(const Property::Map& map)
+{
+ PlaceholderHandler::SetPlaceholderProperty(*this, map);
+}
+
+void Controller::GetPlaceholderProperty(Property::Map& map)
+{
+ PlaceholderHandler::GetPlaceholderProperty(*this, map);
+}
+
+Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
+{
+ // Make sure the model is up-to-date before layouting
+ EventHandler::ProcessModifyEvents(*this);
+
+ return mImpl->GetTextDirection();
+}
+
+Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
+{
+ return mImpl->mModel->GetVerticalLineAlignment();
+}
+
+void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
+{
+ mImpl->mModel->mVerticalLineAlignment = alignment;
+}
+
+Toolkit::DevelText::EllipsisPosition::Type Controller::GetEllipsisPosition() const
+{
+ return mImpl->mModel->GetEllipsisPosition();
+}
+
+void Controller::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
+{
+ mImpl->mModel->mEllipsisPosition = ellipsisPosition;
+ mImpl->mModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
+}
+
+void Controller::SetCharacterSpacing(float characterSpacing)
+{
+ mImpl->mModel->mVisualModel->SetCharacterSpacing(characterSpacing);
+
+ mImpl->RelayoutAllCharacters();
+ mImpl->RequestRelayout();
+}
+
+const float Controller::GetCharacterSpacing() const
+{
+ return mImpl->mModel->mVisualModel->GetCharacterSpacing();
+}
+
+Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
+{
+ return Relayouter::Relayout(*this, size, layoutDirection);
+}
+
+void Controller::RequestRelayout()
+{
+ mImpl->RequestRelayout();
+}
+
+Vector<Vector2> Controller::GetTextSize(CharacterIndex startIndex, CharacterIndex endIndex)
+{
+ Vector<Vector2> sizesList;
+ Vector<Vector2> positionsList;
+
+ GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizesList, positionsList);
+ return sizesList;
+}
+
+Vector<Vector2> Controller::GetTextPosition(CharacterIndex startIndex, CharacterIndex endIndex)
+{
+ Vector<Vector2> sizesList;
+ Vector<Vector2> positionsList;
+
+ GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizesList, positionsList);
+ return positionsList;
+}
+
+Rect<> Controller::GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex)
+{
+ Vector<Vector2> sizeList;
+ Vector<Vector2> positionList;
+
+ GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizeList, positionList);
+
+ if(sizeList.Empty() || sizeList.Size() != positionList.Size())
+ {
+ return {0, 0, 0, 0};
+ }
+
+ auto minX = positionList[0].x;
+ auto minY = positionList[0].y;
+ auto maxRight = positionList[0].x + sizeList[0].x;
+ auto maxBottom = positionList[0].y + sizeList[0].y;
+
+ for(unsigned int i = 1; i < sizeList.Size(); i++)
+ {
+ minX = std::min(minX, positionList[i].x);
+ minY = std::min(minY, positionList[i].y);
+ maxRight = std::max(maxRight, positionList[i].x + sizeList[i].x);
+ maxBottom = std::max(maxBottom, positionList[i].y + sizeList[i].y);
+ }
+
+ return {minX, minY, maxRight - minX, maxBottom - minY};
+}
+
+bool Controller::IsInputStyleChangedSignalsQueueEmpty()
+{
+ return mImpl->IsInputStyleChangedSignalsQueueEmpty();
+}
+
+void Controller::ProcessInputStyleChangedSignals()
+{
+ mImpl->ProcessInputStyleChangedSignals();
+}
+
+void Controller::KeyboardFocusGainEvent()
+{
+ EventHandler::KeyboardFocusGainEvent(*this);
+}
+
+void Controller::KeyboardFocusLostEvent()
+{
+ EventHandler::KeyboardFocusLostEvent(*this);
+}
+
+bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
+{
+ return EventHandler::KeyEvent(*this, keyEvent);
+}
+
+void Controller::AnchorEvent(float x, float y)
+{
+ EventHandler::AnchorEvent(*this, x, y);
+}
+
+void Controller::TapEvent(unsigned int tapCount, float x, float y)
+{
+ EventHandler::TapEvent(*this, tapCount, x, y);
+}
+
+void Controller::PanEvent(GestureState state, const Vector2& displacement)
+{
+ EventHandler::PanEvent(*this, state, displacement);
+}
+
+void Controller::LongPressEvent(GestureState state, float x, float y)
+{
+ EventHandler::LongPressEvent(*this, state, x, y);
+}
+
+void Controller::SelectEvent(float x, float y, SelectionType selectType)
+{
+ EventHandler::SelectEvent(*this, x, y, selectType);
+}
+
+void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
+{
+ if(mImpl->mEventData)
+ {
+ mImpl->mEventData->mCheckScrollAmount = true;
+ mImpl->mEventData->mIsLeftHandleSelected = true;
+ mImpl->mEventData->mIsRightHandleSelected = true;
+ mImpl->SetTextSelectionRange(start, end);
+ mImpl->RequestRelayout();
+ EventHandler::KeyboardFocusGainEvent(*this);
+ }
+}
+
+Uint32Pair Controller::GetTextSelectionRange() const
+{
+ return mImpl->GetTextSelectionRange();
+}
+
+CharacterIndex Controller::GetPrimaryCursorPosition() const
+{
+ return mImpl->GetPrimaryCursorPosition();
+}
+
+bool Controller::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
+{
+ if(mImpl->mEventData)
+ {
+ mImpl->mEventData->mCheckScrollAmount = true;
+ mImpl->mEventData->mIsLeftHandleSelected = true;
+ mImpl->mEventData->mIsRightHandleSelected = true;
+ mImpl->mEventData->mCheckScrollAmount = true;
+ if(mImpl->SetPrimaryCursorPosition(index, focused) && focused)
+ {
+ EventHandler::KeyboardFocusGainEvent(*this);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Controller::SelectWholeText()
+{
+ EventHandler::SelectEvent(*this, 0.f, 0.f, SelectionType::ALL);
+}
+
+void Controller::SelectNone()
+{
+ EventHandler::SelectEvent(*this, 0.f, 0.f, SelectionType::NONE);
+}
+
+void Controller::SelectText(const uint32_t start, const uint32_t end)
+{
+ EventHandler::SelectEvent(*this, start, end, SelectionType::RANGE);
+}
+
+string Controller::GetSelectedText() const
+{
+ return mImpl->GetSelectedText();
+}
+
+string Controller::CopyText()
+{
+ return mImpl->CopyText();
+}
+
+string Controller::CutText()
+{
+ return mImpl->CutText();
+}
+
+void Controller::PasteText()
+{
+ mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
+}
+
+InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
+{
+ return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
+}
+
+void Controller::PasteClipboardItemEvent()
+{
+ EventHandler::PasteClipboardItemEvent(*this);
+}
+
+void Controller::GetTargetSize(Vector2& targetSize)
+{
+ targetSize = mImpl->mModel->mVisualModel->mControlSize;
+}
+
+void Controller::AddDecoration(Actor& actor, DecorationType type, bool needsClipping)
+{
+ if(mImpl->mEditableControlInterface)
+ {
+ mImpl->mEditableControlInterface->AddDecoration(actor, type, needsClipping);
+ }
+}
+
+bool Controller::IsEditable() const
+{
+ return mImpl->IsEditable();
+}
+
+void Controller::SetEditable(bool editable)
+{
+ mImpl->SetEditable(editable);
+}
+
+void Controller::ScrollBy(Vector2 scroll)
+{
+ mImpl->ScrollBy(scroll);
+}
+
+bool Controller::IsScrollable(const Vector2& displacement)
+{
+ return mImpl->IsScrollable(displacement);
+}
+
+float Controller::GetHorizontalScrollPosition()
+{
+ return mImpl->GetHorizontalScrollPosition();
+}
+
+float Controller::GetVerticalScrollPosition()
+{
+ return mImpl->GetVerticalScrollPosition();
+}
+
+void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
+{
+ EventHandler::DecorationEvent(*this, handleType, state, x, y);
+}
+
+void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
+{
+ EventHandler::TextPopupButtonTouched(*this, button);
+}
+
+void Controller::DisplayTimeExpired()
+{
+ mImpl->mEventData->mUpdateCursorPosition = true;
+ // Apply modifications to the model
+ mImpl->mOperationsPending = ALL_OPERATIONS;
+
+ mImpl->RequestRelayout();
+}
+
+void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
+{
+ // Reset the cursor position
+ if(NULL != mImpl->mEventData)
+ {
+ mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
+
+ // Update the cursor if it's in editing mode.
+ if(EventData::IsEditingState(mImpl->mEventData->mState))
+ {
+ mImpl->mEventData->mUpdateCursorPosition = true;
+ }
+ }
+}
+
+CharacterIndex Controller::GetCursorPosition()
+{
+ return mImpl->mEventData ? mImpl->mEventData->mPrimaryCursorPosition : 0;
+}
+
+void Controller::SetControlInterface(ControlInterface* controlInterface)
+{
+ mImpl->mControlInterface = controlInterface;
+}
+
+void Controller::SetAnchorControlInterface(AnchorControlInterface* anchorControlInterface)
+{
+ mImpl->mAnchorControlInterface = anchorControlInterface;
+}
+
+bool Controller::ShouldClearFocusOnEscape() const
+{
+ return mImpl->mShouldClearFocusOnEscape;
+}
+
+Actor Controller::CreateBackgroundActor()
+{
+ return CreateControllerBackgroundActor(mImpl->mView, mImpl->mModel->mVisualModel, mImpl->mModel->mLogicalModel, mImpl->mShaderBackground);
+}
+
+void Controller::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
+{
+ mImpl->GetAnchorActors(anchorActors);
+}
+
+int Controller::GetAnchorIndex(size_t characterOffset)
+{
+ return mImpl->GetAnchorIndex(characterOffset);
+}
+
+Controller::Controller(ControlInterface* controlInterface,
+ EditableControlInterface* editableControlInterface,
+ SelectableControlInterface* selectableControlInterface,
+ AnchorControlInterface* anchorControlInterface)
+: mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface, anchorControlInterface))
+{
+}
+
+Controller::~Controller()
+{
+ delete mImpl;
+}
+
+} // namespace Dali::Toolkit::Text
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/public-api/events/gesture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/hidden-text.h>
+#include <dali-toolkit/internal/text/input-filter.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
+#include <dali-toolkit/internal/text/text-model-interface.h>
+#include <dali-toolkit/internal/text/text-selectable-control-interface.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+
+namespace Dali::Toolkit::Text
+{
+class Controller;
+class ControlInterface;
+class EditableControlInterface;
+class View;
+class RenderingController;
+
+/**
+ * @brief Text selection operations .
+ */
+enum SelectionType
+{
+ INTERACTIVE = 0x0000, ///< Select the word where the cursor is located.
+ ALL = 0x0001, ///< Select the whole text.
+ NONE = 0x0002, ///< Unselect the whole text.
+ RANGE = 0x0003 ///< Select the range text.
+};
+
+typedef IntrusivePtr<Controller> ControllerPtr;
+
+/**
+ * @brief A Text Controller is used by UI Controls which display text.
+ *
+ * It manipulates the Logical & Visual text models on behalf of the UI Controls.
+ * It provides a view of the text that can be used by rendering back-ends.
+ *
+ * For selectable/editable UI controls, the controller handles input events from the UI control
+ * and decorations (grab handles etc) via the Decorator::ControllerInterface interface.
+ *
+ * The text selection popup button callbacks are as well handled via the TextSelectionPopupCallbackInterface interface.
+ */
+class Controller : public RefObject, public Decorator::ControllerInterface, public TextSelectionPopupCallbackInterface, public HiddenText::Observer
+{
+public: // Enumerated types.
+ /**
+ * @brief Text related operations to be done in the relayout process.
+ */
+ enum OperationsMask
+ {
+ NO_OPERATION = 0x0000,
+ CONVERT_TO_UTF32 = 0x0001,
+ GET_SCRIPTS = 0x0002,
+ VALIDATE_FONTS = 0x0004,
+ GET_LINE_BREAKS = 0x0008,
+ BIDI_INFO = 0x0010,
+ SHAPE_TEXT = 0x0020,
+ GET_GLYPH_METRICS = 0x0040,
+ LAYOUT = 0x0080,
+ UPDATE_LAYOUT_SIZE = 0x0100,
+ REORDER = 0x0200,
+ ALIGN = 0x0400,
+ COLOR = 0x0800,
+ UPDATE_DIRECTION = 0x1000,
+ ALL_OPERATIONS = 0xFFFF
+ };
+
+ /**
+ * @brief Used to distinguish between regular key events and InputMethodContext events
+ */
+ enum InsertType
+ {
+ COMMIT,
+ PRE_EDIT
+ };
+
+ /**
+ * @brief Used to specify whether to update the input style.
+ */
+ enum UpdateInputStyleType
+ {
+ UPDATE_INPUT_STYLE,
+ DONT_UPDATE_INPUT_STYLE
+ };
+
+ /**
+ * @brief Used to specify what has been updated after the Relayout() method has been called.
+ */
+ enum UpdateTextType
+ {
+ NONE_UPDATED = 0x0, ///< Nothing has been updated.
+ MODEL_UPDATED = 0x1, ///< The text's model has been updated.
+ DECORATOR_UPDATED = 0x2 ///< The decoration has been updated.
+ };
+
+ /**
+ * @brief Different placeholder-text can be shown when the control is active/inactive.
+ */
+ enum PlaceholderType
+ {
+ PLACEHOLDER_TYPE_ACTIVE,
+ PLACEHOLDER_TYPE_INACTIVE,
+ };
+
+ /**
+ * @brief Enumeration for Font Size Type.
+ */
+ enum FontSizeType
+ {
+ POINT_SIZE, // The size of font in points.
+ PIXEL_SIZE // The size of font in pixels.
+ };
+
+ struct NoTextTap
+ {
+ enum Action
+ {
+ NO_ACTION, ///< Does no action if there is a tap on top of an area with no text.
+ HIGHLIGHT, ///< Highlights the nearest text (at the beginning or end of the text) and shows the text's selection popup.
+ SHOW_SELECTION_POPUP ///< Shows the text's selection popup.
+ };
+ };
+
+ struct TextFitInfo
+ {
+ enum Property
+ {
+ TEXT_FIT_ENABLE,
+ TEXT_FIT_MIN_SIZE,
+ TEXT_FIT_MAX_SIZE,
+ TEXT_FIT_STEP_SIZE,
+ TEXT_FIT_FONT_SIZE_TYPE
+ };
+ };
+
+public: // Constructor.
+ /**
+ * @brief Create a new instance of a Controller.
+ *
+ * @return A pointer to a new Controller.
+ */
+ static ControllerPtr New()
+ {
+ return ControllerPtr(new Controller());
+ }
+
+ /**
+ * @brief Create a new instance of a Controller.
+ *
+ * @param[in] controlInterface The control's interface.
+ *
+ * @return A pointer to a new Controller.
+ */
+ static ControllerPtr New(ControlInterface* controlInterface)
+ {
+ return ControllerPtr(new Controller(controlInterface));
+ }
+
+ /**
+ * @brief Create a new instance of a Controller.
+ *
+ * @param[in] controlInterface The control's interface.
+ * @param[in] editableControlInterface The editable control's interface.
+ * @param[in] selectableControlInterface The selectable control's interface.
+ * @param[in] anchorControlInterface The anchor control's interface.
+ *
+ * @return A pointer to a new Controller.
+ */
+ static ControllerPtr New(ControlInterface* controlInterface,
+ EditableControlInterface* editableControlInterface,
+ SelectableControlInterface* selectableControlInterface,
+ AnchorControlInterface* anchorControlInterface)
+ {
+ return ControllerPtr(new Controller(controlInterface,
+ editableControlInterface,
+ selectableControlInterface,
+ anchorControlInterface));
+ }
+
+public: // Configure the text controller.
+ /**
+ * @brief Called to enable text input.
+ *
+ * @note Selectable or editable controls should call this once after Controller::New().
+ * @param[in] decorator Used to create cursor, selection handle decorations etc.
+ * @param[in] inputMethodContext Used to manager ime.
+ */
+ void EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext);
+
+ /**
+ * @brief Used to switch between bitmap & vector based glyphs
+ *
+ * @param[in] glyphType The type of glyph; note that metrics for bitmap & vector based glyphs are different.
+ */
+ void SetGlyphType(TextAbstraction::GlyphType glyphType);
+
+ /**
+ * @brief Enables/disables the mark-up processor.
+ *
+ * By default is disabled.
+ *
+ * @param[in] enable Whether to enable the mark-up processor.
+ */
+ void SetMarkupProcessorEnabled(bool enable);
+
+ /**
+ * @brief Retrieves whether the mark-up processor is enabled.
+ *
+ * By default is disabled.
+ *
+ * @return @e true if the mark-up processor is enabled, otherwise returns @e false.
+ */
+ bool IsMarkupProcessorEnabled() const;
+
+ /**
+ * @brief Retrieves whether the current text contains anchors.
+ *
+ * @return @e true if the current text contains anchors. @e false.
+ */
+ bool HasAnchors() const;
+
+ /**
+ * @brief Enables/disables the auto text scrolling
+ *
+ * By default is disabled.
+ *
+ * @param[in] enable Whether to enable the auto scrolling
+ */
+ void SetAutoScrollEnabled(bool enable);
+
+ /**
+ * @brief Whether the auto scrolling texture exceed max texture.
+ *
+ * By default is false.
+ *
+ * @param[in] exceed Whether the auto scrolling texture exceed max texture.
+ */
+ void SetAutoScrollMaxTextureExceeded(bool exceed);
+
+ /**
+ * @brief Retrieves whether auto text scrolling is enabled.
+ *
+ * By default is disabled.
+ *
+ * @return @e true if auto scrolling is enabled, otherwise returns @e false.
+ */
+ bool IsAutoScrollEnabled() const;
+
+ /**
+ * @brief Get direction of the text from the first line of text,
+ * @return bool rtl (right to left) is true
+ */
+ CharacterDirection GetAutoScrollDirection() const;
+
+ /**
+ * @brief Get the alignment offset of the first line of text.
+ *
+ * @return The alignment offset.
+ */
+ float GetAutoScrollLineAlignment() const;
+
+ /**
+ * @brief Enables the horizontal scrolling.
+ *
+ * @param[in] enable Whether to enable the horizontal scrolling.
+ */
+ void SetHorizontalScrollEnabled(bool enable);
+
+ /**
+ * @brief Retrieves whether the horizontal scrolling is enabled.
+ *
+ * @return @e true if the horizontal scrolling is enabled, otherwise it returns @e false.
+ */
+ bool IsHorizontalScrollEnabled() const;
+
+ /**
+ * @brief Enables the vertical scrolling.
+ *
+ * @param[in] enable Whether to enable the vertical scrolling.
+ */
+ void SetVerticalScrollEnabled(bool enable);
+
+ /**
+ * @brief Retrieves whether the verticall scrolling is enabled.
+ *
+ * @return @e true if the vertical scrolling is enabled, otherwise it returns @e false.
+ */
+ bool IsVerticalScrollEnabled() const;
+
+ /**
+ * @brief Enables the smooth handle panning.
+ *
+ * @param[in] enable Whether to enable the smooth handle panning.
+ */
+ void SetSmoothHandlePanEnabled(bool enable);
+
+ /**
+ * @brief Retrieves whether the smooth handle panning is enabled.
+ *
+ * @return @e true if the smooth handle panning is enabled.
+ */
+ bool IsSmoothHandlePanEnabled() const;
+
+ /**
+ * @brief Sets the maximum number of characters that can be inserted into the TextModel
+ *
+ * @param[in] maxCharacters maximum number of characters to be accepted
+ */
+ void SetMaximumNumberOfCharacters(Length maxCharacters);
+
+ /**
+ * @brief Sets the maximum number of characters that can be inserted into the TextModel
+ *
+ * @param[in] maxCharacters maximum number of characters to be accepted
+ */
+ int GetMaximumNumberOfCharacters();
+
+ /**
+ * @brief Called to enable/disable cursor blink.
+ *
+ * @note Only editable controls should calls this.
+ * @param[in] enabled Whether the cursor should blink or not.
+ */
+ void SetEnableCursorBlink(bool enable);
+
+ /**
+ * @brief Query whether cursor blink is enabled.
+ *
+ * @return Whether the cursor should blink or not.
+ */
+ bool GetEnableCursorBlink() const;
+
+ /**
+ * @brief Whether to enable the multi-line layout.
+ *
+ * @param[in] enable \e true enables the multi-line (by default)
+ */
+ void SetMultiLineEnabled(bool enable);
+
+ /**
+ * @return Whether the multi-line layout is enabled.
+ */
+ bool IsMultiLineEnabled() const;
+
+ /**
+ * @brief Sets the text's horizontal alignment.
+ *
+ * @param[in] alignment The horizontal alignment.
+ */
+ void SetHorizontalAlignment(HorizontalAlignment::Type alignment);
+
+ /**
+ * @copydoc ModelInterface::GetHorizontalAlignment()
+ */
+ HorizontalAlignment::Type GetHorizontalAlignment() const;
+
+ /**
+ * @brief Sets the text's vertical alignment.
+ *
+ * @param[in] alignment The vertical alignment.
+ */
+ void SetVerticalAlignment(VerticalAlignment::Type alignment);
+
+ /**
+ * @copydoc ModelInterface::GetVerticalAlignment()
+ */
+ VerticalAlignment::Type GetVerticalAlignment() const;
+
+ /**
+ * @brief Sets the text's wrap mode
+ * @param[in] text wrap mode The unit of wrapping
+ */
+ void SetLineWrapMode(Text::LineWrap::Mode textWarpMode);
+
+ /**
+ * @brief Retrieve text wrap mode previously set.
+ * @return text wrap mode
+ */
+ Text::LineWrap::Mode GetLineWrapMode() const;
+
+ /**
+ * @brief Enable or disable the text elide.
+ *
+ * @param[in] enabled Whether to enable the text elide.
+ */
+ void SetTextElideEnabled(bool enabled);
+
+ /**
+ * @copydoc ModelInterface::IsTextElideEnabled()
+ */
+ bool IsTextElideEnabled() const;
+
+ /**
+ * @brief Enable or disable the text fit.
+ *
+ * @param[in] enabled Whether to enable the text fit.
+ */
+ void SetTextFitEnabled(bool enabled);
+
+ /**
+ * @brief Whether the text fit is enabled or not.
+ *
+ * @return True if the text fit is enabled
+ */
+ bool IsTextFitEnabled() const;
+
+ /**
+ * @brief Sets minimum size valid for text fit.
+ *
+ * @param[in] minimum size value.
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetTextFitMinSize(float pointSize, FontSizeType type);
+
+ /**
+ * @brief Retrieves the minimum point size valid for text fit.
+ *
+ * @return The minimum point size valid for text fit
+ */
+ float GetTextFitMinSize() const;
+
+ /**
+ * @brief Sets maximum size valid for text fit.
+ *
+ * @param[in] maximum size value.
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetTextFitMaxSize(float pointSize, FontSizeType type);
+
+ /**
+ * @brief Retrieves the maximum point size valid for text fit.
+ *
+ * @return The maximum point size valid for text fit
+ */
+ float GetTextFitMaxSize() const;
+
+ /**
+ * @brief Sets step size for font increase valid for text fit.
+ *
+ * @param[in] step size value.
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetTextFitStepSize(float step, FontSizeType type);
+
+ /**
+ * @brief Retrieves the step point size valid for text fit.
+ *
+ * @return The step point size valid for text fit
+ */
+ float GetTextFitStepSize() const;
+
+ /**
+ * @brief Sets content size valid for text fit.
+ *
+ * @param[in] Content size value.
+ */
+ void SetTextFitContentSize(Vector2 size);
+
+ /**
+ * @brief Retrieves the content size valid for text fit.
+ *
+ * @return The content size valid for text fit
+ */
+ Vector2 GetTextFitContentSize() const;
+
+ /**
+ * @brief Retrieve the fited point size.
+ *
+ * @return The fited point size.
+ */
+ float GetTextFitPointSize() const;
+
+ /**
+ * @brief Sets whether the text fit properties have changed.
+ *
+ * @param[in] changed Whether to changed the text fit.
+ */
+ void SetTextFitChanged(bool changed);
+
+ /**
+ * @brief Whether the text fit properties are changed or not.
+ *
+ * @return True if the text fit properties are changed
+ */
+ bool IsTextFitChanged() const;
+
+ /**
+ * @brief Sets disabled color opacity.
+ *
+ * @param[in] opacity The color opacity value in disabled state.
+ */
+ void SetDisabledColorOpacity(float opacity);
+
+ /**
+ * @brief Retrieves the disabled color opacity.
+ *
+ * @return The disabled color opacity value for disabled state.
+ */
+ float GetDisabledColorOpacity() const;
+
+ /**
+ * @brief Enable or disable the placeholder text elide.
+ * @param enabled Whether to enable the placeholder text elide.
+ */
+ void SetPlaceholderTextElideEnabled(bool enabled);
+
+ /**
+ * @brief Whether the placeholder text elide property is enabled.
+ * @return True if the placeholder text elide property is enabled, false otherwise.
+ */
+ bool IsPlaceholderTextElideEnabled() const;
+
+ /**
+ * @brief Enable or disable the text selection.
+ * @param[in] enabled Whether to enable the text selection.
+ */
+ void SetSelectionEnabled(bool enabled);
+
+ /**
+ * @brief Whether the text selection is enabled or not.
+ * @return True if the text selection is enabled
+ */
+ bool IsSelectionEnabled() const;
+
+ /**
+ * @brief Enable or disable the text selection using Shift key.
+ * @param enabled Whether to enable the text selection using Shift key
+ */
+ void SetShiftSelectionEnabled(bool enabled);
+
+ /**
+ * @brief Whether the text selection using Shift key is enabled or not.
+ * @return True if the text selection using Shift key is enabled
+ */
+ bool IsShiftSelectionEnabled() const;
+
+ /**
+ * @brief Enable or disable the grab handles for text selection.
+ *
+ * @param[in] enabled Whether to enable the grab handles
+ */
+ void SetGrabHandleEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether the grab handles are enabled.
+ *
+ * @return True if the grab handles are enabled
+ */
+ bool IsGrabHandleEnabled() const;
+
+ /**
+ * @brief Enable or disable the grab handles for text selection.
+ *
+ * @param[in] enabled Whether to enable the grab handles
+ */
+ void SetGrabHandlePopupEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether the grab handles are enabled.
+ *
+ * @return True if the grab handles are enabled
+ */
+ bool IsGrabHandlePopupEnabled() const;
+
+ /**
+ * @brief Sets input type to password
+ *
+ * @note The string is displayed hidden character
+ *
+ * @param[in] passwordInput True if password input is enabled.
+ */
+ void SetInputModePassword(bool passwordInput);
+
+ /**
+ * @brief Returns whether the input mode type is set as password.
+ *
+ * @return True if input mode type is password
+ */
+ bool IsInputModePassword();
+
+ /**
+ * @brief Sets the action when there is a double tap event on top of a text area with no text.
+ *
+ * @param[in] action The action to do.
+ */
+ void SetNoTextDoubleTapAction(NoTextTap::Action action);
+
+ /**
+ * @brief Retrieves the action when there is a double tap event on top of a text area with no text.
+ *
+ * @return The action to do.
+ */
+ NoTextTap::Action GetNoTextDoubleTapAction() const;
+
+ /**
+ * @briefSets the action when there is a long press event on top of a text area with no text.
+ *
+ * @param[in] action The action to do.
+ */
+ void SetNoTextLongPressAction(NoTextTap::Action action);
+
+ /**
+ * @brief Retrieves the action when there is a long press event on top of a text area with no text.
+ *
+ * @return The action to do.
+ */
+ NoTextTap::Action GetNoTextLongPressAction() const;
+
+ /**
+ * @brief Query if Underline settings were provided by string or map
+ * @return bool true if set by string
+ */
+ bool IsUnderlineSetByString();
+
+ /**
+ * Set method underline setting were set by
+ * @param[in] bool, true if set by string
+ */
+ void UnderlineSetByString(bool setByString);
+
+ /**
+ * @brief Query if shadow settings were provided by string or map
+ * @return bool true if set by string
+ */
+ bool IsShadowSetByString();
+
+ /**
+ * Set method shadow setting were set by
+ * @param[in] bool, true if set by string
+ */
+ void ShadowSetByString(bool setByString);
+
+ /**
+ * @brief Query if outline settings were provided by string or map
+ * @return bool true if set by string
+ */
+ bool IsOutlineSetByString();
+
+ /**
+ * Set method outline setting were set by
+ * @param[in] bool, true if set by string
+ */
+ void OutlineSetByString(bool setByString);
+
+ /**
+ * @brief Query if font style settings were provided by string or map
+ * @return bool true if set by string
+ */
+ bool IsFontStyleSetByString();
+
+ /**
+ * Set method font style setting were set by
+ * @param[in] bool, true if set by string
+ */
+ void FontStyleSetByString(bool setByString);
+
+ /**
+ * @brief Query if Strikethrough settings were provided by string or map
+ * @return bool true if set by string
+ */
+ bool IsStrikethroughSetByString();
+
+ /**
+ * Set method Strikethrough setting were set by
+ * @param[in] bool, true if set by string
+ */
+ void StrikethroughSetByString(bool setByString);
+
+ /**
+ * @brief Set the override used for strikethrough height, 0 indicates height will be supplied by font metrics
+ *
+ * @param[in] height The height in pixels of the strikethrough
+ */
+ void SetStrikethroughHeight(float height);
+
+ /**
+ * @brief Retrieves the override height of an strikethrough, 0 indicates height is supplied by font metrics
+ *
+ * @return The height of the strikethrough, or 0 if height is not overrided.
+ */
+ float GetStrikethroughHeight() const;
+
+ /**
+ * @brief Set the strikethrough color.
+ *
+ * @param[in] color color of strikethrough.
+ */
+ void SetStrikethroughColor(const Vector4& color);
+
+ /**
+ * @brief Retrieve the strikethrough color.
+ *
+ * @return The strikethrough color.
+ */
+ const Vector4& GetStrikethroughColor() const;
+
+ /**
+ * @brief Set the strikethrough enabled flag.
+ *
+ * @param[in] enabled The strikethrough enabled flag.
+ */
+ void SetStrikethroughEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether the text has a strikethrough or not.
+ *
+ * @return The strikethrough state.
+ */
+ bool IsStrikethroughEnabled() const;
+
+public: // Update.
+ /**
+ * @brief Replaces any text previously set.
+ *
+ * @note This will be converted into UTF-32 when stored in the text model.
+ * @param[in] text A string of UTF-8 characters.
+ */
+ void SetText(const std::string& text);
+
+ /**
+ * @brief Retrieve any text previously set.
+ *
+ * @param[out] text A string of UTF-8 characters.
+ */
+ void GetText(std::string& text) const;
+
+ /**
+ * @brief Replaces any placeholder text previously set.
+ *
+ * @param[in] type Different placeholder-text can be shown when the control is active/inactive.
+ * @param[in] text A string of UTF-8 characters.
+ */
+ void SetPlaceholderText(PlaceholderType type, const std::string& text);
+
+ /**
+ * @brief Retrieve any placeholder text previously set.
+ *
+ * @param[in] type Different placeholder-text can be shown when the control is active/inactive.
+ * @param[out] A string of UTF-8 characters.
+ */
+ void GetPlaceholderText(PlaceholderType type, std::string& text) const;
+
+ /**
+ * @ brief Update the text after a font change
+ * @param[in] newDefaultFont The new font to change to
+ */
+ void UpdateAfterFontChange(const std::string& newDefaultFont);
+
+ /**
+ * @brief The method acquires currently selected text
+ * @param selectedText variable to place selected text in
+ */
+ void RetrieveSelection(std::string& selectedText) const;
+
+ /**
+ * @brief The method sets selection in given range
+ * @param start index of first character
+ * @param end index of first character after selection
+ */
+ void SetSelection(int start, int end);
+
+ /**
+ * @brief This method retrieve indexes of current selection
+ *
+ * @return a pair, where first element is left index of selection and second is the right one
+ */
+ std::pair<int, int> GetSelectionIndexes() const;
+
+ /**
+ * Place string in system clipboard
+ * @param source std::string
+ */
+ void CopyStringToClipboard(const std::string& source);
+
+ /**
+ * Place currently selected text in system clipboard
+ * @param deleteAfterSending flag pointing if text should be deleted after sending to clipboard
+ */
+ void SendSelectionToClipboard(bool deleteAfterSending);
+
+public: // Default style & Input style
+ /**
+ * @brief Set the default font family.
+ *
+ * @param[in] defaultFontFamily The default font family.
+ */
+ void SetDefaultFontFamily(const std::string& defaultFontFamily);
+
+ /**
+ * @brief Retrieve the default font family.
+ *
+ * @return The default font family.
+ */
+ const std::string& GetDefaultFontFamily() const;
+
+ /**
+ * @brief Sets the placeholder text font family.
+ * @param[in] placeholderTextFontFamily The placeholder text font family.
+ */
+ void SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily);
+
+ /**
+ * @brief Retrieves the placeholder text font family.
+ *
+ * @return The placeholder text font family
+ */
+ const std::string& GetPlaceholderFontFamily() const;
+
+ /**
+ * @brief Sets the default font weight.
+ *
+ * @param[in] weight The font weight.
+ */
+ void SetDefaultFontWeight(FontWeight weight);
+
+ /**
+ * @brief Whether the font's weight has been defined.
+ */
+ bool IsDefaultFontWeightDefined() const;
+
+ /**
+ * @brief Retrieves the default font weight.
+ *
+ * @return The default font weight.
+ */
+ FontWeight GetDefaultFontWeight() const;
+
+ /**
+ * @brief Sets the placeholder text font weight.
+ *
+ * @param[in] weight The font weight
+ */
+ void SetPlaceholderTextFontWeight(FontWeight weight);
+
+ /**
+ * @brief Whether the font's weight has been defined.
+ *
+ * @return True if the placeholder text font weight is defined
+ */
+ bool IsPlaceholderTextFontWeightDefined() const;
+
+ /**
+ * @brief Retrieves the placeholder text font weight.
+ *
+ * @return The placeholder text font weight
+ */
+ FontWeight GetPlaceholderTextFontWeight() const;
+
+ /**
+ * @brief Sets the default font width.
+ *
+ * @param[in] width The font width.
+ */
+ void SetDefaultFontWidth(FontWidth width);
+
+ /**
+ * @brief Whether the font's width has been defined.
+ */
+ bool IsDefaultFontWidthDefined() const;
+
+ /**
+ * @brief Retrieves the default font width.
+ *
+ * @return The default font width.
+ */
+ FontWidth GetDefaultFontWidth() const;
+
+ /**
+ * @brief Sets the placeholder text font width.
+ *
+ * @param[in] width The font width
+ */
+ void SetPlaceholderTextFontWidth(FontWidth width);
+
+ /**
+ * @brief Whether the font's width has been defined.
+ *
+ * @return True if the placeholder text font width is defined
+ */
+ bool IsPlaceholderTextFontWidthDefined() const;
+
+ /**
+ * @brief Retrieves the placeholder text font width.
+ *
+ * @return The placeholder text font width
+ */
+ FontWidth GetPlaceholderTextFontWidth() const;
+
+ /**
+ * @brief Sets the default font slant.
+ *
+ * @param[in] slant The font slant.
+ */
+ void SetDefaultFontSlant(FontSlant slant);
+
+ /**
+ * @brief Whether the font's slant has been defined.
+ */
+ bool IsDefaultFontSlantDefined() const;
+
+ /**
+ * @brief Retrieves the default font slant.
+ *
+ * @return The default font slant.
+ */
+ FontSlant GetDefaultFontSlant() const;
+
+ /**
+ * @brief Sets the placeholder text font slant.
+ *
+ * @param[in] slant The font slant
+ */
+ void SetPlaceholderTextFontSlant(FontSlant slant);
+
+ /**
+ * @brief Whether the font's slant has been defined.
+ *
+ * @return True if the placeholder text font slant is defined
+ */
+ bool IsPlaceholderTextFontSlantDefined() const;
+
+ /**
+ * @brief Retrieves the placeholder text font slant.
+ *
+ * @return The placeholder text font slant
+ */
+ FontSlant GetPlaceholderTextFontSlant() const;
+
+ /**
+ * @brief Set the default font size.
+ *
+ * @param[in] fontSize The default font size
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetDefaultFontSize(float fontSize, FontSizeType type);
+
+ /**
+ * @brief Retrieve the default point size.
+ *
+ * @param[in] type The font size type
+ * @return The default point size.
+ */
+ float GetDefaultFontSize(FontSizeType type) const;
+
+ /**
+ * @brief Set the font size scale.
+ *
+ * @param[in] scale The font size scale
+ */
+ void SetFontSizeScale(float scale);
+
+ /**
+ * @brief Get the font size scale.
+ *
+ * @return The font size scale.
+ */
+ float GetFontSizeScale() const;
+
+ /**
+ * @brief Set the font size scale enabled flag.
+ *
+ * @param[in] enabled whether to enable the font size scale.
+ */
+ void SetFontSizeScaleEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether the font size scale is enabled or not.
+ *
+ * @return @e true if the font size scale is enabled, otherwise returns @e false.
+ */
+ bool IsFontSizeScaleEnabled() const;
+
+ /**
+ * @brief Sets the Placeholder text font size.
+ * @param[in] fontSize The placeholder text font size
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetPlaceholderTextFontSize(float fontSize, FontSizeType type);
+
+ /**
+ * @brief Retrieves the Placeholder text font size.
+ * @param[in] type The font size type
+ * @return The placeholder font size
+ */
+ float GetPlaceholderTextFontSize(FontSizeType type) const;
+
+ /**
+ * @brief Sets the text's default color.
+ *
+ * @param color The default color.
+ */
+ void SetDefaultColor(const Vector4& color);
+
+ /**
+ * @brief Retrieves the text's default color.
+ *
+ * @return The default color.
+ */
+ const Vector4& GetDefaultColor() const;
+
+ /**
+ * @brief Sets the user interaction enabled.
+ *
+ * @param enabled whether to enable the user interaction.
+ */
+ void SetUserInteractionEnabled(bool enabled);
+
+ /**
+ * @brief Whether the user interaction is enabled.
+ *
+ * @return true if the user interaction is enabled, false otherwise.
+ */
+ bool IsUserInteractionEnabled() const;
+
+ /**
+ * @brief Set the text color
+ *
+ * @param textColor The text color
+ */
+ void SetPlaceholderTextColor(const Vector4& textColor);
+
+ /**
+ * @brief Retrieve the text color
+ *
+ * @return The text color
+ */
+ const Vector4& GetPlaceholderTextColor() const;
+
+ /**
+ * @brief Set the shadow offset.
+ *
+ * @param[in] shadowOffset The shadow offset, 0,0 indicates no shadow.
+ */
+ void SetShadowOffset(const Vector2& shadowOffset);
+
+ /**
+ * @brief Retrieve the shadow offset.
+ *
+ * @return The shadow offset.
+ */
+ const Vector2& GetShadowOffset() const;
+
+ /**
+ * @brief Set the shadow color.
+ *
+ * @param[in] shadowColor The shadow color.
+ */
+ void SetShadowColor(const Vector4& shadowColor);
+
+ /**
+ * @brief Retrieve the shadow color.
+ *
+ * @return The shadow color.
+ */
+ const Vector4& GetShadowColor() const;
+
+ /**
+ * @brief Set the shadow blur radius.
+ *
+ * @param[in] shadowBlurRadius The shadow blur radius, 0,0 indicates no blur.
+ */
+ void SetShadowBlurRadius(const float& shadowBlurRadius);
+
+ /**
+ * @brief Retrieve the shadow blur radius.
+ *
+ * @return The shadow blur radius.
+ */
+ const float& GetShadowBlurRadius() const;
+
+ /**
+ * @brief Set the underline color.
+ *
+ * @param[in] color color of underline.
+ */
+ void SetUnderlineColor(const Vector4& color);
+
+ /**
+ * @brief Retrieve the underline color.
+ *
+ * @return The underline color.
+ */
+ const Vector4& GetUnderlineColor() const;
+
+ /**
+ * @brief Set the underline enabled flag.
+ *
+ * @param[in] enabled The underline enabled flag.
+ */
+ void SetUnderlineEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether the text is underlined or not.
+ *
+ * @return The underline state.
+ */
+ bool IsUnderlineEnabled() const;
+
+ /**
+ * @brief Set the override used for underline height, 0 indicates height will be supplied by font metrics
+ *
+ * @param[in] height The height in pixels of the underline
+ */
+ void SetUnderlineHeight(float height);
+
+ /**
+ * @brief Retrieves the override height of an underline, 0 indicates height is supplied by font metrics
+ *
+ * @return The height of the underline, or 0 if height is not overrided.
+ */
+ float GetUnderlineHeight() const;
+
+ /**
+ * @brief Sets the underline type.
+ * @param[in] type The underline type.
+ */
+ void SetUnderlineType(Text::Underline::Type type);
+
+ /**
+ * @brief Retrieve underline type.
+ * @return The underline type.
+ */
+ Text::Underline::Type GetUnderlineType() const;
+
+ /**
+ * @brief Set the width of the dashes of the dashed underline.
+ *
+ * @param[in] width The width in pixels of the dashes of the dashed underline.
+ */
+ void SetDashedUnderlineWidth(float width);
+
+ /**
+ * @brief Retrieves the width of the dashes of the dashed underline.
+ *
+ * @return The width of the dashes of the dashed underline.
+ */
+ float GetDashedUnderlineWidth() const;
+
+ /**
+ * @brief Set the gap between the dashes of the dashed underline.
+ *
+ * @param[in] gap The gap between the dashes of the dashed underline.
+ */
+ void SetDashedUnderlineGap(float gap);
+
+ /**
+ * @brief Retrieves the gap between the dashes of the dashed underline.
+ *
+ * @return The The gap between the dashes of the dashed underline.
+ */
+ float GetDashedUnderlineGap() const;
+
+ /**
+ * @brief Set the outline color.
+ *
+ * @param[in] color color of outline.
+ */
+ void SetOutlineColor(const Vector4& color);
+
+ /**
+ * @brief Retrieve the outline color.
+ *
+ * @return The outline color.
+ */
+ const Vector4& GetOutlineColor() const;
+
+ /**
+ * @brief Set the outline width
+ *
+ * @param[in] width The width in pixels of the outline, 0 indicates no outline
+ */
+ void SetOutlineWidth(uint16_t width);
+
+ /**
+ * @brief Retrieves the width of an outline
+ *
+ * @return The width of the outline.
+ */
+ uint16_t GetOutlineWidth() const;
+
+ /**
+ * @brief Set the background color.
+ *
+ * @param[in] color color of background.
+ */
+ void SetBackgroundColor(const Vector4& color);
+
+ /**
+ * @brief Retrieve the background color.
+ *
+ * @return The background color.
+ */
+ const Vector4& GetBackgroundColor() const;
+
+ /**
+ * @brief Set the background enabled flag.
+ *
+ * @param[in] enabled The background enabled flag.
+ */
+ void SetBackgroundEnabled(bool enabled);
+
+ /**
+ * @brief Returns whether to enable text background or not.
+ *
+ * @return Whether text background is enabled.
+ */
+ bool IsBackgroundEnabled() const;
+
+ /**
+ * @brief Sets the emboss's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] embossProperties The emboss's properties string.
+ */
+ void SetDefaultEmbossProperties(const std::string& embossProperties);
+
+ /**
+ * @brief Retrieves the emboss's properties string.
+ *
+ * @return The emboss's properties string.
+ */
+ const std::string& GetDefaultEmbossProperties() const;
+
+ /**
+ * @brief Sets the outline's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] outlineProperties The outline's properties string.
+ */
+ void SetDefaultOutlineProperties(const std::string& outlineProperties);
+
+ /**
+ * @brief Retrieves the outline's properties string.
+ *
+ * @return The outline's properties string.
+ */
+ const std::string& GetDefaultOutlineProperties() const;
+
+ /**
+ * @brief Sets the default line spacing.
+ *
+ * @param[in] lineSpacing The line spacing.
+ *
+ * @return True if lineSpacing has been updated, false otherwise
+ */
+ bool SetDefaultLineSpacing(float lineSpacing);
+
+ /**
+ * @brief Retrieves the default line spacing.
+ *
+ * @return The line spacing.
+ */
+ float GetDefaultLineSpacing() const;
+
+ /**
+ * @brief Sets the default line size.
+ *
+ * @param[in] lineSize The line size.
+ *
+ * @return True if lineSize has been updated, false otherwise
+ */
+ bool SetDefaultLineSize(float lineSize);
+
+ /**
+ * @brief Retrieves the default line size.
+ *
+ * @return The line size.
+ */
+ float GetDefaultLineSize() const;
+
+ /**
+ * @brief Sets the relative line size to the original line size.
+ *
+ * @param[in] relativeLineSize The relativeline size.
+ *
+ * @return True if relativeLineSize has been updated, false otherwise
+ */
+ bool SetRelativeLineSize(float lineSize);
+
+ /**
+ * @brief Retrieves the relative line size.
+ *
+ * @return The relative line size.
+ */
+ float GetRelativeLineSize() const;
+
+ /**
+ * @brief Sets the input text's color.
+ *
+ * @param[in] color The input text's color.
+ */
+ void SetInputColor(const Vector4& color);
+
+ /**
+ * @brief Retrieves the input text's color.
+ *
+ * @return The input text's color.
+ */
+ const Vector4& GetInputColor() const;
+
+ /**
+ * @brief Sets the input text's font family name.
+ *
+ * @param[in] fontFamily The text's font family name.
+ */
+ void SetInputFontFamily(const std::string& fontFamily);
+
+ /**
+ * @brief Retrieves the input text's font family name.
+ *
+ * @return The input text's font family name.
+ */
+ const std::string& GetInputFontFamily() const;
+
+ /**
+ * @brief Sets the input font's weight.
+ *
+ * @param[in] weight The input font's weight.
+ */
+ void SetInputFontWeight(FontWeight weight);
+
+ /**
+ * @return Whether the font's weight has been defined.
+ */
+ bool IsInputFontWeightDefined() const;
+
+ /**
+ * @brief Retrieves the input font's weight.
+ *
+ * @return The input font's weight.
+ */
+ FontWeight GetInputFontWeight() const;
+
+ /**
+ * @brief Sets the input font's width.
+ *
+ * @param[in] width The input font's width.
+ */
+ void SetInputFontWidth(FontWidth width);
+
+ /**
+ * @return Whether the font's width has been defined.
+ */
+ bool IsInputFontWidthDefined() const;
+
+ /**
+ * @brief Retrieves the input font's width.
+ *
+ * @return The input font's width.
+ */
+ FontWidth GetInputFontWidth() const;
+
+ /**
+ * @brief Sets the input font's slant.
+ *
+ * @param[in] slant The input font's slant.
+ */
+ void SetInputFontSlant(FontSlant slant);
+
+ /**
+ * @return Whether the font's slant has been defined.
+ */
+ bool IsInputFontSlantDefined() const;
+
+ /**
+ * @brief Retrieves the input font's slant.
+ *
+ * @return The input font's slant.
+ */
+ FontSlant GetInputFontSlant() const;
+
+ /**
+ * @brief Sets the input font's point size.
+ *
+ * @param[in] size The input font's point size.
+ */
+ void SetInputFontPointSize(float size);
+
+ /**
+ * @brief Retrieves the input font's point size.
+ *
+ * @return The input font's point size.
+ */
+ float GetInputFontPointSize() const;
+
+ /**
+ * @brief Sets the input line spacing.
+ *
+ * @param[in] lineSpacing The line spacing.
+ */
+ void SetInputLineSpacing(float lineSpacing);
+
+ /**
+ * @brief Retrieves the input line spacing.
+ *
+ * @return The line spacing.
+ */
+ float GetInputLineSpacing() const;
+
+ /**
+ * @brief Sets the input shadow's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] shadowProperties The shadow's properties string.
+ */
+ void SetInputShadowProperties(const std::string& shadowProperties);
+
+ /**
+ * @brief Retrieves the input shadow's properties string.
+ *
+ * @return The shadow's properties string.
+ */
+ const std::string& GetInputShadowProperties() const;
+
+ /**
+ * @brief Sets the input underline's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] underlineProperties The underline's properties string.
+ */
+ void SetInputUnderlineProperties(const std::string& underlineProperties);
+
+ /**
+ * @brief Retrieves the input underline's properties string.
+ *
+ * @return The underline's properties string.
+ */
+ const std::string& GetInputUnderlineProperties() const;
+
+ /**
+ * @brief Sets the input emboss's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] embossProperties The emboss's properties string.
+ */
+ void SetInputEmbossProperties(const std::string& embossProperties);
+
+ /**
+ * @brief Retrieves the input emboss's properties string.
+ *
+ * @return The emboss's properties string.
+ */
+ const std::string& GetInputEmbossProperties() const;
+
+ /**
+ * @brief Sets input the outline's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] outlineProperties The outline's properties string.
+ */
+ void SetInputOutlineProperties(const std::string& outlineProperties);
+
+ /**
+ * @brief Retrieves the input outline's properties string.
+ *
+ * @return The outline's properties string.
+ */
+ const std::string& GetInputOutlineProperties() const;
+
+ /**
+ * @brief Sets the input strikethrough's properties string.
+ *
+ * @note The string is stored to be recovered.
+ *
+ * @param[in] strikethroughProperties The strikethrough's properties string.
+ */
+ void SetInputStrikethroughProperties(const std::string& strikethroughProperties);
+
+ /**
+ * @brief Retrieves the input strikethrough's properties string.
+ *
+ * @return The strikethrough's properties string.
+ */
+ const std::string& GetInputStrikethroughProperties() const;
+
+ /**
+ * @brief Set the control's interface.
+ *
+ * @param[in] controlInterface The control's interface.
+ */
+ void SetControlInterface(ControlInterface* controlInterface);
+
+ /**
+ * @brief Set the anchor control's interface.
+ *
+ * @param[in] anchorControlInterface The control's interface.
+ */
+ void SetAnchorControlInterface(AnchorControlInterface* anchorControlInterface);
+
+ /**
+ * @brief Sets the character spacing.
+ *
+ * @note A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
+ *
+ * @param[in] characterSpacing The character spacing.
+ */
+ void SetCharacterSpacing(float characterSpacing);
+
+ /**
+ * @brief Retrieves the character spacing.
+ *
+ * @note A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
+ *
+ * @return The character spacing.
+ */
+ const float GetCharacterSpacing() const;
+
+public: // Queries & retrieves.
+ /**
+ * @brief Return the layout engine.
+ *
+ * @return A reference to the layout engine.
+ */
+ Layout::Engine& GetLayoutEngine();
+
+ /**
+ * @brief Return a view of the text.
+ *
+ * @return A reference to the view.
+ */
+ View& GetView();
+
+ /**
+ * @copydoc Control::GetNaturalSize()
+ */
+ Vector3 GetNaturalSize();
+
+ /**
+ * @copydoc Control::GetHeightForWidth()
+ */
+ float GetHeightForWidth(float width);
+
+ /**
+ * @brief Calculates the point size for text for given layout()
+ */
+ void FitPointSizeforLayout(Size layoutSize);
+
+ /**
+ * @brief Checks if the point size fits within the layout size.
+ *
+ * @return Whether the point size fits within the layout size.
+ */
+ bool CheckForTextFit(float pointSize, Size& layoutSize);
+
+ /**
+ * @brief Retrieves the text's number of lines for a given width.
+ * @param[in] width The width of the text's area.
+ * @ return The number of lines.
+ */
+ int GetLineCount(float width);
+
+ /**
+ * @brief Retrieves the text's model.
+ *
+ * @return A pointer to the text's model.
+ */
+ const ModelInterface* const GetTextModel() const;
+
+ /**
+ * @brief Used to get scrolled distance by user input
+ *
+ * @return Distance from last scroll offset to new scroll offset
+ */
+ float GetScrollAmountByUserInput();
+
+ /**
+ * @brief Get latest scroll amount, control size and layout size
+ *
+ * This method is used to get information of control's scroll
+ * @param[out] scrollPosition The current scrolled position
+ * @param[out] controlHeight The size of a UI control
+ * @param[out] layoutHeight The size of a bounding box to layout text within.
+ *
+ * @return Whether the text scroll position is changed or not after last update.
+ */
+ bool GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight);
+
+ /**
+ * @brief Used to set the hidden input option
+ */
+ void SetHiddenInputOption(const Property::Map& options);
+
+ /**
+ * @brief Used to get the hidden input option
+ */
+ void GetHiddenInputOption(Property::Map& options);
+
+ /**
+ * @brief Used to set the input filter option
+ */
+ void SetInputFilterOption(const Property::Map& options);
+
+ /**
+ * @brief Used to get the input filter option
+ */
+ void GetInputFilterOption(Property::Map& options);
+
+ /**
+ * @brief Sets the Placeholder Properties.
+ *
+ * @param[in] map The placeholder property map
+ */
+ void SetPlaceholderProperty(const Property::Map& map);
+
+ /**
+ * @brief Retrieves the Placeholder Property map.
+ *
+ * @param[out] map The property map
+ */
+ void GetPlaceholderProperty(Property::Map& map);
+
+ /**
+ * @brief Checks text direction.
+ * @return The text direction.
+ */
+ Toolkit::DevelText::TextDirection::Type GetTextDirection();
+
+ /**
+ * @brief Retrieves vertical line alignment
+ * @return The vertical line alignment
+ */
+ Toolkit::DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const;
+
+ /**
+ * @brief Sets vertical line alignment
+ * @param[in] alignment The vertical line alignment for the text
+ */
+ void SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment);
+
+ /**
+ * @brief Retrieves ellipsis position
+ * @return The ellipsis position
+ */
+ Toolkit::DevelText::EllipsisPosition::Type GetEllipsisPosition() const;
+
+ /**
+ * @brief Sets ellipsis position
+ * @param[in] ellipsisPosition The ellipsis position for the text
+ */
+ void SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition);
+
+ /**
+ * @brief Retrieves ignoreSpaceAfterText value from model
+ * @return The value of ignoreSpaceAfterText
+ */
+ bool IsIgnoreSpacesAfterText() const;
+
+ /**
+ * @brief Sets ignoreSpaceAfterText value to model
+ * @param[in] ignore The value of ignoreSpacesAfterText for the text
+ */
+ void SetIgnoreSpacesAfterText(bool ignore);
+
+ /**
+ * @brief Sets SetMatchLayoutDirection value to model
+ * @param[in] match The value of matchLayoutDirection for the text
+ */
+ void SetMatchLayoutDirection(DevelText::MatchLayoutDirection type);
+
+ /**
+ * @brief Retrieves matchLayoutDirection value from model
+ * @return The value of matchLayoutDirection
+ */
+ DevelText::MatchLayoutDirection GetMatchLayoutDirection() const;
+
+ /**
+ * @brief Sets layoutDirection type value.
+ * @param[in] layoutDirection The value of the layout direction type.
+ */
+ void SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection);
+
+ /**
+ * @brief Gets layoutDirection type value.
+ * @param[in] actor The actor which will get the layout direction type.
+ * @return The value of the layout direction type.
+ */
+ Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
+
+ /**
+ * @brief Get the rendered size of a specific text range.
+ * if the requested text is at multilines, multiple sizes will be returned for each text located in a separate line.
+ * if a line contains characters with different directions, multiple sizes will be returned for each block of contiguous characters with the same direction.
+ *
+ * @param[in] startIndex start index of the text requested to calculate size for.
+ * @param[in] endIndex end index(included) of the text requested to calculate size for.
+ * @return list of sizes of the reuested text.
+ */
+ Vector<Vector2> GetTextSize(CharacterIndex startIndex, CharacterIndex endIndex);
+
+ /**
+ * @brief Get the top/left rendered position of a specific text range.
+ * if the requested text is at multilines, multiple positions will be returned for each text located in a separate line.
+ * if a line contains characters with different directions, multiple positions will be returned for each block of contiguous characters with the same direction.
+ *
+ * @param[in] startIndex start index of the text requested to get position to.
+ * @param[in] endIndex end index(included) of the text requested to get position to.
+ * @return list of positions of the requested text.
+ */
+ Vector<Vector2> GetTextPosition(CharacterIndex startIndex, CharacterIndex endIndex);
+
+ /**
+ * @brief Gets the bounding box of a specific text range.
+ *
+ * @param[in] startIndex start index of the text requested to get bounding box to.
+ * @param[in] endIndex end index(included) of the text requested to get bounding box to.
+ * @return bounding box of the requested text.
+ */
+ Rect<> GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex);
+
+ /**
+ * @brief Sets the layout direction changed.
+ */
+ void ChangedLayoutDirection();
+
+ /**
+ * @brief Retrieves if showing real text or not.
+ * @return The value of showing real text.
+ */
+ bool IsShowingRealText() const;
+
+public: // Relayout.
+ /**
+ * @brief Triggers a relayout which updates View (if necessary).
+ *
+ * @note UI Controls are expected to minimize calls to this method e.g. call once after size negotiation.
+ * @param[in] size A the size of a bounding box to layout text within.
+ * @param[in] layoutDirection The direction of the system language.
+ *
+ * @return Whether the text model or decorations were updated.
+ */
+ UpdateTextType Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection = Dali::LayoutDirection::LEFT_TO_RIGHT);
+
+ /**
+ * @brief Request a relayout using the ControlInterface.
+ */
+ void RequestRelayout();
+
+public: // Input style change signals.
+ /**
+ * @return Whether the queue of input style changed signals is empty.
+ */
+ bool IsInputStyleChangedSignalsQueueEmpty();
+
+ /**
+ * @brief Process all pending input style changed signals.
+ *
+ * Calls the Text::ControlInterface::InputStyleChanged() method which is overriden by the
+ * text controls. Text controls may send signals to state the input style has changed.
+ */
+ void ProcessInputStyleChangedSignals();
+
+public: // Text-input Event Queuing.
+ /**
+ * @brief Called by editable UI controls when keyboard focus is gained.
+ */
+ void KeyboardFocusGainEvent();
+
+ /**
+ * @brief Called by editable UI controls when focus is lost.
+ */
+ void KeyboardFocusLostEvent();
+
+ /**
+ * @brief Called by editable UI controls when key events are received.
+ *
+ * @param[in] event The key event.
+ * @param[in] type Used to distinguish between regular key events and InputMethodContext events.
+ */
+ bool KeyEvent(const Dali::KeyEvent& event);
+
+ /**
+ * @brief Called by anchor when a tap gesture occurs.
+ * @param[in] x The x position relative to the top-left of the parent control.
+ * @param[in] y The y position relative to the top-left of the parent control.
+ */
+ void AnchorEvent(float x, float y);
+
+ /**
+ * @brief Called by editable UI controls when a tap gesture occurs.
+ * @param[in] tapCount The number of taps.
+ * @param[in] x The x position relative to the top-left of the parent control.
+ * @param[in] y The y position relative to the top-left of the parent control.
+ */
+ void TapEvent(unsigned int tapCount, float x, float y);
+
+ /**
+ * @brief Called by editable UI controls when a pan gesture occurs.
+ *
+ * @param[in] state The state of the gesture.
+ * @param[in] displacement This distance panned since the last pan gesture.
+ */
+ void PanEvent(GestureState state, const Vector2& displacement);
+
+ /**
+ * @brief Called by editable UI controls when a long press gesture occurs.
+ *
+ * @param[in] state The state of the gesture.
+ * @param[in] x The x position relative to the top-left of the parent control.
+ * @param[in] y The y position relative to the top-left of the parent control.
+ */
+ void LongPressEvent(GestureState state, float x, float y);
+
+ /**
+ * @brief Used to get the Primary cursor position.
+ *
+ * @return Primary cursor position.
+ */
+ CharacterIndex GetPrimaryCursorPosition() const;
+
+ /**
+ * @brief Used to set the Primary cursor position.
+ *
+ * @param[in] index for the Primary cursor position.
+ * @param[in] focused true if UI control has gained focus to receive key event, false otherwise.
+ * @return[in] true if cursor position changed, false otherwise.
+ */
+ bool SetPrimaryCursorPosition(CharacterIndex index, bool focused);
+
+ /**
+ * @brief Creates a selection event.
+ *
+ * It could be called from the TapEvent (double tap) or when the text selection popup's sellect all button is pressed.
+ *
+ * @param[in] x The x position relative to the top-left of the parent control.
+ * @param[in] y The y position relative to the top-left of the parent control.
+ * @param[in] selection type like the whole text is selected or unselected.
+ */
+ void SelectEvent(float x, float y, SelectionType selection);
+
+ /**
+ * @copydoc Text::SelectableControlInterface::SetTextSelectionRange()
+ */
+ void SetTextSelectionRange(const uint32_t* start, const uint32_t* end);
+
+ /**
+ * @copydoc Text::SelectableControlInterface::GetTextSelectionRange()
+ */
+ Uint32Pair GetTextSelectionRange() const;
+
+ /**
+ * @copydoc Text::SelectableControlInterface::SelectWholeText()
+ */
+ void SelectWholeText();
+
+ /**
+ * @copydoc Text::EditableControlInterface::CopyText()
+ */
+ string CopyText();
+
+ /**
+ * @copydoc Text::EditableControlInterface::CutText()
+ */
+ string CutText();
+
+ /**
+ * @copydoc Text::EditableControlInterface::PasteText()
+ */
+ void PasteText();
+
+ /**
+ * @copydoc Text::SelectableControlInterface::SelectNone()
+ */
+ void SelectNone();
+
+ /**
+ * @copydoc Text::SelectableControlInterface::SelectText()
+ */
+ void SelectText(const uint32_t start, const uint32_t end);
+
+ /**
+ * @copydoc Text::SelectableControlInterface::GetSelectedText()
+ */
+ string GetSelectedText() const;
+
+ /**
+ * @copydoc Text::EditableControlInterface::IsEditable()
+ */
+ virtual bool IsEditable() const;
+
+ /**
+ * @copydoc Text::EditableControlInterface::SetEditable()
+ */
+ virtual void SetEditable(bool editable);
+
+ /**
+ * @copydoc Dali::Toolkit::Internal::TextEditor::ScrollBy()
+ */
+ virtual void ScrollBy(Vector2 scroll);
+
+ /**
+ * @brief Whether the text is scrollable.
+ * @return Returns true if the text is scrollable.
+ */
+ bool IsScrollable(const Vector2& displacement);
+
+ /**
+ * @copydoc Dali::Toolkit::Internal::TextEditor::GetHorizontalScrollPosition()
+ */
+ float GetHorizontalScrollPosition();
+
+ /**
+ * @copydoc Dali::Toolkit::Internal::TextEditor::GetVerticalScrollPosition()
+ */
+ float GetVerticalScrollPosition();
+
+ /**
+ * @brief Event received from input method context
+ *
+ * @param[in] inputMethodContext The input method context.
+ * @param[in] inputMethodContextEvent The event received.
+ * @return A data struture indicating if update is needed, cursor position and current text.
+ */
+ InputMethodContext::CallbackData OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent);
+
+ /**
+ * @brief Event from Clipboard notifying an Item has been selected for pasting
+ */
+ void PasteClipboardItemEvent();
+
+ /**
+ * @brief Return true when text control should clear key input focus when escape key is pressed.
+ *
+ * @return Whether text control should clear key input focus or not when escape key is pressed.
+ */
+ bool ShouldClearFocusOnEscape() const;
+
+ /**
+ * @brief Create an actor that renders the text background color
+ *
+ * @return the created actor or an empty handle if no background color needs to be rendered.
+ */
+ Actor CreateBackgroundActor();
+
+ /**
+ * @brief Used to reset the cursor position after setting a new text.
+ *
+ * @param[in] cursorIndex Where to place the cursor.
+ */
+ void ResetCursorPosition(CharacterIndex cursorIndex);
+
+ /**
+ * @brief The method acquires current position of cursor
+ * @return unsigned value with cursor position
+ */
+ CharacterIndex GetCursorPosition();
+
+ /**
+ * @brief Resets a provided vector with actors that marks the position of anchors in markup enabled text
+ *
+ * @param[out] anchorActors the vector of actor (empty collection if no anchors available).
+ */
+ void GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors);
+
+ /**
+ * @brief Return an index of first anchor in the anchor vector whose boundaries includes given character offset
+ *
+ * @param[in] characterOffset A position in text coords.
+ *
+ * @return the index in anchor vector (-1 if an anchor not found)
+ */
+ int GetAnchorIndex(size_t characterOffset);
+
+protected: // Inherit from Text::Decorator::ControllerInterface.
+ /**
+ * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::GetTargetSize()
+ */
+ void GetTargetSize(Vector2& targetSize) override;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::AddDecoration()
+ */
+ void AddDecoration(Actor& actor, DecorationType type, bool needsClipping) override;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::DecorationEvent()
+ */
+ void DecorationEvent(HandleType handle, HandleState state, float x, float y) override;
+
+protected: // Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
+ /**
+ * @copydoc Dali::Toolkit::TextSelectionPopup::TextPopupButtonCallbackInterface::TextPopupButtonTouched()
+ */
+ void TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button) override;
+
+protected: // Inherit from HiddenText.
+ /**
+ * @brief Invoked from HiddenText when showing time of the last character was expired
+ */
+ void DisplayTimeExpired() override;
+
+private: // Private contructors & copy operator.
+ /**
+ * @brief Private constructor.
+ */
+ Controller()
+ : Controller(nullptr, nullptr, nullptr, nullptr)
+ {
+ }
+
+ /**
+ * @brief Private constructor.
+ */
+ Controller(ControlInterface* controlInterface)
+ : Controller(controlInterface, nullptr, nullptr, nullptr)
+ {
+ }
+
+ /**
+ * @brief Private constructor.
+ */
+ Controller(ControlInterface* controlInterface,
+ EditableControlInterface* editableControlInterface,
+ SelectableControlInterface* selectableControlInterface,
+ AnchorControlInterface* anchorControlInterface);
+
+ Controller(const Controller& handle) = delete;
+ Controller& operator=(const Controller& handle) = delete;
+
+protected: // Destructor.
+ /**
+ * @brief A reference counted object may only be deleted by calling Unreference().
+ */
+ virtual ~Controller();
+
+public:
+ struct Impl; ///< Made public for testing purposes
+
+private:
+ struct EventHandler;
+ struct InputFontHandler;
+ struct InputProperties;
+ struct PlaceholderHandler;
+ struct Relayouter;
+ struct TextUpdater;
+
+ Impl* mImpl;
+};
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-anchor.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-#include <memory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/anchor.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessAnchor(const Tag& tag, Anchor& anchor)
-{
- anchor.href = nullptr;
-
- for(auto&& attribute : tag.attributes)
- {
- if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::HREF, attribute.nameBuffer, attribute.nameLength))
- {
- Length hrefLength = attribute.valueLength + 1;
- anchor.href = new char[hrefLength];
- memcpy(anchor.href, attribute.valueBuffer, hrefLength);
- anchor.href[hrefLength - 1] = '\0';
- // The memory is freed when the font run is removed from the logical model.
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
\ No newline at end of file
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ANCHOR_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ANCHOR_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Text
-{
-
-struct Tag;
-struct Anchor;
-
-/**
- * @brief Retrieves the @e anchor from the @p tag.
- *
- * @param[in] tag The anchor tag and its attributes.
- * @param[in,out] anchor The anchor.
- */
-void ProcessAnchor( const Tag& tag, Anchor& anchor );
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ANCHOR_H
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-
-// EXTERNAL INCLUDES
-#include <memory.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void CopyAttributeValueFromBuffer(const Attribute& attribute, const Length maxLengthAttributeValue, char* value)
-{
- const Length length = attribute.valueLength > maxLengthAttributeValue ? maxLengthAttributeValue : attribute.valueLength;
- memcpy(value, attribute.valueBuffer, length);
- value[length] = 0;
-}
-
-float ProcessFloatAttribute(const Attribute& attribute)
-{
- return StringToFloat(attribute.valueBuffer);
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-definitions.h>
-
-// EXTERNAL INCLUDES
-#include <functional>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Attribute;
-
-/**
- * @brief Copy the value from attribute buffer to value.
- *
- * @param[in] attribute the value of attribute.
- * @param[in] maxLengthAttributeValue the maximum length of any of the possible value for attribute
- * @param[out] value the value container.
- *
- */
-void CopyAttributeValueFromBuffer(const Attribute& attribute, const Length maxLengthAttributeValue, char* value);
-
-/**
- * @brief Process the float attribute value from buffer.
- *
- * @param[in] attribute the float attribute.
- *
- * @return The float value.
- */
-float ProcessFloatAttribute(const Attribute& attribute);
-
-/**
- * @brief Process the Enumeration attribute value from buffer.
- *
- * @param[in] attribute the Enumeration attribute.
- * @param[in] maxLengthAttributeValue the maximum length of any of the possible value for attribute
- * @param[in] funcStringToEnum the function converts string value to enum value
- * @param[out] enumValue the enum value
- *
- * @return True if the enum value was processed successfully
- *
- */
-template<typename T>
-bool ProcessEnumerationAttribute(const Attribute& attribute,
- const Length maxLengthAttributeValue,
- std::function<T(const char* const)> funcStringToEnum,
- T& enumValue)
-{
- char* value = new char[maxLengthAttributeValue + 1u];
-
- CopyAttributeValueFromBuffer(attribute, maxLengthAttributeValue, value);
-
- enumValue = funcStringToEnum(value); // @TODO: the functions that process Enum value should be refactored to return bool from Scripting::GetEnumeration
-
- delete[] value;
-
- return true;
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-background.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-#include <memory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/color-run.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessBackground(const Tag& tag, ColorRun& colorRun)
-{
- for(auto&& attribute : tag.attributes)
- {
- if(TokenComparison(MARKUP::BACKGROUND_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
\ No newline at end of file
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct ColorRun;
-
-/**
- * @brief Retrieves the @e background from the @p tag.
- *
- * @param[in] tag The background tag and its attributes.
- * @param[in,out] colorRun The color run to be filled.
- */
-void ProcessBackground(const Tag& tag, ColorRun& colorRun);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-character-spacing.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/character-spacing-character-run.h>
-#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
-{
- characterSpacingCharacterRun.value = ProcessFloatAttribute(attribute);
-}
-
-void ProcessCharacterSpacingTag(const Tag& tag, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
-{
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
-
- if(TokenComparison(MARKUP::CHARACTER_SPACING_ATTRIBUTES::VALUE, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessValueAttribute(attribute, characterSpacingCharacterRun);
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct Attribute;
-struct CharacterSpacingCharacterRun;
-
-/**
- * @brief Fill the character-spacing character run with the value (space or advance) attribute.
- *
- * @param[in] attribute the value attribute.
- * @param[out] characterSpacingCharacterRun The underlined character run
- */
-void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun);
-
-/**
- * @brief Retrieves the character-spacing run info from the tag and sets it to the character-spacing run.
- *
- * @param[in] tag The character-spacing tag and its attributes.
- * @param[in,out] characterSpacingCharacterRun The character-spacing character run
- */
-void ProcessCharacterSpacingTag(const Tag& tag, CharacterSpacingCharacterRun& characterSpacingCharacterRun);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-color.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/color-run.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessColor(const Attribute& attribute, ColorRun& colorRun)
-{
- ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
-}
-
-void ProcessColorTag(const Tag& tag, ColorRun& colorRun)
-{
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
- if(TokenComparison(MARKUP::COLOR_ATTRIBUTES::VALUE, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessColor(attribute, colorRun);
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct Attribute;
-struct ColorRun;
-
-/**
- * @brief Retrieves the color value from the tag and sets it to the color run.
- *
- * @param[in] attribute the color attribute.
- * @param[in,out] colorRun The color run.
- */
-void ProcessColor(const Attribute& attribute, ColorRun& colorRun);
-
-/**
- * @brief Retrieves the color value from the tag and sets it to the color run.
- *
- * @param[in] tag The color tag and its attributes.
- * @param[in,out] colorRun The color run.
- */
-void ProcessColorTag(const Tag& tag, ColorRun& colorRun);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-#include <memory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/embedded-item.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-namespace
-{
-const std::string NONE("none");
-const std::string MULTIPLY("multiply");
-} // namespace
-
-void ProcessEmbeddedItem(const Tag& tag, EmbeddedItem& embeddedItem)
-{
- embeddedItem.url = nullptr;
- embeddedItem.urlLength = 0u;
- embeddedItem.width = 0u;
- embeddedItem.height = 0u;
- embeddedItem.colorBlendingMode = ColorBlendingMode::NONE;
-
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
- if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::URL, attribute.nameBuffer, attribute.nameLength))
- {
- embeddedItem.urlLength = attribute.valueLength;
- embeddedItem.url = new char[embeddedItem.urlLength];
- memcpy(embeddedItem.url, attribute.valueBuffer, embeddedItem.urlLength);
- // The memory is freed when the font run is removed from the logical model.
- }
- else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::WIDTH, attribute.nameBuffer, attribute.nameLength))
- {
- embeddedItem.width = StringToUint(attribute.valueBuffer);
- }
- else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- embeddedItem.height = StringToUint(attribute.valueBuffer);
- }
- else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::COLOR_BLENDING, attribute.nameBuffer, attribute.nameLength))
- {
- if(TokenComparison(MULTIPLY, attribute.valueBuffer, attribute.valueLength))
- {
- embeddedItem.colorBlendingMode = ColorBlendingMode::MULTIPLY;
- }
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct EmbeddedItem;
-
-/**
- * @brief Retrieves the @e embedded @e item from the @p tag.
- *
- * @param[in] tag The embedded item tag and its attributes.
- * @param[in,out] embeddedItem The embedded item.
- */
-void ProcessEmbeddedItem(const Tag& tag, EmbeddedItem& embeddedItem);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-font.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-#include <memory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/font-description-run.h>
-#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-#include <dali-toolkit/internal/text/text-font-style.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-namespace
-{
-const std::string FONT_PREFIX("font-");
-const unsigned int FONT_PREFIX_LENGTH = 5u;
-const unsigned int MIN_FONT_ATTRIBUTE_SIZE = 4u; ///< The minimum length of any of the possible 'weight', 'width' , 'slant' or 'size' values.
-const unsigned int MAX_FONT_ATTRIBUTE_SIZE = 15u; ///< The maximum length of any of the possible 'weight', 'width' or 'slant' values.
-const float PIXEL_FORMAT_64_FACTOR = 64.f; ///< 64.f is used to convert from point size to 26.6 pixel format.
-} // namespace
-
-void processFontAttributeValue(char value[], const Attribute& attribute)
-{
- // The StringToWeight() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
- const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
- memcpy(value, attribute.valueBuffer, length);
- value[length] = 0;
-}
-
-void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun)
-{
- fontRun.familyDefined = true;
- fontRun.familyLength = attribute.valueLength;
- fontRun.familyName = new char[fontRun.familyLength];
- memcpy(fontRun.familyName, attribute.valueBuffer, fontRun.familyLength);
- // The memory is freed when the font run is removed from the logical model.
-}
-
-void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun)
-{
- // 64.f is used to convert from point size to 26.6 pixel format.
- fontRun.size = static_cast<PointSize26Dot6>(ProcessFloatAttribute(attribute) * PIXEL_FORMAT_64_FACTOR);
- fontRun.sizeDefined = true;
-}
-
-void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun)
-{
- fontRun.weightDefined = ProcessEnumerationAttribute<FontWeight>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToWeight, fontRun.weight);
-}
-
-void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun)
-{
- fontRun.widthDefined = ProcessEnumerationAttribute<FontWidth>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToWidth, fontRun.width);
-}
-
-void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun)
-{
- fontRun.slantDefined = ProcessEnumerationAttribute<FontSlant>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToSlant, fontRun.slant);
-}
-
-void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun)
-{
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
-
- if(TokenComparison(MARKUP::FONT_ATTRIBUTES::FAMILY, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessFontFamily(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::SIZE, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessFontSize(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::WEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessFontWeight(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::WIDTH, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessFontWidth(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::SLANT, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessFontSlant(attribute, fontRun);
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct Attribute;
-struct FontDescriptionRun;
-
-/**
- * @brief Retrieves the font attributes from the tag and sets it to the font run.
- *
- * @param[in] tag The font tag and its attributes.
- * @param[in,out] fontRun The font description run.
- */
-void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun);
-
-/**
- * @brief Fill the font run with the font slant attribute value.
- *
- * @param[in] attribute the font slant attribute.
- * @param[out] fontRun The font description run.
- */
-void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun);
-
-/**
- * @brief Fill the font run with the font width attribute value.
- *
- * @param[in] attribute the font width attribute.
- * @param[out] fontRun The font description run.
- */
-void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun);
-
-/**
- * @brief Fill the font run with the font weight attribute value.
- *
- * @param[in] attribute the font weight attribute.
- * @param[out] fontRun The font description run.
- */
-void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun);
-
-/**
- * @brief Fill the font run with the font size attribute value.
- *
- * @param[in] attribute the font size attribute.
- * @param[out] fontRun The font description run.
- */
-void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun);
-
-/**
- * @brief Fill the font run with the font family attribute value.
- *
- * @param[in] attribute the font family attribute.
- * @param[out] fontRun The font description run.
- */
-void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/constants.h>
-#include <dali/public-api/math/vector2.h>
-#include <stdlib.h>
-#include <iomanip>
-#include <sstream>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-namespace
-{
-const char WHITE_SPACE = 0x20; // ASCII value of the white space.
-const char FIRST_UPPER_CASE = 0x41; // ASCII value of the one after the first upper case character (A).
-const char LAST_UPPER_CASE = 0x5b; // ASCII value of the one after the last upper case character (Z).
-const char TO_LOWER_CASE = 32; // Value to add to a upper case character to transform it into a lower case.
-
-const unsigned int MAX_FLOAT_ATTRIBUTE_SIZE = 17u; ///< The maximum length of any of the possible float values. +99999.999999999f (sign, five digits, dot, nine digits, f)
-
-const char WEB_COLOR_TOKEN('#');
-const char* const HEX_COLOR_TOKEN("0x");
-const char* const ALPHA_ONE("FF");
-
-const std::string BLACK_COLOR("black");
-const std::string WHITE_COLOR("white");
-const std::string RED_COLOR("red");
-const std::string GREEN_COLOR("green");
-const std::string BLUE_COLOR("blue");
-const std::string YELLOW_COLOR("yellow");
-const std::string MAGENTA_COLOR("magenta");
-const std::string CYAN_COLOR("cyan");
-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)
-{
- const Length stringSize = string1.size();
- if(stringSize != length)
- {
- // Early return. Strings have different sizes.
- return false;
- }
-
- const char* const stringBuffer1 = string1.c_str();
-
- for(std::size_t index = 0; index < stringSize; ++index)
- {
- const char character = *(stringBuffer2 + index);
- const bool toLower = (character < LAST_UPPER_CASE) && (character >= FIRST_UPPER_CASE);
- if(*(stringBuffer1 + index) != (toLower ? character + TO_LOWER_CASE : character))
- {
- return false;
- }
- }
-
- return true;
-}
-
-void SkipWhiteSpace(const char*& stringBuffer,
- const char* const stringEndBuffer)
-{
- for(; (WHITE_SPACE >= *stringBuffer) && (stringBuffer < stringEndBuffer); ++stringBuffer)
- ;
-}
-
-void JumpToWhiteSpace(const char*& stringBuffer,
- const char* const stringEndBuffer)
-{
- for(; (WHITE_SPACE != *stringBuffer) && (stringBuffer < stringEndBuffer); ++stringBuffer)
- ;
-}
-
-unsigned int StringToUint(const char* const uintStr)
-{
- return static_cast<unsigned int>(strtoul(uintStr, NULL, 10));
-}
-
-unsigned int StringToHex(const char* const uintStr)
-{
- return static_cast<unsigned int>(strtoul(uintStr, NULL, 16));
-}
-
-float StringToFloat(const char* const floatStr)
-{
- return static_cast<float>(strtod(floatStr, NULL));
-}
-
-void FloatToString(float value, std::string& floatStr)
-{
- std::stringstream ss;
- ss << value;
- floatStr = ss.str();
-}
-
-void UintToString(unsigned int value, std::string& uIntStr)
-{
- std::stringstream ss;
- ss << value;
- uIntStr = ss.str();
-}
-
-void UintColorToVector4(unsigned int color, Vector4& retColor)
-{
- retColor.a = static_cast<float>((color & 0xFF000000) >> 24u) / 255.f;
- retColor.r = static_cast<float>((color & 0x00FF0000) >> 16u) / 255.f;
- retColor.g = static_cast<float>((color & 0x0000FF00) >> 8u) / 255.f;
- retColor.b = static_cast<float>(color & 0x000000FF) / 255.f;
-}
-
-void ColorStringToVector4(const char* const colorStr, Length length, Vector4& retColor)
-{
- if(WEB_COLOR_TOKEN == *colorStr)
- {
- std::string webColor(colorStr + 1u, length - 1u);
- if(4u == length) // 3 component web color #F00 (red)
- {
- webColor.insert(2u, &(webColor[2]), 1u);
- webColor.insert(1u, &(webColor[1]), 1u);
- webColor.insert(0u, &(webColor[0]), 1u);
- webColor.insert(0u, ALPHA_ONE);
- }
- else if(7u == length) // 6 component web color #FF0000 (red)
- {
- webColor.insert(0u, ALPHA_ONE);
- }
-
- UintColorToVector4(StringToHex(webColor.c_str()), retColor);
- }
- else if(TokenComparison(HEX_COLOR_TOKEN, colorStr, 2u))
- {
- UintColorToVector4(StringToHex(colorStr + 2u), retColor);
- }
- else if(TokenComparison(BLACK_COLOR, colorStr, length))
- {
- retColor = Color::BLACK;
- }
- else if(TokenComparison(WHITE_COLOR, colorStr, length))
- {
- retColor = Color::WHITE;
- }
- else if(TokenComparison(RED_COLOR, colorStr, length))
- {
- retColor = Color::RED;
- }
- else if(TokenComparison(GREEN_COLOR, colorStr, length))
- {
- retColor = Color::GREEN;
- }
- else if(TokenComparison(BLUE_COLOR, colorStr, length))
- {
- retColor = Color::BLUE;
- }
- else if(TokenComparison(YELLOW_COLOR, colorStr, length))
- {
- retColor = Color::YELLOW;
- }
- else if(TokenComparison(MAGENTA_COLOR, colorStr, length))
- {
- retColor = Color::MAGENTA;
- }
- else if(TokenComparison(CYAN_COLOR, colorStr, length))
- {
- retColor = Color::CYAN;
- }
- else if(TokenComparison(TRANSPARENT_COLOR, colorStr, length))
- {
- retColor = Color::TRANSPARENT;
- }
-}
-
-void Vector4ToColorString(const Vector4& value, std::string& vector2Str)
-{
- if(Color::BLACK == value)
- {
- vector2Str = BLACK_COLOR;
- return;
- }
-
- if(Color::WHITE == value)
- {
- vector2Str = WHITE_COLOR;
- return;
- }
-
- if(Color::RED == value)
- {
- vector2Str = RED_COLOR;
- return;
- }
-
- if(Color::GREEN == value)
- {
- vector2Str = GREEN_COLOR;
- return;
- }
-
- if(Color::BLUE == value)
- {
- vector2Str = BLUE_COLOR;
- return;
- }
-
- if(Color::YELLOW == value)
- {
- vector2Str = YELLOW_COLOR;
- return;
- }
-
- if(Color::MAGENTA == value)
- {
- vector2Str = MAGENTA_COLOR;
- return;
- }
-
- if(Color::CYAN == value)
- {
- vector2Str = CYAN_COLOR;
- return;
- }
-
- if(Color::TRANSPARENT == value)
- {
- vector2Str = TRANSPARENT_COLOR;
- return;
- }
-
- const unsigned int alpha = static_cast<unsigned int>(255.f * value.a);
- const unsigned int red = static_cast<unsigned int>(255.f * value.r);
- const unsigned int green = static_cast<unsigned int>(255.f * value.g);
- const unsigned int blue = static_cast<unsigned int>(255.f * value.b);
-
- std::stringstream ss;
- const unsigned int size = 2u * sizeof(unsigned char);
-
- ss << "0x"
- << std::setfill('0') << std::setw(size)
- << std::hex << alpha
- << std::setfill('0') << std::setw(size)
- << std::hex << red
- << std::setfill('0') << std::setw(size)
- << std::hex << green
- << std::setfill('0') << std::setw(size)
- << std::hex << blue;
- vector2Str = ss.str();
-}
-
-void StringToVector2(const char* const vectorStr, Length length, Vector2& vector2)
-{
- // Points to the first character of the string.
- const char* strBuffer = vectorStr;
-
- // Points to the first character of the 'x' value.
- const char* const xBuffer = strBuffer;
-
- // Jumps to the next white space.
- JumpToWhiteSpace(strBuffer, strBuffer + length);
-
- // Points to the first character of the 'y' value.
- const char* const yBuffer = strBuffer;
-
- // Converts the shadow's offset to float.
- vector2.x = StringToFloat(xBuffer);
- vector2.y = StringToFloat(yBuffer);
-}
-
-void Vector2ToString(const Vector2& value, std::string& vector2Str)
-{
- FloatToString(value.x, vector2Str);
- vector2Str += " ";
-
- std::string yStr;
- FloatToString(value.y, yStr);
-
- vector2Str += yStr;
-}
-
-void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Text::Underline::Type& retType)
-{
- if(TokenComparison(SOLID_UNDERLINE, typeStr, length))
- {
- retType = Text::Underline::SOLID;
- }
- else if(TokenComparison(DASHED_UNDERLINE, typeStr, length))
- {
- retType = Text::Underline::DASHED;
- }
- else if(TokenComparison(DOUBLE_UNDERLINE, typeStr, length))
- {
- retType = Text::Underline::DOUBLE;
- }
-}
-
-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
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-definitions.h>
-#include <dali-toolkit/public-api/text/text-enumerations.h>
-
-namespace Dali
-{
-struct Vector2;
-struct Vector4;
-
-namespace Toolkit
-{
-namespace Text
-{
-/**
- * @brief Stores an attribute pair: name, value.
- */
-struct Attribute
-{
- const char* nameBuffer;
- const char* valueBuffer;
- Length nameLength;
- Length valueLength;
-};
-
-/**
- * @brief Stores a tag and its attributes.
- */
-struct Tag
-{
- Vector<Attribute> attributes;
- const char* buffer;
- Length length;
- bool isEndTag;
-};
-
-/**
- * @brief Compare if two tokens are equal.
- *
- * @pre @p string1 must be lower case. (The html-ish constant tokens)
- * The @p stringBuffer2 parameter is transformed to lower case.
- * This function is used in the mark-up parser.
- * It has no sense to transform the constants html-ish tokens to lower case when
- * it's known they already are.
- *
- * @param[in] string1 The html-ish constant token.
- * @param[in] stringBuffer2 Pointer to the html-ish token buffer.
- * @param[in] length The length of the html-ish token.
- *
- * @return @e true if both strings are equal.
- */
-bool TokenComparison(const std::string& string1, const char* const stringBuffer2, Length length);
-
-/**
- * @brief Skips any unnecessary white space.
- *
- * @param[in,out] stringBuffer The string buffer. It's a const iterator pointing the current character.
- * @param[in] stringEndBuffer Pointer to one character after the end of the string buffer.
- */
-void SkipWhiteSpace(const char*& stringBuffer,
- const char* const stringEndBuffer);
-
-/**
- * @Brief Jumps to the next white space.
- *
- * @param[in,out] stringBuffer The string buffer. It's a const iterator pointing the current character.
- * @param[in] stringEndBuffer Pointer to one character after the end of the string buffer.
- */
-void JumpToWhiteSpace(const char*& stringBuffer,
- const char* const stringEndBuffer);
-
-/**
-* @brief Converts a string into an unsigned int.
-*
-* @param[in] uintStr An unsigned int packed inside a string.
-*
-* @return The unsigned int value.
-*/
-unsigned int StringToUint(const char* const uintStr);
-
-/**
- * @brief Converts a string into an hexadecimal unsigned int.
- *
- * @param[in] uintStr An hexadecimal unsigned int packed inside a string.
- *
- * @return The hexadecimal value.
- */
-unsigned int StringToHex(const char* const uintStr);
-
-/**
- * @brief Converts a string into a float value.
- *
- * @param[in] floatStr A float packed inside a string.
- *
- * @return The float value.
- */
-float StringToFloat(const char* const floatStr);
-
-/**
- * @brief Converts a float into a string.
- *
- * @param[in] value The float value.
- * @param[out] floatStr The string.
- */
-void FloatToString(float value, std::string& floatStr);
-
-/**
- * @brief Converts an unsigned int into a string.
- *
- * @param[in] value The unsigned int value.
- * @param[out] uIntStr The string.
- */
-void UintToString(unsigned int value, std::string& uIntStr);
-
-/**
- * @brief Converts an ARGB color packed in 4 byte unsigned int into a Vector4 color used in Dali.
- *
- * @param[in] color An ARGB color packed in an unsigned int.
- * @param[out] retColor A Vector4 with the converted color.
- */
-void UintColorToVector4(unsigned int color, Vector4& retColor);
-
-/**
- * @brief Converts a color packed inside a string into an ARGB Vector4 color.
- *
- * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values:
- * black, white, red, green, blue, yellow, magenta, cyan or transparent.
- *
- * @param[in] colorStr A color packed inside a string.
- * @param[in] length The length of the color string.
- * @param[out] retColor A color packed inside a Vector4.
- */
-void ColorStringToVector4(const char* const colorStr, Length length, Vector4& retColor);
-
-/**
- * @brief Converts a color packed in a Vector4 into a string.
- *
- * Constant colors will be converted to the strings black, white, red, green, blue, yellow, magenta, cyan or transparent.
- *
- * If is not a constant color it will be converted to a string with hexadecimal ARGB content.
- *
- * @param[in] value The color value.
- * @param[out] colorStr The string.
- */
-void Vector4ToColorString(const Vector4& value, std::string& vector2Str);
-
-/**
- * @brief Converts a two dimension vector packed inside a string into a Vector2.
- *
- * @param[in] vectorStr The two dimension vector packed inside a string.
- * @param[in] length The length of the string.
- * @param[out] vector2 The Vector2.
- */
-void StringToVector2(const char* const vectorStr, Length length, Vector2& vector2);
-
-/**
- * @brief Converts a Vector2 into a string.
- *
- * @param[in] value The vector2 value.
- * @param[out] vector2Str The string.
- */
-void Vector2ToString(const Vector2& value, std::string& vector2Str);
-
-/**
- * @brief Converts a string into its value in the enum Text::Underline::Type.
- *
- * @param[in] typeStr The underline type value packed inside a string.
- * @param[in] length The length of the string.
- * @param[out] retType The Underline type.
- */
-void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Text::Underline::Type& retType);
-
-/**
- * @brief Converts a string into a float value.
- *
- * @param[in] floatStr A float packed inside a string.
- *
- * @return The float value.
- */
-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
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-paragraph.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/bounded-paragraph-run.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessHorizontalAlignment(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
-{
- boundedParagraphRun.horizontalAlignmentDefined = HorizontalAlignmentTypeStringToTypeValue(attribute.valueBuffer,
- attribute.valueLength,
- boundedParagraphRun.horizontalAlignment);
-}
-
-void ProcessRelativeLineHeight(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
-{
- boundedParagraphRun.relativeLineSize = StringToFloat(attribute.valueBuffer);
- boundedParagraphRun.relativeLineSizeDefined = true;
-}
-
-void ProcessAttributesOfParagraphTag(const Tag& tag, BoundedParagraphRun& boundedParagraphRun)
-{
- // By default the align attribute is not defined until it's parsed.
- boundedParagraphRun.horizontalAlignmentDefined = false;
-
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
- if(TokenComparison(MARKUP::PARAGRAPH_ATTRIBUTES::ALIGN, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessHorizontalAlignment(attribute, boundedParagraphRun);
- }
- else if(TokenComparison(MARKUP::PARAGRAPH_ATTRIBUTES::RELATIVE_LINE_HEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessRelativeLineHeight(attribute, boundedParagraphRun);
- }
- }
-}
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#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);
-
-/**
- * @brief Retrieves the relative line height value from the paragraph tag and sets it to the bounded paragraph run.
- *
- * @param[in] attribute the relative line height attribute.
- * @param[in,out] boundedParagraphRun The bounded paragraph run.
- */
-void ProcessRelativeLineHeight(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_PARAGRAPH_H
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-color.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/color-run.h>
-#include <dali-toolkit/internal/text/font-description-run.h>
-#include <dali-toolkit/internal/text/markup-processor-character-spacing.h>
-#include <dali-toolkit/internal/text/markup-processor-font.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
-#include <dali-toolkit/internal/text/markup-processor-underline.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessSpanTag(const Tag& tag,
- ColorRun& colorRun,
- FontDescriptionRun& fontRun,
- UnderlinedCharacterRun& underlinedCharacterRun,
- ColorRun& backgroundColorRun,
- StrikethroughCharacterRun& strikethroughRun,
- CharacterSpacingCharacterRun& characterSpacingCharacterRun,
- bool& isColorDefined,
- bool& isFontDefined,
- bool& isUnderlinedCharacterDefined,
- bool& isBackgroundColorDefined,
- bool& isStrikethroughDefined,
- bool& isCharacterSpacingDefined)
-{
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
-
- if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::TEXT_COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- isColorDefined = true;
- ProcessColor(attribute, colorRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::BACKGROUND_COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- isBackgroundColorDefined = true;
- ProcessColor(attribute, backgroundColorRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_FAMILY, attribute.nameBuffer, attribute.nameLength))
- {
- isFontDefined = true;
- ProcessFontFamily(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_SIZE, attribute.nameBuffer, attribute.nameLength))
- {
- isFontDefined = true;
- ProcessFontSize(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_WEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- isFontDefined = true;
- ProcessFontWeight(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_WIDTH, attribute.nameBuffer, attribute.nameLength))
- {
- isFontDefined = true;
- ProcessFontWidth(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_SLANT, attribute.nameBuffer, attribute.nameLength))
- {
- isFontDefined = true;
- ProcessFontSlant(attribute, fontRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- isUnderlinedCharacterDefined = true;
- ProcessColorAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_HEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- isUnderlinedCharacterDefined = true;
- ProcessHeightAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_TYPE, attribute.nameBuffer, attribute.nameLength))
- {
- isUnderlinedCharacterDefined = true;
- ProcessTypeAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_DASH_GAP, attribute.nameBuffer, attribute.nameLength))
- {
- isUnderlinedCharacterDefined = true;
- ProcessDashGapAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_DASH_WIDTH, attribute.nameBuffer, attribute.nameLength))
- {
- isUnderlinedCharacterDefined = true;
- ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::STRIKETHROUGH_COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- isStrikethroughDefined = true;
- ProcessColorAttribute(attribute, strikethroughRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::STRIKETHROUGH_HEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- isStrikethroughDefined = true;
- ProcessHeightAttribute(attribute, strikethroughRun);
- }
- else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::CHARACTER_SPACING_VALUE, attribute.nameBuffer, attribute.nameLength))
- {
- isCharacterSpacingDefined = true;
- ProcessValueAttribute(attribute, characterSpacingCharacterRun);
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_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 MarkupProcessData;
-
-/**
- * @brief process the span from the tag and process all styles in it.
- *
- * @param[in] tag The span tag and its attributes.
- * @param[out] colorRun the color run to be filled.
- * @param[out] fontRun the font run to be filled.
- * @param[out] underlinedCharacterRun the underlined character run to be filled.
- * @param[out] backgroundColorRun the background color run to be filled.
- * @param[out] strikethroughRun the strikethrough run to be filled.
- * @param[out] characterSpacingCharacterRun the character-spacing run to be filled.
- * @param[out] isColorDefined if the span has color defined.
- * @param[out] isFontDefined if the span has font defined.
- * @param[out] isUnderlinedCharacterDefined if the span has underlined-character defined.
- * @param[out] isBackgroundColorDefined if the span has background color defined.
- * @param[out] isStrikethroughDefined if the span has strikethrough defined.
- * @param[out] isCharacterSpacingDefined if the span has character-spacing defined.
- */
-void ProcessSpanTag(const Tag& tag,
- ColorRun& colorRun,
- FontDescriptionRun& fontRun,
- UnderlinedCharacterRun& underlinedCharacterRun,
- ColorRun& backgroundColorRun,
- StrikethroughCharacterRun& strikethroughRun,
- CharacterSpacingCharacterRun& characterSpacingCharacterRun,
- bool& isColorDefined,
- bool& isFontDefined,
- bool& isUnderlinedCharacterDefined,
- bool& isBackgroundColorDefined,
- bool& isStrikethroughDefined,
- bool& isCharacterSpacingDefined);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-#include <dali-toolkit/internal/text/strikethrough-character-run.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
-
-{
- ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, strikethroughRun.properties.color);
- strikethroughRun.properties.colorDefined = true;
-}
-
-void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
-{
- strikethroughRun.properties.height = ProcessFloatAttribute(attribute);
- strikethroughRun.properties.heightDefined = true;
-}
-
-void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun)
-{
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
-
- if(TokenComparison(MARKUP::STRIKETHROUGH_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessColorAttribute(attribute, strikethroughRun);
- }
- else if(TokenComparison(MARKUP::STRIKETHROUGH_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessHeightAttribute(attribute, strikethroughRun);
- }
- }
-}
-
-void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns)
-{
- // Handle nested tags
- // The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag.
- // Example:
- // <s height='5.0f' color='blue'> outer tag before <s color='green'> inner tag </s> outer tag after </s>
- // "outer tag before" and "outer tag after" have height = 5.0f and color = 'blue'
- // "inner tag" has height = 5.0f and color = 'green'
-
- if(strikethroughCharacterRuns.Count() > 0u)
- {
- Vector<StrikethroughCharacterRun>::ConstIterator preIt = strikethroughCharacterRuns.Begin();
-
- Vector<StrikethroughCharacterRun>::Iterator it = strikethroughCharacterRuns.Begin() + 1;
- Vector<StrikethroughCharacterRun>::ConstIterator endIt = strikethroughCharacterRuns.End();
-
- while(it != endIt)
- {
- const StrikethroughCharacterRun& run = *it;
- const CharacterIndex& characterIndex = run.characterRun.characterIndex;
- const Length& numberOfCharacters = run.characterRun.numberOfCharacters;
-
- const StrikethroughCharacterRun& preRun = *preIt;
- const CharacterIndex& preCharacterIndex = preRun.characterRun.characterIndex;
- const Length& preNumberOfCharacters = preRun.characterRun.numberOfCharacters;
-
- if((preCharacterIndex <= characterIndex) &&
- ((characterIndex + numberOfCharacters) <= (preCharacterIndex + preNumberOfCharacters)))
- {
- it->properties.CopyIfNotDefined(preIt->properties);
- }
-
- it++;
- preIt++;
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_STRIKETHROUGH_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_STRIKETHROUGH_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/strikethrough-character-run.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct Attribute;
-struct StrikethroughCharacterRun;
-
-/**
- * @brief Fill the strikethrough character run with the color attribute value.
- *
- * @param[in] attribute the color attribute.
- * @param[out] strikethroughCharacterRun The strikethrough character run
- */
-void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughCharacterRun);
-
-/**
- * @brief Fill the strikethrough character run with the height attribute value.
- *
- * @param[in] attribute the height attribute.
- * @param[out] strikethroughRun The strikethrough character run
- */
-void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun);
-
-/**
- * @brief Retrieves the strikethrough run info from the tag and sets it to the strikethrough run.
- *
- * @param[in] tag The strikethrough tag and its attributes.
- * @param[in,out] strikethroughRun The strikethrough run.
- */
-void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun);
-
-/**
- * @brief Override the run's attributes which contained in the previous run. This is to handle the nested tags.
- *
- * @param[in,out] strikethroughCharacterRun The list of strikethrough character run
- */
-void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRun);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_STRIKETHROUGH_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor-underline.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-#include <dali-toolkit/internal/text/text-effects-style.h>
-#include <dali-toolkit/internal/text/underlined-character-run.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-namespace
-{
-const unsigned int MAX_TYPE_ATTRIBUTE_SIZE = 7u; ///< The maximum length of any of the possible 'type' values.
-
-} // namespace
-
-void ProcessTypeAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
-{
- underlinedCharacterRun.properties.typeDefined = ProcessEnumerationAttribute<Text::Underline::Type>(attribute,
- MAX_TYPE_ATTRIBUTE_SIZE,
- &StringToUnderlineType,
- underlinedCharacterRun.properties.type);
-}
-
-void ProcessDashGapAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
-{
- underlinedCharacterRun.properties.dashGap = ProcessFloatAttribute(attribute);
- underlinedCharacterRun.properties.dashGapDefined = true;
-}
-
-void ProcessDashWidthAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
-{
- underlinedCharacterRun.properties.dashWidth = ProcessFloatAttribute(attribute);
- underlinedCharacterRun.properties.dashWidthDefined = true;
-}
-void ProcessHeightAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
-{
- underlinedCharacterRun.properties.height = ProcessFloatAttribute(attribute);
- underlinedCharacterRun.properties.heightDefined = true;
-}
-
-void ProcessColorAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
-{
- ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, underlinedCharacterRun.properties.color);
- underlinedCharacterRun.properties.colorDefined = true;
-}
-
-void ProcessUnderlineTag(const Tag& tag, UnderlinedCharacterRun& underlinedCharacterRun)
-{
- for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
- endIt = tag.attributes.End();
- it != endIt;
- ++it)
- {
- const Attribute& attribute(*it);
-
- if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessColorAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessHeightAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::TYPE, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessTypeAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::DASH_GAP, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessDashGapAttribute(attribute, underlinedCharacterRun);
- }
- else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::DASH_WIDTH, attribute.nameBuffer, attribute.nameLength))
- {
- ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
- }
- }
-}
-
-void OverrideNestedUnderlinedCharacterRuns(Vector<UnderlinedCharacterRun>& underlinedCharacterRuns)
-{
- // Handle nested tags
- // The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag.
- // Example:
- // <u height='5.0f' color='blue'> outer tag before <u color='green'> inner tag </u> outer tag after </u>
- // "outer tag before" and "outer tag after" have height = 5.0f and color = 'blue'
- // "inner tag" has height = 5.0f and color = 'green'
-
- if(underlinedCharacterRuns.Count() > 0u)
- {
- Vector<UnderlinedCharacterRun>::ConstIterator preIt = underlinedCharacterRuns.Begin();
-
- Vector<UnderlinedCharacterRun>::Iterator it = underlinedCharacterRuns.Begin() + 1;
- Vector<UnderlinedCharacterRun>::ConstIterator endIt = underlinedCharacterRuns.End();
-
- while(it != endIt)
- {
- const UnderlinedCharacterRun& run = *it;
- const CharacterIndex& characterIndex = run.characterRun.characterIndex;
- const Length& numberOfCharacters = run.characterRun.numberOfCharacters;
-
- const UnderlinedCharacterRun& preRun = *preIt;
- const CharacterIndex& preCharacterIndex = preRun.characterRun.characterIndex;
- const Length& preNumberOfCharacters = preRun.characterRun.numberOfCharacters;
-
- if((preCharacterIndex <= characterIndex) &&
- ((characterIndex + numberOfCharacters) <= (preCharacterIndex + preNumberOfCharacters)))
- {
- it->properties.CopyIfNotDefined(preIt->properties);
- }
-
- it++;
- preIt++;
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/underlined-character-run.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Tag;
-struct Attribute;
-
-/**
- * @brief Fill the underlined character run with the type attribute value.
- *
- * @param[in] attribute the type attribute.
- * @param[out] underlinedCharacterRun The underlined character run
- */
-void ProcessTypeAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
-
-/**
- * @brief Fill the underlined character run with the dash-gap attribute value.
- *
- * @param[in] attribute the dash-gap attribute.
- * @param[out] underlinedCharacterRun The underlined character run
- */
-void ProcessDashGapAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
-
-/**
- * @brief Fill the underlined character run with the dash-width attribute value.
- *
- * @param[in] attribute the dash-width attribute.
- * @param[out] underlinedCharacterRun The underlined character run
- */
-void ProcessDashWidthAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
-
-/**
- * @brief Fill the underlined character run with the height attribute value.
- *
- * @param[in] attribute the height attribute.
- * @param[out] underlinedCharacterRun The underlined character run
- */
-void ProcessHeightAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
-
-/**
- * @brief Fill the underlined character run with the color attribute value.
- *
- * @param[in] attribute the color attribute.
- * @param[out] underlinedCharacterRun The underlined character run
- */
-void ProcessColorAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
-
-/**
- * @brief Retrieves the underline run info from the tag and sets it to the underline run.
- *
- * @param[in] tag The underline tag and its attributes.
- * @param[in,out] underlinedCharacterRun The underlined character run
- */
-void ProcessUnderlineTag(const Tag& tag, UnderlinedCharacterRun& underlinedCharacterRun);
-
-/**
- * @brief Override the run's attributes which contained in the previous run. This is to handle the nested tags.
- *
- * @param[in,out] underlinedCharacterRuns The list of underlined character run
- */
-void OverrideNestedUnderlinedCharacterRuns(Vector<UnderlinedCharacterRun>& underlinedCharacterRuns);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// FILE HEADER
-#include <dali-toolkit/internal/text/markup-processor.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <climits> // for ULONG_MAX
-#include <functional>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/markup-processor-anchor.h>
-#include <dali-toolkit/internal/text/markup-processor-background.h>
-#include <dali-toolkit/internal/text/markup-processor-character-spacing.h>
-#include <dali-toolkit/internal/text/markup-processor-color.h>
-#include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
-#include <dali-toolkit/internal/text/markup-processor-font.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
-#include <dali-toolkit/internal/text/markup-processor-paragraph.h>
-#include <dali-toolkit/internal/text/markup-processor-span.h>
-#include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
-#include <dali-toolkit/internal/text/markup-processor-underline.h>
-#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
-#include <dali-toolkit/internal/text/xhtml-entities.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-namespace
-{
-const char LESS_THAN = '<';
-const char GREATER_THAN = '>';
-const char EQUAL = '=';
-const char QUOTATION_MARK = '\'';
-const char SLASH = '/';
-const char BACK_SLASH = '\\';
-const char AMPERSAND = '&';
-const char HASH = '#';
-const char SEMI_COLON = ';';
-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
-// Range 3 0x10000u < XHTML_DECIMAL_ENTITY_RANGE <= 0x10FFFFu
-const unsigned long XHTML_DECIMAL_ENTITY_RANGE[] = {0x0u, 0xD7FFu, 0xE000u, 0xFFFDu, 0x10000u, 0x10FFFFu};
-
-// The MAX_NUM_OF_ATTRIBUTES is the number of attributes in span tag "markup-processor-span.cpp". Because it contains the maximum number of attributes in all tags.
-const unsigned int MAX_NUM_OF_ATTRIBUTES = 14u; ///< The span tag has the 'font-family', 'font-size' 'font-weight', 'font-width', 'font-slant','text-color', 'u-color', 'u-height','u-type','u-dash-gap', 'u-dash-width', 's-color', 's-height' and 'char-space-value' attrubutes.
-const unsigned int DEFAULT_VECTOR_SIZE = 16u; ///< Default size of run vectors.
-
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MARKUP_PROCESSOR");
-#endif
-
-typedef VectorBase::SizeType RunIndex;
-
-/**
- * @brief Struct used to retrieve the style runs from the mark-up string.
- */
-template<typename StyleStackType>
-struct StyleStack
-{
- Vector<StyleStackType> stack; ///< Use a vector as a style stack.
- unsigned int topIndex; ///< Points the top of the stack.
-
- StyleStack()
- : stack(),
- topIndex(0u)
- {
- stack.Resize(DEFAULT_VECTOR_SIZE);
- }
-
- void Push(StyleStackType item)
- {
- // Check if there is space inside the style stack.
- const VectorBase::SizeType size = stack.Count();
- if(topIndex >= size)
- {
- // Resize the style stack.
- stack.Resize(2u * size);
- }
-
- // Set the item in the top of the stack.
- *(stack.Begin() + topIndex) = item;
-
- // Reposition the pointer to the top of the stack.
- ++topIndex;
- }
-
- StyleStackType Pop()
- {
- // Pop the top of the stack.
- --topIndex;
- return *(stack.Begin() + topIndex);
- }
-};
-
-/**
- * @brief Struct used to retrieve spans from the mark-up string.
- */
-struct Span
-{
- RunIndex colorRunIndex;
- RunIndex fontRunIndex;
- RunIndex underlinedCharacterRunIndex;
- RunIndex backgroundColorRunIndex;
- RunIndex strikethroughCharacterRunIndex;
- RunIndex characterSpacingCharacterRunIndex;
-
- bool isColorDefined;
- bool isFontDefined;
- bool isUnderlinedCharacterDefined;
- bool isBackgroundColorDefined;
- bool isStrikethroughDefined;
- bool isCharacterSpacingDefined;
-};
-
-/**
- * @brief Initializes a font run description to its defaults.
- *
- * @param[in,out] fontRun The font description run to initialize.
- */
-void Initialize(FontDescriptionRun& fontRun)
-{
- fontRun.characterRun.characterIndex = 0u;
- fontRun.characterRun.numberOfCharacters = 0u;
- fontRun.familyName = NULL;
- fontRun.familyLength = 0u;
- fontRun.weight = TextAbstraction::FontWeight::NORMAL;
- fontRun.width = TextAbstraction::FontWidth::NORMAL;
- fontRun.slant = TextAbstraction::FontSlant::NORMAL;
- fontRun.size = 0u;
- fontRun.familyDefined = false;
- fontRun.weightDefined = false;
- fontRun.widthDefined = false;
- fontRun.slantDefined = false;
- fontRun.sizeDefined = false;
-}
-
-/**
- * @brief Initializes a color run description to its defaults.
- *
- * @param[in,out] colorRun The font description run to initialize.
- */
-void Initialize(ColorRun& colorRun)
-{
- colorRun.characterRun.characterIndex = 0u;
- colorRun.characterRun.numberOfCharacters = 0u;
-}
-
-/**
- * @brief Initializes a underlined character run to its defaults.
- *
- * @param[in,out] underlinedCharacterRun The underelined character run to initialize.
- */
-void Initialize(UnderlinedCharacterRun& underlinedCharacterRun)
-{
- underlinedCharacterRun.characterRun.characterIndex = 0u;
- underlinedCharacterRun.characterRun.numberOfCharacters = 0u;
-}
-
-/**
- * @brief Initializes a span to its defaults.
- *
- * @param[in,out] span The span to be initialized.
- */
-void Initialize(Span& span)
-{
- span.colorRunIndex = 0u;
- span.isColorDefined = false;
-
- span.fontRunIndex = 0u;
- span.isFontDefined = false;
-
- span.underlinedCharacterRunIndex = 0u;
- span.isUnderlinedCharacterDefined = false;
- span.backgroundColorRunIndex = 0u;
- span.isBackgroundColorDefined = false;
-
- //strikethrough
- span.strikethroughCharacterRunIndex = 0u;
- span.isStrikethroughDefined = false;
-
- //characterSpacing
- span.characterSpacingCharacterRunIndex = 0u;
- span.isCharacterSpacingDefined = false;
-}
-
-/**
- * @brief Initializes a strikethrough character run to its defaults.
- *
- * @param[in,out] strikethroughCharacterRun The strikethrough character run to initialize.
- */
-void Initialize(StrikethroughCharacterRun& strikethroughCharacterRun)
-{
- strikethroughCharacterRun.characterRun.characterIndex = 0u;
- strikethroughCharacterRun.characterRun.numberOfCharacters = 0u;
- strikethroughCharacterRun.properties.colorDefined = false;
-}
-
-/**
- * @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 Initializes a character-spacing run to its defaults.
- *
- * @param[in,out] characterSpacingCharacterRun The character-spacing run to initialize.
- */
-void Initialize(CharacterSpacingCharacterRun& characterSpacingCharacterRun)
-{
- characterSpacingCharacterRun.characterRun.characterIndex = 0u;
- characterSpacingCharacterRun.characterRun.numberOfCharacters = 0u;
- characterSpacingCharacterRun.value = 0.0f;
-}
-
-/**
- * @brief Splits the tag string into the tag name and its attributes.
- *
- * The attributes are stored in a vector in the tag.
- *
- * @param[in,out] tag The tag.
- */
-void ParseAttributes(Tag& tag)
-{
- if(tag.buffer == NULL)
- {
- return;
- }
-
- tag.attributes.Resize(MAX_NUM_OF_ATTRIBUTES);
-
- // Find first the tag name.
- bool isQuotationOpen = false;
-
- const char* tagBuffer = tag.buffer;
- const char* const tagEndBuffer = tagBuffer + tag.length;
- tag.length = 0u;
- for(; tagBuffer < tagEndBuffer; ++tagBuffer)
- {
- const char character = *tagBuffer;
- if(WHITE_SPACE < character)
- {
- ++tag.length;
- }
- else
- {
- // Stops counting the length of the tag when a white space is found.
- // @note a white space is the WHITE_SPACE character and anything below as 'tab', 'return' or 'control characters'.
- break;
- }
- }
- SkipWhiteSpace(tagBuffer, tagEndBuffer);
-
- // Find the attributes.
- unsigned int attributeIndex = 0u;
- const char* nameBuffer = NULL;
- const char* valueBuffer = NULL;
- Length nameLength = 0u;
- Length valueLength = 0u;
-
- bool addToNameValue = true;
- Length numberOfWhiteSpace = 0u;
- for(; tagBuffer < tagEndBuffer; ++tagBuffer)
- {
- const char character = *tagBuffer;
- if((WHITE_SPACE >= character) && !isQuotationOpen)
- {
- if(NULL != valueBuffer)
- {
- // Remove white spaces at the end of the value.
- valueLength -= numberOfWhiteSpace;
- }
-
- if((NULL != nameBuffer) && (NULL != valueBuffer))
- {
- // Every time a white space is found, a new attribute is created and stored in the attributes vector.
- Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
- ++attributeIndex;
-
- attribute.nameBuffer = nameBuffer;
- attribute.valueBuffer = valueBuffer;
- attribute.nameLength = nameLength;
- attribute.valueLength = valueLength;
-
- nameBuffer = NULL;
- valueBuffer = NULL;
- nameLength = 0u;
- valueLength = 0u;
-
- addToNameValue = true; // next read characters will be added to the name.
- }
- }
- else if(EQUAL == character) // '='
- {
- addToNameValue = false; // next read characters will be added to the value.
- SkipWhiteSpace(tagBuffer, tagEndBuffer);
- }
- else if(QUOTATION_MARK == character) // '\''
- {
- // Do not add quotation marks to neither name nor value.
- isQuotationOpen = !isQuotationOpen;
-
- if(isQuotationOpen)
- {
- ++tagBuffer;
- SkipWhiteSpace(tagBuffer, tagEndBuffer);
- --tagBuffer;
- }
- }
- else
- {
- // Adds characters to the name or the value.
- if(addToNameValue)
- {
- if(NULL == nameBuffer)
- {
- nameBuffer = tagBuffer;
- }
- ++nameLength;
- }
- else
- {
- if(isQuotationOpen)
- {
- if(WHITE_SPACE >= character)
- {
- ++numberOfWhiteSpace;
- }
- else
- {
- numberOfWhiteSpace = 0u;
- }
- }
- if(NULL == valueBuffer)
- {
- valueBuffer = tagBuffer;
- }
- ++valueLength;
- }
- }
- }
-
- if(NULL != valueBuffer)
- {
- // Remove white spaces at the end of the value.
- valueLength -= numberOfWhiteSpace;
- }
-
- if((NULL != nameBuffer) && (NULL != valueBuffer))
- {
- // Checks if the last attribute needs to be added.
- Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
- ++attributeIndex;
-
- attribute.nameBuffer = nameBuffer;
- attribute.valueBuffer = valueBuffer;
- attribute.nameLength = nameLength;
- attribute.valueLength = valueLength;
- }
-
- // Resize the vector of attributes.
- tag.attributes.Resize(attributeIndex);
-}
-
-/**
- * @brief It parses a tag and its attributes if the given iterator @e it is pointing at a tag beginning.
- *
- * @param[in,out] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
- * @param[in] markupStringEndBuffer Pointer to one character after the end of the mark-up string buffer.
- * @param[out] tag The tag with its attributes.
- *
- * @return @e true if the iterator @e it is pointing a mark-up tag. Otherwise @e false.
- */
-bool IsTag(const char*& markupStringBuffer,
- const char* const markupStringEndBuffer,
- Tag& tag)
-{
- bool isTag = false;
- bool isQuotationOpen = false;
- bool attributesFound = false;
- tag.isEndTag = false;
- bool isPreviousLessThan = false;
- bool isPreviousSlash = false;
-
- const char character = *markupStringBuffer;
- if(LESS_THAN == character) // '<'
- {
- tag.buffer = NULL;
- tag.length = 0u;
- isPreviousLessThan = true;
-
- // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed.
- ++markupStringBuffer;
- if(markupStringBuffer < markupStringEndBuffer)
- {
- SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
-
- for(; (!isTag) && (markupStringBuffer < markupStringEndBuffer); ++markupStringBuffer)
- {
- const char character = *markupStringBuffer;
-
- if(!isQuotationOpen && (SLASH == character)) // '/'
- {
- if(isPreviousLessThan)
- {
- tag.isEndTag = true;
- }
- else
- {
- // if the tag has a '/' it may be an end tag.
- isPreviousSlash = true;
- }
-
- isPreviousLessThan = false;
- if((markupStringBuffer + 1u < markupStringEndBuffer) && (WHITE_SPACE >= *(markupStringBuffer + 1u)))
- {
- ++markupStringBuffer;
- SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
- --markupStringBuffer;
- }
- }
- else if(GREATER_THAN == character) // '>'
- {
- isTag = true;
- if(isPreviousSlash)
- {
- tag.isEndTag = true;
- }
-
- isPreviousSlash = false;
- isPreviousLessThan = false;
- }
- else if(QUOTATION_MARK == character)
- {
- isQuotationOpen = !isQuotationOpen;
- ++tag.length;
-
- isPreviousSlash = false;
- isPreviousLessThan = false;
- }
- else if(WHITE_SPACE >= character) // ' '
- {
- // If the tag contains white spaces then it may have attributes.
- if(!isQuotationOpen)
- {
- attributesFound = true;
- }
- ++tag.length;
- }
- else
- {
- if(NULL == tag.buffer)
- {
- tag.buffer = markupStringBuffer;
- }
-
- // If it's not any of the 'special' characters then just add it to the tag string.
- ++tag.length;
-
- isPreviousSlash = false;
- isPreviousLessThan = false;
- }
- }
- }
-
- // If the tag string has white spaces, then parse the attributes is needed.
- if(attributesFound)
- {
- ParseAttributes(tag);
- }
- }
-
- return isTag;
-}
-
-/**
- * @brief Returns length of XHTML entity by parsing the text. It also determines if it is XHTML entity or not.
- *
- * @param[in] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
- * @param[in] markupStringEndBuffer Pointing to end of mark-up string buffer.
- *
- * @return Length of markupText in case of XHTML entity otherwise return 0.
- */
-unsigned int GetXHTMLEntityLength(const char*& markupStringBuffer,
- const char* const markupStringEndBuffer)
-{
- char character = *markupStringBuffer;
- if(AMPERSAND == character) // '&'
- {
- // if the iterator is pointing to a '&' character, then check for ';' to find end to XHTML entity.
- ++markupStringBuffer;
- if(markupStringBuffer < markupStringEndBuffer)
- {
- unsigned int len = 1u;
- for(; markupStringBuffer < markupStringEndBuffer; ++markupStringBuffer)
- {
- character = *markupStringBuffer;
- ++len;
- if(SEMI_COLON == character) // ';'
- {
- // found end of XHTML entity
- ++markupStringBuffer;
- return len;
- }
- else if((AMPERSAND == character) || (BACK_SLASH == character) || (LESS_THAN == character))
- {
- return 0;
- }
- }
- }
- }
- return 0;
-}
-
-/**
- * @brief It parses a XHTML string which has hex/decimal entity and fill its corresponging utf-8 string.
- *
- * @param[in] markupText The mark-up text buffer.
- * @param[out] utf-8 text Corresponding to markup Text
- *
- * @return true if string is successfully parsed otherwise false
- */
-bool XHTMLNumericEntityToUtf8(const char* markupText, char* utf8)
-{
- bool result = false;
-
- if(NULL != markupText)
- {
- bool isHex = false;
-
- // check if hex or decimal entity
- if((CHAR_ARRAY_END != *markupText) && (HEX_CODE == *markupText))
- {
- isHex = true;
- ++markupText;
- }
-
- char* end = NULL;
- unsigned long l = strtoul(markupText, &end, (isHex ? 16 : 10)); // l contains UTF-32 code in case of correct XHTML entity
-
- // check for valid XHTML numeric entities (between '#' or "#x" and ';')
- if((l > 0) && (l < ULONG_MAX) && (*end == SEMI_COLON)) // in case wrong XHTML entity is set eg. "abcdefs;" in that case *end will be 'a'
- {
- /* characters XML 1.1 permits */
- if(((XHTML_DECIMAL_ENTITY_RANGE[0] < l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[1])) ||
- ((XHTML_DECIMAL_ENTITY_RANGE[2] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[3])) ||
- ((XHTML_DECIMAL_ENTITY_RANGE[4] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[5])))
- {
- // Convert UTF32 code to UTF8
- Utf32ToUtf8(reinterpret_cast<const uint32_t* const>(&l), 1, reinterpret_cast<uint8_t*>(utf8));
- result = true;
- }
- }
- }
- return result;
-}
-
-/**
- * @brief Processes a particular tag for the required run (color-run, font-run or underlined-character-run).
- *
- * @tparam RunType Whether ColorRun , FontDescriptionRun or UnderlinedCharacterRun
- *
- * @param[in/out] runsContainer The container containing all the runs
- * @param[in/out] styleStack The style stack
- * @param[in] tag The tag we are currently processing
- * @param[in] characterIndex The current character index
- * @param[in/out] runIndex The run index
- * @param[in/out] tagReference The tagReference we should increment/decrement
- * @param[in] parameterSettingFunction This function will be called to set run specific parameters
- */
-template<typename RunType>
-void ProcessTagForRun(
- Vector<RunType>& runsContainer,
- StyleStack<RunIndex>& styleStack,
- const Tag& tag,
- const CharacterIndex characterIndex,
- RunIndex& runIndex,
- int& tagReference,
- std::function<void(const Tag&, RunType&)> parameterSettingFunction)
-{
- if(!tag.isEndTag)
- {
- // Create a new run.
- RunType run;
- Initialize(run);
-
- // Fill the run with the parameters.
- run.characterRun.characterIndex = characterIndex;
- parameterSettingFunction(tag, run);
-
- // Push the run in the logical model.
- runsContainer.PushBack(run);
-
- // Push the index of the run into the stack.
- styleStack.Push(runIndex);
-
- // Point the next free run.
- ++runIndex;
-
- // Increase reference
- ++tagReference;
- }
- else
- {
- if(tagReference > 0)
- {
- // Pop the top of the stack and set the number of characters of the run.
- RunType& run = *(runsContainer.Begin() + styleStack.Pop());
- run.characterRun.numberOfCharacters = characterIndex - run.characterRun.characterIndex;
- --tagReference;
- }
- }
-}
-
-/**
- * @brief Processes the item tag
- *
- * @param[in/out] markupProcessData The markup process data
- * @param[in] tag The current tag
- * @param[in/out] characterIndex The current character index
- */
-void ProcessItemTag(
- MarkupProcessData& markupProcessData,
- const Tag tag,
- CharacterIndex& characterIndex)
-{
- if(tag.isEndTag)
- {
- // Create an embedded item instance.
- EmbeddedItem item;
- item.characterIndex = characterIndex;
- ProcessEmbeddedItem(tag, item);
-
- markupProcessData.items.PushBack(item);
-
- // Insert white space character that will be replaced by the item.
- markupProcessData.markupProcessedText.append(1u, WHITE_SPACE);
- ++characterIndex;
- }
-}
-
-/**
- * @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
- * @param[in] tag The current tag
- * @param[in/out] characterIndex The current character index
- */
-void ProcessAnchorTag(
- MarkupProcessData& markupProcessData,
- const Tag tag,
- CharacterIndex& characterIndex)
-{
- if(!tag.isEndTag)
- {
- // Create an anchor instance.
- Anchor anchor;
- anchor.startIndex = characterIndex;
- anchor.endIndex = 0u;
- ProcessAnchor(tag, anchor);
- markupProcessData.anchors.PushBack(anchor);
- }
- else
- {
- // Update end index.
- unsigned int count = markupProcessData.anchors.Count();
- if(count > 0)
- {
- markupProcessData.anchors[count - 1].endIndex = characterIndex;
- }
- }
-}
-
-/**
- * @brief Processes span tag for the color-run & font-run.
- *
- * @param[in] spanTag The tag we are currently processing
- * @param[inout] spanStack The spans stack
- * @param[inout] colorRuns The container containing all the color runs
- * @param[inout] fontRuns The container containing all the font description runs
- * @param[inout] underlinedCharacterRuns The container containing all the underlined character runs
- * @param[inout] strikethroughCharacterRuns The container containing all the strikethroughed character runs
- * @param[inout] colorRunIndex The color run index
- * @param[inout] fontRunIndex The font run index
- * @param[inout] underlinedCharacterRunIndex The underlined character run index
- * @param[inout] strikethroughCharacterRunIndex The strikethroughed character run index
- * @param[in] characterIndex The current character index
- * @param[in] tagReference The tagReference we should increment/decrement
- */
-void ProcessSpanForRun(
- const Tag& spanTag,
- StyleStack<Span>& spanStack,
- Vector<ColorRun>& colorRuns,
- Vector<FontDescriptionRun>& fontRuns,
- Vector<UnderlinedCharacterRun>& underlinedCharacterRuns,
- Vector<ColorRun>& backgroundColorRuns,
- Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns,
- Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns,
- RunIndex& colorRunIndex,
- RunIndex& fontRunIndex,
- RunIndex& underlinedCharacterRunIndex,
- RunIndex& backgroundColorRunIndex,
- RunIndex& strikethroughCharacterRunIndex,
- RunIndex& characterSpacingCharacterRunIndex,
- const CharacterIndex characterIndex,
- int& tagReference)
-{
- if(!spanTag.isEndTag)
- {
- // Create a new run.
- ColorRun colorRun;
- Initialize(colorRun);
-
- FontDescriptionRun fontRun;
- Initialize(fontRun);
-
- UnderlinedCharacterRun underlinedCharacterRun;
- Initialize(underlinedCharacterRun);
-
- ColorRun backgroundColorRun;
- Initialize(backgroundColorRun);
-
- StrikethroughCharacterRun strikethroughCharacterRun;
- Initialize(strikethroughCharacterRun);
-
- CharacterSpacingCharacterRun characterSpacingCharacterRun;
- Initialize(characterSpacingCharacterRun);
-
- Span span;
- Initialize(span);
-
- // Fill the run with the parameters.
- colorRun.characterRun.characterIndex = characterIndex;
- fontRun.characterRun.characterIndex = characterIndex;
- underlinedCharacterRun.characterRun.characterIndex = characterIndex;
- backgroundColorRun.characterRun.characterIndex = characterIndex;
- strikethroughCharacterRun.characterRun.characterIndex = characterIndex;
- characterSpacingCharacterRun.characterRun.characterIndex = characterIndex;
-
- span.colorRunIndex = colorRunIndex;
- span.fontRunIndex = fontRunIndex;
- span.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
- span.backgroundColorRunIndex = backgroundColorRunIndex;
- span.strikethroughCharacterRunIndex = strikethroughCharacterRunIndex;
- span.characterSpacingCharacterRunIndex = characterSpacingCharacterRunIndex;
-
- ProcessSpanTag(spanTag,
- colorRun,
- fontRun,
- underlinedCharacterRun,
- backgroundColorRun,
- strikethroughCharacterRun,
- characterSpacingCharacterRun,
- span.isColorDefined,
- span.isFontDefined,
- span.isUnderlinedCharacterDefined,
- span.isBackgroundColorDefined,
- span.isStrikethroughDefined,
- span.isCharacterSpacingDefined);
-
- // Push the span into the stack.
- spanStack.Push(span);
-
- // Point the next free run.
- if(span.isColorDefined)
- {
- // Push the run in the logical model.
- colorRuns.PushBack(colorRun);
- ++colorRunIndex;
- }
-
- if(span.isFontDefined)
- {
- // Push the run in the logical model.
- fontRuns.PushBack(fontRun);
- ++fontRunIndex;
- }
-
- if(span.isUnderlinedCharacterDefined)
- {
- // Push the run in the logical model.
- underlinedCharacterRuns.PushBack(underlinedCharacterRun);
- ++underlinedCharacterRunIndex;
- }
-
- if(span.isBackgroundColorDefined)
- {
- // Push the run in the logical model.
- backgroundColorRuns.PushBack(backgroundColorRun);
- ++backgroundColorRunIndex;
- }
-
- if(span.isStrikethroughDefined)
- {
- // Push the run in the logical model.
- strikethroughCharacterRuns.PushBack(strikethroughCharacterRun);
- ++strikethroughCharacterRunIndex;
- }
-
- if(span.isCharacterSpacingDefined)
- {
- // Push the run in the logical model.
- characterSpacingCharacterRuns.PushBack(characterSpacingCharacterRun);
- ++characterSpacingCharacterRunIndex;
- }
-
- // Increase reference
- ++tagReference;
- }
- else
- {
- if(tagReference > 0)
- {
- // Pop the top of the stack and set the number of characters of the run.
- Span span = spanStack.Pop();
-
- if(span.isColorDefined)
- {
- ColorRun& colorRun = *(colorRuns.Begin() + span.colorRunIndex);
- colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
- }
-
- if(span.isFontDefined)
- {
- FontDescriptionRun& fontRun = *(fontRuns.Begin() + span.fontRunIndex);
- fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
- }
-
- if(span.isUnderlinedCharacterDefined)
- {
- UnderlinedCharacterRun& underlinedCharacterRun = *(underlinedCharacterRuns.Begin() + span.underlinedCharacterRunIndex);
- underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
- }
-
- if(span.isBackgroundColorDefined)
- {
- ColorRun& backgroundColorRun = *(backgroundColorRuns.Begin() + span.backgroundColorRunIndex);
- backgroundColorRun.characterRun.numberOfCharacters = characterIndex - backgroundColorRun.characterRun.characterIndex;
- }
-
- if(span.isStrikethroughDefined)
- {
- StrikethroughCharacterRun& strikethroughCharacterRun = *(strikethroughCharacterRuns.Begin() + span.strikethroughCharacterRunIndex);
- strikethroughCharacterRun.characterRun.numberOfCharacters = characterIndex - strikethroughCharacterRun.characterRun.characterIndex;
- }
-
- if(span.isCharacterSpacingDefined)
- {
- CharacterSpacingCharacterRun& characterSpacingCharacterRun = *(characterSpacingCharacterRuns.Begin() + span.characterSpacingCharacterRunIndex);
- characterSpacingCharacterRun.characterRun.numberOfCharacters = characterIndex - characterSpacingCharacterRun.characterRun.characterIndex;
- }
-
- --tagReference;
- }
- }
-}
-
-/**
- * @brief Resizes the model's vectors
- *
- * @param[inout] markupProcessData The markup process data
- * @param[in] fontRunIndex The font run index
- * @param[in] colorRunIndex The color run index
- * @param[in] underlinedCharacterRunIndex The underlined character run index
- * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
- * @param[in] backgroundRunIndex The background run index
- * @param[in] boundedParagraphRunIndex The bounded paragraph run index
- * @param[in] characterSpacingCharacterRunIndex The character-spacing character run index
- *
- */
-void ResizeModelVectors(MarkupProcessData& markupProcessData,
- const RunIndex fontRunIndex,
- const RunIndex colorRunIndex,
- const RunIndex underlinedCharacterRunIndex,
- const RunIndex strikethroughCharacterRunIndex,
- const RunIndex backgroundRunIndex,
- const RunIndex boundedParagraphRunIndex,
- const RunIndex characterSpacingCharacterRunIndex)
-{
- markupProcessData.fontRuns.Resize(fontRunIndex);
- markupProcessData.colorRuns.Resize(colorRunIndex);
- markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
- markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
- markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
- markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
- markupProcessData.characterSpacingCharacterRuns.Resize(characterSpacingCharacterRunIndex);
-
-#ifdef DEBUG_ENABLED
- if(gLogFilter->IsEnabledFor(Debug::Verbose))
- {
- for(uint32_t i = 0; i < colorRunIndex; ++i)
- {
- ColorRun& run = markupProcessData.colorRuns[i];
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "run[%d] index: %d, length: %d, color %f,%f,%f,%f\n", i, run.characterRun.characterIndex, run.characterRun.numberOfCharacters, run.color.r, run.color.g, run.color.b, run.color.a);
- }
- }
-#endif
-}
-
-/**
- * @brief Processes the markup string buffer
- *
- * @param[in/out] markupProcessData The markup process data
- * @param[in/out] markupStringBuffer The markup string buffer pointer
- * @param[in] markupStringEndBuffer The markup string end buffer pointer
- * @param[in/out] characterIndex The current character index
- */
-void ProcessMarkupStringBuffer(
- MarkupProcessData& markupProcessData,
- const char*& markupStringBuffer,
- const char* const markupStringEndBuffer,
- CharacterIndex& characterIndex)
-{
- unsigned char character = *markupStringBuffer;
- const char* markupBuffer = markupStringBuffer;
- unsigned char count = GetUtf8Length(character);
- char utf8[8];
-
- if((BACK_SLASH == character) && (markupStringBuffer + 1u < markupStringEndBuffer))
- {
- // Adding < , > or & special character.
- const unsigned char nextCharacter = *(markupStringBuffer + 1u);
- if((LESS_THAN == nextCharacter) || (GREATER_THAN == nextCharacter) || (AMPERSAND == nextCharacter))
- {
- character = nextCharacter;
- ++markupStringBuffer;
-
- count = GetUtf8Length(character);
- markupBuffer = markupStringBuffer;
- }
- }
- else // checking if contains XHTML entity or not
- {
- const unsigned int len = GetXHTMLEntityLength(markupStringBuffer, markupStringEndBuffer);
-
- // Parse markupStringTxt if it contains XHTML Entity between '&' and ';'
- if(len > 0)
- {
- char* entityCode = NULL;
- bool result = false;
- count = 0;
-
- // Checking if XHTML Numeric Entity
- if(HASH == *(markupBuffer + 1u))
- {
- entityCode = &utf8[0];
- // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#'
- result = XHTMLNumericEntityToUtf8((markupBuffer + 2u), entityCode);
- }
- else // Checking if XHTML Named Entity
- {
- entityCode = const_cast<char*>(NamedEntityToUtf8(markupBuffer, len));
- result = (entityCode != NULL);
- }
- if(result)
- {
- markupBuffer = entityCode; //utf8 text assigned to markupBuffer
- character = markupBuffer[0];
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer);
- markupBuffer = NULL;
- }
- }
- else // in case string conatins Start of XHTML Entity('&') but not its end character(';')
- {
- if(character == AMPERSAND)
- {
- markupBuffer = NULL;
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n");
- }
- }
- }
-
- if(markupBuffer != NULL)
- {
- const unsigned char numberOfBytes = GetUtf8Length(character);
- markupProcessData.markupProcessedText.push_back(character);
-
- for(unsigned char i = 1u; i < numberOfBytes; ++i)
- {
- ++markupBuffer;
- markupProcessData.markupProcessedText.push_back(*markupBuffer);
- }
-
- ++characterIndex;
- markupStringBuffer += count;
- }
-}
-
-} // namespace
-
-void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str());
-
- // Reserve space for the plain text.
- const Length markupStringSize = markupString.size();
- markupProcessData.markupProcessedText.reserve(markupStringSize);
-
- // Stores a struct with the index to the first character of the run, the type of run and its parameters.
- StyleStack<RunIndex> styleStack;
-
- // Stores a struct with the index to the first character of the color run & color font for the span.
- StyleStack<Span> spanStack;
-
- // Points the next free position in the vector of runs.
- RunIndex colorRunIndex = 0u;
- RunIndex fontRunIndex = 0u;
- RunIndex underlinedCharacterRunIndex = 0u;
- RunIndex backgroundRunIndex = 0u;
- RunIndex strikethroughCharacterRunIndex = 0u;
- RunIndex boundedParagraphRunIndex = 0u;
- RunIndex characterSpacingCharacterRunIndex = 0u;
-
- // check tag reference
- int colorTagReference = 0u;
- int fontTagReference = 0u;
- int iTagReference = 0u;
- int bTagReference = 0u;
- int uTagReference = 0u;
- int backgroundTagReference = 0u;
- int spanTagReference = 0u;
- int sTagReference = 0u;
- int pTagReference = 0u;
- int characterSpacingTagReference = 0u;
-
- // Give an initial default value to the model's vectors.
- markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
- markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
- markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
- markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
- markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
- markupProcessData.characterSpacingCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
-
- // Get the mark-up string buffer.
- const char* markupStringBuffer = markupString.c_str();
- const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
-
- Tag tag;
- CharacterIndex characterIndex = 0u;
- for(; markupStringBuffer < markupStringEndBuffer;)
- {
- tag.attributes.Clear();
- if(IsTag(markupStringBuffer,
- markupStringEndBuffer,
- tag))
- {
- if(TokenComparison(MARKUP::TAG::COLOR, tag.buffer, tag.length))
- {
- ProcessTagForRun<ColorRun>(
- markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) { ProcessColorTag(tag, run); });
- } // <color></color>
- else if(TokenComparison(MARKUP::TAG::ITALIC, tag.buffer, tag.length))
- {
- ProcessTagForRun<FontDescriptionRun>(
- markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, iTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
- fontRun.slant = TextAbstraction::FontSlant::ITALIC;
- fontRun.slantDefined = true;
- });
- } // <i></i>
- else if(TokenComparison(MARKUP::TAG::UNDERLINE, tag.buffer, tag.length))
- {
- ProcessTagForRun<UnderlinedCharacterRun>(
- markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { ProcessUnderlineTag(tag, run); });
- } // <u></u>
- else if(TokenComparison(MARKUP::TAG::BOLD, tag.buffer, tag.length))
- {
- ProcessTagForRun<FontDescriptionRun>(
- markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, bTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
- fontRun.weight = TextAbstraction::FontWeight::BOLD;
- fontRun.weightDefined = true;
- });
- } // <b></b>
- else if(TokenComparison(MARKUP::TAG::FONT, tag.buffer, tag.length))
- {
- ProcessTagForRun<FontDescriptionRun>(
- markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, fontTagReference, [](const Tag& tag, FontDescriptionRun& fontRun) { ProcessFontTag(tag, fontRun); });
- } // <font></font>
- else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length))
- {
- /* Anchor */
- ProcessAnchorTag(markupProcessData, tag, characterIndex);
- /* Color */
- ProcessTagForRun<ColorRun>(
- markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) {
- run.color = Color::BLUE;
- ProcessColorTag(tag, run);
- });
- /* Underline */
- ProcessTagForRun<UnderlinedCharacterRun>(
- markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) {
- run.properties.color = Color::BLUE;
- run.properties.colorDefined = true;
- ProcessUnderlineTag(tag, run);
- });
- } // <a href=https://www.tizen.org>tizen</a>
- else if(TokenComparison(MARKUP::TAG::SHADOW, tag.buffer, tag.length))
- {
- // TODO: If !tag.isEndTag, then create a new shadow run.
- // else Pop the top of the stack and set the number of characters of the run.
- } // <shadow></shadow>
- else if(TokenComparison(MARKUP::TAG::GLOW, tag.buffer, tag.length))
- {
- // TODO: If !tag.isEndTag, then create a new glow run.
- // else Pop the top of the stack and set the number of characters of the run.
- } // <glow></glow>
- else if(TokenComparison(MARKUP::TAG::OUTLINE, tag.buffer, tag.length))
- {
- // TODO: If !tag.isEndTag, then create a new outline run.
- // else Pop the top of the stack and set the number of characters of the run.
- } // <outline></outline>
- else if(TokenComparison(MARKUP::TAG::EMBEDDED_ITEM, tag.buffer, tag.length))
- {
- ProcessItemTag(markupProcessData, tag, characterIndex);
- }
- else if(TokenComparison(MARKUP::TAG::BACKGROUND, tag.buffer, tag.length))
- {
- ProcessTagForRun<ColorRun>(
- markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
- }
- else if(TokenComparison(MARKUP::TAG::SPAN, tag.buffer, tag.length))
- {
- ProcessSpanForRun(tag,
- spanStack,
- markupProcessData.colorRuns,
- markupProcessData.fontRuns,
- markupProcessData.underlinedCharacterRuns,
- markupProcessData.backgroundColorRuns,
- markupProcessData.strikethroughCharacterRuns,
- markupProcessData.characterSpacingCharacterRuns,
- colorRunIndex,
- fontRunIndex,
- underlinedCharacterRunIndex,
- backgroundRunIndex,
- strikethroughCharacterRunIndex,
- characterSpacingCharacterRunIndex,
- characterIndex,
- spanTagReference);
- }
- else if(TokenComparison(MARKUP::TAG::STRIKETHROUGH, tag.buffer, tag.length))
- {
- ProcessTagForRun<StrikethroughCharacterRun>(
- markupProcessData.strikethroughCharacterRuns, styleStack, tag, characterIndex, strikethroughCharacterRunIndex, sTagReference, [](const Tag& tag, StrikethroughCharacterRun& run) { ProcessStrikethroughTag(tag, run); });
- } // <s></s>
- else if(TokenComparison(MARKUP::TAG::PARAGRAPH, tag.buffer, tag.length))
- {
- ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex);
- ProcessTagForRun<BoundedParagraphRun>(
- markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
- } // <p></p>
- else if(TokenComparison(MARKUP::TAG::CHARACTER_SPACING, tag.buffer, tag.length))
- {
- ProcessTagForRun<CharacterSpacingCharacterRun>(
- markupProcessData.characterSpacingCharacterRuns, styleStack, tag, characterIndex, characterSpacingCharacterRunIndex, characterSpacingTagReference, [](const Tag& tag, CharacterSpacingCharacterRun& run) { ProcessCharacterSpacingTag(tag, run); });
- } // <char-spacing></char-spacing>
- } // end if( IsTag() )
- else if(markupStringBuffer < markupStringEndBuffer)
- {
- ProcessMarkupStringBuffer(markupProcessData, markupStringBuffer, markupStringEndBuffer, characterIndex);
- }
- }
-
- // Resize the model's vectors.
- ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex, characterSpacingCharacterRunIndex);
-
- // Handle the nested tags
- OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
- OverrideNestedStrikethroughCharacterRuns(markupProcessData.strikethroughCharacterRuns);
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
-#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/common/dali-vector.h>
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/anchor.h>
-#include <dali-toolkit/internal/text/bounded-paragraph-run.h>
-#include <dali-toolkit/internal/text/character-spacing-character-run.h>
-#include <dali-toolkit/internal/text/color-run.h>
-#include <dali-toolkit/internal/text/embedded-item.h>
-#include <dali-toolkit/internal/text/font-description-run.h>
-#include <dali-toolkit/internal/text/strikethrough-character-run.h>
-#include <dali-toolkit/internal/text/underlined-character-run.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-/**
- * @brief Keeps the plain text and references to vectors from the model which stores runs with text styles.
- */
-struct MarkupProcessData
-{
- MarkupProcessData(Vector<ColorRun>& colorRuns,
- Vector<FontDescriptionRun>& fontRuns,
- Vector<EmbeddedItem>& items,
- Vector<Anchor>& anchors,
- Vector<UnderlinedCharacterRun>& underlinedCharacterRuns,
- Vector<ColorRun>& backgroundColorRuns,
- Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns,
- Vector<BoundedParagraphRun>& boundedParagraphRuns,
- Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns)
- : colorRuns(colorRuns),
- fontRuns(fontRuns),
- items(items),
- anchors(anchors),
- underlinedCharacterRuns(underlinedCharacterRuns),
- backgroundColorRuns(backgroundColorRuns),
- strikethroughCharacterRuns(strikethroughCharacterRuns),
- boundedParagraphRuns(boundedParagraphRuns),
- characterSpacingCharacterRuns(characterSpacingCharacterRuns),
- markupProcessedText()
- {
- }
-
- Vector<ColorRun>& colorRuns; ///< The color runs.
- Vector<FontDescriptionRun>& fontRuns; ///< The font description runs.
- Vector<EmbeddedItem>& items; ///< The embedded items.
- Vector<Anchor>& anchors; ///< The anchors.
- Vector<UnderlinedCharacterRun>& underlinedCharacterRuns; ///< The underlined character runs.
- Vector<ColorRun>& backgroundColorRuns; ///< The background color runs.
- Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns; ///< The strikethrough character runs.
- Vector<BoundedParagraphRun>& boundedParagraphRuns; ///< The bounded paragraph runs
- Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns; ///< The character-spacing runs
-
- std::string markupProcessedText; ///< The mark-up string.
-};
-
-/**
- * @brief Process the mark-up string.
- *
- * @param[in] markupString The mark-up string.
- * @param[out] markupProcessData The plain text and the style.
- */
-void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData);
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/anchor.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessAnchor(const Tag& tag, Anchor& anchor)
+{
+ anchor.href = nullptr;
+
+ for(auto&& attribute : tag.attributes)
+ {
+ if(TokenComparison(MARKUP::ANCHOR_ATTRIBUTES::HREF, attribute.nameBuffer, attribute.nameLength))
+ {
+ Length hrefLength = attribute.valueLength + 1;
+ anchor.href = new char[hrefLength];
+ memcpy(anchor.href, attribute.valueBuffer, hrefLength);
+ anchor.href[hrefLength - 1] = '\0';
+ // The memory is freed when the font run is removed from the logical model.
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ANCHOR_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ANCHOR_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 Anchor;
+
+/**
+ * @brief Retrieves the @e anchor from the @p tag.
+ *
+ * @param[in] tag The anchor tag and its attributes.
+ * @param[in,out] anchor The anchor.
+ */
+void ProcessAnchor( const Tag& tag, Anchor& anchor );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ANCHOR_H
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-attribute-helper-functions.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void CopyAttributeValueFromBuffer(const Attribute& attribute, const Length maxLengthAttributeValue, char* value)
+{
+ const Length length = attribute.valueLength > maxLengthAttributeValue ? maxLengthAttributeValue : attribute.valueLength;
+ memcpy(value, attribute.valueBuffer, length);
+ value[length] = 0;
+}
+
+float ProcessFloatAttribute(const Attribute& attribute)
+{
+ return StringToFloat(attribute.valueBuffer);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <functional>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Attribute;
+
+/**
+ * @brief Copy the value from attribute buffer to value.
+ *
+ * @param[in] attribute the value of attribute.
+ * @param[in] maxLengthAttributeValue the maximum length of any of the possible value for attribute
+ * @param[out] value the value container.
+ *
+ */
+void CopyAttributeValueFromBuffer(const Attribute& attribute, const Length maxLengthAttributeValue, char* value);
+
+/**
+ * @brief Process the float attribute value from buffer.
+ *
+ * @param[in] attribute the float attribute.
+ *
+ * @return The float value.
+ */
+float ProcessFloatAttribute(const Attribute& attribute);
+
+/**
+ * @brief Process the Enumeration attribute value from buffer.
+ *
+ * @param[in] attribute the Enumeration attribute.
+ * @param[in] maxLengthAttributeValue the maximum length of any of the possible value for attribute
+ * @param[in] funcStringToEnum the function converts string value to enum value
+ * @param[out] enumValue the enum value
+ *
+ * @return True if the enum value was processed successfully
+ *
+ */
+template<typename T>
+bool ProcessEnumerationAttribute(const Attribute& attribute,
+ const Length maxLengthAttributeValue,
+ std::function<T(const char* const)> funcStringToEnum,
+ T& enumValue)
+{
+ char* value = new char[maxLengthAttributeValue + 1u];
+
+ CopyAttributeValueFromBuffer(attribute, maxLengthAttributeValue, value);
+
+ enumValue = funcStringToEnum(value); // @TODO: the functions that process Enum value should be refactored to return bool from Scripting::GetEnumeration
+
+ delete[] value;
+
+ return true;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-background.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessBackground(const Tag& tag, ColorRun& colorRun)
+{
+ for(auto&& attribute : tag.attributes)
+ {
+ if(TokenComparison(MARKUP::BACKGROUND_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_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 ColorRun;
+
+/**
+ * @brief Retrieves the @e background from the @p tag.
+ *
+ * @param[in] tag The background tag and its attributes.
+ * @param[in,out] colorRun The color run to be filled.
+ */
+void ProcessBackground(const Tag& tag, ColorRun& colorRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-character-spacing.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-spacing-character-run.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-attribute-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
+{
+ characterSpacingCharacterRun.value = ProcessFloatAttribute(attribute);
+}
+
+void ProcessCharacterSpacingTag(const Tag& tag, CharacterSpacingCharacterRun& characterSpacingCharacterRun)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+
+ if(TokenComparison(MARKUP::CHARACTER_SPACING_ATTRIBUTES::VALUE, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessValueAttribute(attribute, characterSpacingCharacterRun);
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct Attribute;
+struct CharacterSpacingCharacterRun;
+
+/**
+ * @brief Fill the character-spacing character run with the value (space or advance) attribute.
+ *
+ * @param[in] attribute the value attribute.
+ * @param[out] characterSpacingCharacterRun The underlined character run
+ */
+void ProcessValueAttribute(const Attribute& attribute, CharacterSpacingCharacterRun& characterSpacingCharacterRun);
+
+/**
+ * @brief Retrieves the character-spacing run info from the tag and sets it to the character-spacing run.
+ *
+ * @param[in] tag The character-spacing tag and its attributes.
+ * @param[in,out] characterSpacingCharacterRun The character-spacing character run
+ */
+void ProcessCharacterSpacingTag(const Tag& tag, CharacterSpacingCharacterRun& characterSpacingCharacterRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_CHARACTER_SPACING_H
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-color.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessColor(const Attribute& attribute, ColorRun& colorRun)
+{
+ ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
+}
+
+void ProcessColorTag(const Tag& tag, ColorRun& colorRun)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+ if(TokenComparison(MARKUP::COLOR_ATTRIBUTES::VALUE, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessColor(attribute, colorRun);
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_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 ColorRun;
+
+/**
+ * @brief Retrieves the color value from the tag and sets it to the color run.
+ *
+ * @param[in] attribute the color attribute.
+ * @param[in,out] colorRun The color run.
+ */
+void ProcessColor(const Attribute& attribute, ColorRun& colorRun);
+
+/**
+ * @brief Retrieves the color value from the tag and sets it to the color run.
+ *
+ * @param[in] tag The color tag and its attributes.
+ * @param[in,out] colorRun The color run.
+ */
+void ProcessColorTag(const Tag& tag, ColorRun& colorRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-embedded-item.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/embedded-item.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string NONE("none");
+const std::string MULTIPLY("multiply");
+} // namespace
+
+void ProcessEmbeddedItem(const Tag& tag, EmbeddedItem& embeddedItem)
+{
+ embeddedItem.url = nullptr;
+ embeddedItem.urlLength = 0u;
+ embeddedItem.width = 0u;
+ embeddedItem.height = 0u;
+ embeddedItem.colorBlendingMode = ColorBlendingMode::NONE;
+
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+ if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::URL, attribute.nameBuffer, attribute.nameLength))
+ {
+ embeddedItem.urlLength = attribute.valueLength;
+ embeddedItem.url = new char[embeddedItem.urlLength];
+ memcpy(embeddedItem.url, attribute.valueBuffer, embeddedItem.urlLength);
+ // The memory is freed when the font run is removed from the logical model.
+ }
+ else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::WIDTH, attribute.nameBuffer, attribute.nameLength))
+ {
+ embeddedItem.width = StringToUint(attribute.valueBuffer);
+ }
+ else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ embeddedItem.height = StringToUint(attribute.valueBuffer);
+ }
+ else if(TokenComparison(MARKUP::EMBEDDED_ITEM_ATTRIBUTES::COLOR_BLENDING, attribute.nameBuffer, attribute.nameLength))
+ {
+ if(TokenComparison(MULTIPLY, attribute.valueBuffer, attribute.valueLength))
+ {
+ embeddedItem.colorBlendingMode = ColorBlendingMode::MULTIPLY;
+ }
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_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 EmbeddedItem;
+
+/**
+ * @brief Retrieves the @e embedded @e item from the @p tag.
+ *
+ * @param[in] tag The embedded item tag and its attributes.
+ * @param[in,out] embeddedItem The embedded item.
+ */
+void ProcessEmbeddedItem(const Tag& tag, EmbeddedItem& embeddedItem);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-font.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-attribute-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string FONT_PREFIX("font-");
+const unsigned int FONT_PREFIX_LENGTH = 5u;
+const unsigned int MIN_FONT_ATTRIBUTE_SIZE = 4u; ///< The minimum length of any of the possible 'weight', 'width' , 'slant' or 'size' values.
+const unsigned int MAX_FONT_ATTRIBUTE_SIZE = 15u; ///< The maximum length of any of the possible 'weight', 'width' or 'slant' values.
+const float PIXEL_FORMAT_64_FACTOR = 64.f; ///< 64.f is used to convert from point size to 26.6 pixel format.
+} // namespace
+
+void processFontAttributeValue(char value[], const Attribute& attribute)
+{
+ // The StringToWeight() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
+ const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
+ memcpy(value, attribute.valueBuffer, length);
+ value[length] = 0;
+}
+
+void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ fontRun.familyDefined = true;
+ fontRun.familyLength = attribute.valueLength;
+ fontRun.familyName = new char[fontRun.familyLength];
+ memcpy(fontRun.familyName, attribute.valueBuffer, fontRun.familyLength);
+ // The memory is freed when the font run is removed from the logical model.
+}
+
+void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ // 64.f is used to convert from point size to 26.6 pixel format.
+ fontRun.size = static_cast<PointSize26Dot6>(ProcessFloatAttribute(attribute) * PIXEL_FORMAT_64_FACTOR);
+ fontRun.sizeDefined = true;
+}
+
+void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ fontRun.weightDefined = ProcessEnumerationAttribute<FontWeight>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToWeight, fontRun.weight);
+}
+
+void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ fontRun.widthDefined = ProcessEnumerationAttribute<FontWidth>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToWidth, fontRun.width);
+}
+
+void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ fontRun.slantDefined = ProcessEnumerationAttribute<FontSlant>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToSlant, fontRun.slant);
+}
+
+void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+
+ if(TokenComparison(MARKUP::FONT_ATTRIBUTES::FAMILY, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessFontFamily(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::SIZE, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessFontSize(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::WEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessFontWeight(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::WIDTH, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessFontWidth(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::FONT_ATTRIBUTES::SLANT, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessFontSlant(attribute, fontRun);
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_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 FontDescriptionRun;
+
+/**
+ * @brief Retrieves the font attributes from the tag and sets it to the font run.
+ *
+ * @param[in] tag The font tag and its attributes.
+ * @param[in,out] fontRun The font description run.
+ */
+void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font slant attribute value.
+ *
+ * @param[in] attribute the font slant attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font width attribute value.
+ *
+ * @param[in] attribute the font width attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font weight attribute value.
+ *
+ * @param[in] attribute the font weight attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font size attribute value.
+ *
+ * @param[in] attribute the font size attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font family attribute value.
+ *
+ * @param[in] attribute the font family attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/constants.h>
+#include <dali/public-api/math/vector2.h>
+#include <stdlib.h>
+#include <iomanip>
+#include <sstream>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const char WHITE_SPACE = 0x20; // ASCII value of the white space.
+const char FIRST_UPPER_CASE = 0x41; // ASCII value of the one after the first upper case character (A).
+const char LAST_UPPER_CASE = 0x5b; // ASCII value of the one after the last upper case character (Z).
+const char TO_LOWER_CASE = 32; // Value to add to a upper case character to transform it into a lower case.
+
+const unsigned int MAX_FLOAT_ATTRIBUTE_SIZE = 17u; ///< The maximum length of any of the possible float values. +99999.999999999f (sign, five digits, dot, nine digits, f)
+
+const char WEB_COLOR_TOKEN('#');
+const char* const HEX_COLOR_TOKEN("0x");
+const char* const ALPHA_ONE("FF");
+
+const std::string BLACK_COLOR("black");
+const std::string WHITE_COLOR("white");
+const std::string RED_COLOR("red");
+const std::string GREEN_COLOR("green");
+const std::string BLUE_COLOR("blue");
+const std::string YELLOW_COLOR("yellow");
+const std::string MAGENTA_COLOR("magenta");
+const std::string CYAN_COLOR("cyan");
+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)
+{
+ const Length stringSize = string1.size();
+ if(stringSize != length)
+ {
+ // Early return. Strings have different sizes.
+ return false;
+ }
+
+ const char* const stringBuffer1 = string1.c_str();
+
+ for(std::size_t index = 0; index < stringSize; ++index)
+ {
+ const char character = *(stringBuffer2 + index);
+ const bool toLower = (character < LAST_UPPER_CASE) && (character >= FIRST_UPPER_CASE);
+ if(*(stringBuffer1 + index) != (toLower ? character + TO_LOWER_CASE : character))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void SkipWhiteSpace(const char*& stringBuffer,
+ const char* const stringEndBuffer)
+{
+ for(; (WHITE_SPACE >= *stringBuffer) && (stringBuffer < stringEndBuffer); ++stringBuffer)
+ ;
+}
+
+void JumpToWhiteSpace(const char*& stringBuffer,
+ const char* const stringEndBuffer)
+{
+ for(; (WHITE_SPACE != *stringBuffer) && (stringBuffer < stringEndBuffer); ++stringBuffer)
+ ;
+}
+
+unsigned int StringToUint(const char* const uintStr)
+{
+ return static_cast<unsigned int>(strtoul(uintStr, NULL, 10));
+}
+
+unsigned int StringToHex(const char* const uintStr)
+{
+ return static_cast<unsigned int>(strtoul(uintStr, NULL, 16));
+}
+
+float StringToFloat(const char* const floatStr)
+{
+ return static_cast<float>(strtod(floatStr, NULL));
+}
+
+void FloatToString(float value, std::string& floatStr)
+{
+ std::stringstream ss;
+ ss << value;
+ floatStr = ss.str();
+}
+
+void UintToString(unsigned int value, std::string& uIntStr)
+{
+ std::stringstream ss;
+ ss << value;
+ uIntStr = ss.str();
+}
+
+void UintColorToVector4(unsigned int color, Vector4& retColor)
+{
+ retColor.a = static_cast<float>((color & 0xFF000000) >> 24u) / 255.f;
+ retColor.r = static_cast<float>((color & 0x00FF0000) >> 16u) / 255.f;
+ retColor.g = static_cast<float>((color & 0x0000FF00) >> 8u) / 255.f;
+ retColor.b = static_cast<float>(color & 0x000000FF) / 255.f;
+}
+
+void ColorStringToVector4(const char* const colorStr, Length length, Vector4& retColor)
+{
+ if(WEB_COLOR_TOKEN == *colorStr)
+ {
+ std::string webColor(colorStr + 1u, length - 1u);
+ if(4u == length) // 3 component web color #F00 (red)
+ {
+ webColor.insert(2u, &(webColor[2]), 1u);
+ webColor.insert(1u, &(webColor[1]), 1u);
+ webColor.insert(0u, &(webColor[0]), 1u);
+ webColor.insert(0u, ALPHA_ONE);
+ }
+ else if(7u == length) // 6 component web color #FF0000 (red)
+ {
+ webColor.insert(0u, ALPHA_ONE);
+ }
+
+ UintColorToVector4(StringToHex(webColor.c_str()), retColor);
+ }
+ else if(TokenComparison(HEX_COLOR_TOKEN, colorStr, 2u))
+ {
+ UintColorToVector4(StringToHex(colorStr + 2u), retColor);
+ }
+ else if(TokenComparison(BLACK_COLOR, colorStr, length))
+ {
+ retColor = Color::BLACK;
+ }
+ else if(TokenComparison(WHITE_COLOR, colorStr, length))
+ {
+ retColor = Color::WHITE;
+ }
+ else if(TokenComparison(RED_COLOR, colorStr, length))
+ {
+ retColor = Color::RED;
+ }
+ else if(TokenComparison(GREEN_COLOR, colorStr, length))
+ {
+ retColor = Color::GREEN;
+ }
+ else if(TokenComparison(BLUE_COLOR, colorStr, length))
+ {
+ retColor = Color::BLUE;
+ }
+ else if(TokenComparison(YELLOW_COLOR, colorStr, length))
+ {
+ retColor = Color::YELLOW;
+ }
+ else if(TokenComparison(MAGENTA_COLOR, colorStr, length))
+ {
+ retColor = Color::MAGENTA;
+ }
+ else if(TokenComparison(CYAN_COLOR, colorStr, length))
+ {
+ retColor = Color::CYAN;
+ }
+ else if(TokenComparison(TRANSPARENT_COLOR, colorStr, length))
+ {
+ retColor = Color::TRANSPARENT;
+ }
+}
+
+void Vector4ToColorString(const Vector4& value, std::string& vector2Str)
+{
+ if(Color::BLACK == value)
+ {
+ vector2Str = BLACK_COLOR;
+ return;
+ }
+
+ if(Color::WHITE == value)
+ {
+ vector2Str = WHITE_COLOR;
+ return;
+ }
+
+ if(Color::RED == value)
+ {
+ vector2Str = RED_COLOR;
+ return;
+ }
+
+ if(Color::GREEN == value)
+ {
+ vector2Str = GREEN_COLOR;
+ return;
+ }
+
+ if(Color::BLUE == value)
+ {
+ vector2Str = BLUE_COLOR;
+ return;
+ }
+
+ if(Color::YELLOW == value)
+ {
+ vector2Str = YELLOW_COLOR;
+ return;
+ }
+
+ if(Color::MAGENTA == value)
+ {
+ vector2Str = MAGENTA_COLOR;
+ return;
+ }
+
+ if(Color::CYAN == value)
+ {
+ vector2Str = CYAN_COLOR;
+ return;
+ }
+
+ if(Color::TRANSPARENT == value)
+ {
+ vector2Str = TRANSPARENT_COLOR;
+ return;
+ }
+
+ const unsigned int alpha = static_cast<unsigned int>(255.f * value.a);
+ const unsigned int red = static_cast<unsigned int>(255.f * value.r);
+ const unsigned int green = static_cast<unsigned int>(255.f * value.g);
+ const unsigned int blue = static_cast<unsigned int>(255.f * value.b);
+
+ std::stringstream ss;
+ const unsigned int size = 2u * sizeof(unsigned char);
+
+ ss << "0x"
+ << std::setfill('0') << std::setw(size)
+ << std::hex << alpha
+ << std::setfill('0') << std::setw(size)
+ << std::hex << red
+ << std::setfill('0') << std::setw(size)
+ << std::hex << green
+ << std::setfill('0') << std::setw(size)
+ << std::hex << blue;
+ vector2Str = ss.str();
+}
+
+void StringToVector2(const char* const vectorStr, Length length, Vector2& vector2)
+{
+ // Points to the first character of the string.
+ const char* strBuffer = vectorStr;
+
+ // Points to the first character of the 'x' value.
+ const char* const xBuffer = strBuffer;
+
+ // Jumps to the next white space.
+ JumpToWhiteSpace(strBuffer, strBuffer + length);
+
+ // Points to the first character of the 'y' value.
+ const char* const yBuffer = strBuffer;
+
+ // Converts the shadow's offset to float.
+ vector2.x = StringToFloat(xBuffer);
+ vector2.y = StringToFloat(yBuffer);
+}
+
+void Vector2ToString(const Vector2& value, std::string& vector2Str)
+{
+ FloatToString(value.x, vector2Str);
+ vector2Str += " ";
+
+ std::string yStr;
+ FloatToString(value.y, yStr);
+
+ vector2Str += yStr;
+}
+
+void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Text::Underline::Type& retType)
+{
+ if(TokenComparison(SOLID_UNDERLINE, typeStr, length))
+ {
+ retType = Text::Underline::SOLID;
+ }
+ else if(TokenComparison(DASHED_UNDERLINE, typeStr, length))
+ {
+ retType = Text::Underline::DASHED;
+ }
+ else if(TokenComparison(DOUBLE_UNDERLINE, typeStr, length))
+ {
+ retType = Text::Underline::DOUBLE;
+ }
+}
+
+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
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+
+namespace Dali
+{
+struct Vector2;
+struct Vector4;
+
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Stores an attribute pair: name, value.
+ */
+struct Attribute
+{
+ const char* nameBuffer;
+ const char* valueBuffer;
+ Length nameLength;
+ Length valueLength;
+};
+
+/**
+ * @brief Stores a tag and its attributes.
+ */
+struct Tag
+{
+ Vector<Attribute> attributes;
+ const char* buffer;
+ Length length;
+ bool isEndTag;
+};
+
+/**
+ * @brief Compare if two tokens are equal.
+ *
+ * @pre @p string1 must be lower case. (The html-ish constant tokens)
+ * The @p stringBuffer2 parameter is transformed to lower case.
+ * This function is used in the mark-up parser.
+ * It has no sense to transform the constants html-ish tokens to lower case when
+ * it's known they already are.
+ *
+ * @param[in] string1 The html-ish constant token.
+ * @param[in] stringBuffer2 Pointer to the html-ish token buffer.
+ * @param[in] length The length of the html-ish token.
+ *
+ * @return @e true if both strings are equal.
+ */
+bool TokenComparison(const std::string& string1, const char* const stringBuffer2, Length length);
+
+/**
+ * @brief Skips any unnecessary white space.
+ *
+ * @param[in,out] stringBuffer The string buffer. It's a const iterator pointing the current character.
+ * @param[in] stringEndBuffer Pointer to one character after the end of the string buffer.
+ */
+void SkipWhiteSpace(const char*& stringBuffer,
+ const char* const stringEndBuffer);
+
+/**
+ * @Brief Jumps to the next white space.
+ *
+ * @param[in,out] stringBuffer The string buffer. It's a const iterator pointing the current character.
+ * @param[in] stringEndBuffer Pointer to one character after the end of the string buffer.
+ */
+void JumpToWhiteSpace(const char*& stringBuffer,
+ const char* const stringEndBuffer);
+
+/**
+* @brief Converts a string into an unsigned int.
+*
+* @param[in] uintStr An unsigned int packed inside a string.
+*
+* @return The unsigned int value.
+*/
+unsigned int StringToUint(const char* const uintStr);
+
+/**
+ * @brief Converts a string into an hexadecimal unsigned int.
+ *
+ * @param[in] uintStr An hexadecimal unsigned int packed inside a string.
+ *
+ * @return The hexadecimal value.
+ */
+unsigned int StringToHex(const char* const uintStr);
+
+/**
+ * @brief Converts a string into a float value.
+ *
+ * @param[in] floatStr A float packed inside a string.
+ *
+ * @return The float value.
+ */
+float StringToFloat(const char* const floatStr);
+
+/**
+ * @brief Converts a float into a string.
+ *
+ * @param[in] value The float value.
+ * @param[out] floatStr The string.
+ */
+void FloatToString(float value, std::string& floatStr);
+
+/**
+ * @brief Converts an unsigned int into a string.
+ *
+ * @param[in] value The unsigned int value.
+ * @param[out] uIntStr The string.
+ */
+void UintToString(unsigned int value, std::string& uIntStr);
+
+/**
+ * @brief Converts an ARGB color packed in 4 byte unsigned int into a Vector4 color used in Dali.
+ *
+ * @param[in] color An ARGB color packed in an unsigned int.
+ * @param[out] retColor A Vector4 with the converted color.
+ */
+void UintColorToVector4(unsigned int color, Vector4& retColor);
+
+/**
+ * @brief Converts a color packed inside a string into an ARGB Vector4 color.
+ *
+ * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values:
+ * black, white, red, green, blue, yellow, magenta, cyan or transparent.
+ *
+ * @param[in] colorStr A color packed inside a string.
+ * @param[in] length The length of the color string.
+ * @param[out] retColor A color packed inside a Vector4.
+ */
+void ColorStringToVector4(const char* const colorStr, Length length, Vector4& retColor);
+
+/**
+ * @brief Converts a color packed in a Vector4 into a string.
+ *
+ * Constant colors will be converted to the strings black, white, red, green, blue, yellow, magenta, cyan or transparent.
+ *
+ * If is not a constant color it will be converted to a string with hexadecimal ARGB content.
+ *
+ * @param[in] value The color value.
+ * @param[out] colorStr The string.
+ */
+void Vector4ToColorString(const Vector4& value, std::string& vector2Str);
+
+/**
+ * @brief Converts a two dimension vector packed inside a string into a Vector2.
+ *
+ * @param[in] vectorStr The two dimension vector packed inside a string.
+ * @param[in] length The length of the string.
+ * @param[out] vector2 The Vector2.
+ */
+void StringToVector2(const char* const vectorStr, Length length, Vector2& vector2);
+
+/**
+ * @brief Converts a Vector2 into a string.
+ *
+ * @param[in] value The vector2 value.
+ * @param[out] vector2Str The string.
+ */
+void Vector2ToString(const Vector2& value, std::string& vector2Str);
+
+/**
+ * @brief Converts a string into its value in the enum Text::Underline::Type.
+ *
+ * @param[in] typeStr The underline type value packed inside a string.
+ * @param[in] length The length of the string.
+ * @param[out] retType The Underline type.
+ */
+void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Text::Underline::Type& retType);
+
+/**
+ * @brief Converts a string into a float value.
+ *
+ * @param[in] floatStr A float packed inside a string.
+ *
+ * @return The float value.
+ */
+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
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-paragraph.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessHorizontalAlignment(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
+{
+ boundedParagraphRun.horizontalAlignmentDefined = HorizontalAlignmentTypeStringToTypeValue(attribute.valueBuffer,
+ attribute.valueLength,
+ boundedParagraphRun.horizontalAlignment);
+}
+
+void ProcessRelativeLineHeight(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun)
+{
+ boundedParagraphRun.relativeLineSize = StringToFloat(attribute.valueBuffer);
+ boundedParagraphRun.relativeLineSizeDefined = true;
+}
+
+void ProcessAttributesOfParagraphTag(const Tag& tag, BoundedParagraphRun& boundedParagraphRun)
+{
+ // By default the align attribute is not defined until it's parsed.
+ boundedParagraphRun.horizontalAlignmentDefined = false;
+
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+ if(TokenComparison(MARKUP::PARAGRAPH_ATTRIBUTES::ALIGN, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessHorizontalAlignment(attribute, boundedParagraphRun);
+ }
+ else if(TokenComparison(MARKUP::PARAGRAPH_ATTRIBUTES::RELATIVE_LINE_HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessRelativeLineHeight(attribute, boundedParagraphRun);
+ }
+ }
+}
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#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);
+
+/**
+ * @brief Retrieves the relative line height value from the paragraph tag and sets it to the bounded paragraph run.
+ *
+ * @param[in] attribute the relative line height attribute.
+ * @param[in,out] boundedParagraphRun The bounded paragraph run.
+ */
+void ProcessRelativeLineHeight(const Attribute& attribute, BoundedParagraphRun& boundedParagraphRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_PARAGRAPH_H
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-color.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-character-spacing.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-font.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-strikethrough.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-underline.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessSpanTag(const Tag& tag,
+ ColorRun& colorRun,
+ FontDescriptionRun& fontRun,
+ UnderlinedCharacterRun& underlinedCharacterRun,
+ ColorRun& backgroundColorRun,
+ StrikethroughCharacterRun& strikethroughRun,
+ CharacterSpacingCharacterRun& characterSpacingCharacterRun,
+ bool& isColorDefined,
+ bool& isFontDefined,
+ bool& isUnderlinedCharacterDefined,
+ bool& isBackgroundColorDefined,
+ bool& isStrikethroughDefined,
+ bool& isCharacterSpacingDefined)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+
+ if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::TEXT_COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ isColorDefined = true;
+ ProcessColor(attribute, colorRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::BACKGROUND_COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ isBackgroundColorDefined = true;
+ ProcessColor(attribute, backgroundColorRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_FAMILY, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontFamily(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_SIZE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontSize(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_WEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontWeight(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_WIDTH, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontWidth(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::FONT_SLANT, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontSlant(attribute, fontRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ isUnderlinedCharacterDefined = true;
+ ProcessColorAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ isUnderlinedCharacterDefined = true;
+ ProcessHeightAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_TYPE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isUnderlinedCharacterDefined = true;
+ ProcessTypeAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_DASH_GAP, attribute.nameBuffer, attribute.nameLength))
+ {
+ isUnderlinedCharacterDefined = true;
+ ProcessDashGapAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::UNDERLINE_DASH_WIDTH, attribute.nameBuffer, attribute.nameLength))
+ {
+ isUnderlinedCharacterDefined = true;
+ ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::STRIKETHROUGH_COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ isStrikethroughDefined = true;
+ ProcessColorAttribute(attribute, strikethroughRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::STRIKETHROUGH_HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ isStrikethroughDefined = true;
+ ProcessHeightAttribute(attribute, strikethroughRun);
+ }
+ else if(TokenComparison(MARKUP::SPAN_ATTRIBUTES::CHARACTER_SPACING_VALUE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isCharacterSpacingDefined = true;
+ ProcessValueAttribute(attribute, characterSpacingCharacterRun);
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_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 MarkupProcessData;
+
+/**
+ * @brief process the span from the tag and process all styles in it.
+ *
+ * @param[in] tag The span tag and its attributes.
+ * @param[out] colorRun the color run to be filled.
+ * @param[out] fontRun the font run to be filled.
+ * @param[out] underlinedCharacterRun the underlined character run to be filled.
+ * @param[out] backgroundColorRun the background color run to be filled.
+ * @param[out] strikethroughRun the strikethrough run to be filled.
+ * @param[out] characterSpacingCharacterRun the character-spacing run to be filled.
+ * @param[out] isColorDefined if the span has color defined.
+ * @param[out] isFontDefined if the span has font defined.
+ * @param[out] isUnderlinedCharacterDefined if the span has underlined-character defined.
+ * @param[out] isBackgroundColorDefined if the span has background color defined.
+ * @param[out] isStrikethroughDefined if the span has strikethrough defined.
+ * @param[out] isCharacterSpacingDefined if the span has character-spacing defined.
+ */
+void ProcessSpanTag(const Tag& tag,
+ ColorRun& colorRun,
+ FontDescriptionRun& fontRun,
+ UnderlinedCharacterRun& underlinedCharacterRun,
+ ColorRun& backgroundColorRun,
+ StrikethroughCharacterRun& strikethroughRun,
+ CharacterSpacingCharacterRun& characterSpacingCharacterRun,
+ bool& isColorDefined,
+ bool& isFontDefined,
+ bool& isUnderlinedCharacterDefined,
+ bool& isBackgroundColorDefined,
+ bool& isStrikethroughDefined,
+ bool& isCharacterSpacingDefined);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-strikethrough.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-attribute-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+#include <dali-toolkit/internal/text/strikethrough-character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
+
+{
+ ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, strikethroughRun.properties.color);
+ strikethroughRun.properties.colorDefined = true;
+}
+
+void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
+{
+ strikethroughRun.properties.height = ProcessFloatAttribute(attribute);
+ strikethroughRun.properties.heightDefined = true;
+}
+
+void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+
+ if(TokenComparison(MARKUP::STRIKETHROUGH_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessColorAttribute(attribute, strikethroughRun);
+ }
+ else if(TokenComparison(MARKUP::STRIKETHROUGH_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessHeightAttribute(attribute, strikethroughRun);
+ }
+ }
+}
+
+void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns)
+{
+ // Handle nested tags
+ // The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag.
+ // Example:
+ // <s height='5.0f' color='blue'> outer tag before <s color='green'> inner tag </s> outer tag after </s>
+ // "outer tag before" and "outer tag after" have height = 5.0f and color = 'blue'
+ // "inner tag" has height = 5.0f and color = 'green'
+
+ if(strikethroughCharacterRuns.Count() > 0u)
+ {
+ Vector<StrikethroughCharacterRun>::ConstIterator preIt = strikethroughCharacterRuns.Begin();
+
+ Vector<StrikethroughCharacterRun>::Iterator it = strikethroughCharacterRuns.Begin() + 1;
+ Vector<StrikethroughCharacterRun>::ConstIterator endIt = strikethroughCharacterRuns.End();
+
+ while(it != endIt)
+ {
+ const StrikethroughCharacterRun& run = *it;
+ const CharacterIndex& characterIndex = run.characterRun.characterIndex;
+ const Length& numberOfCharacters = run.characterRun.numberOfCharacters;
+
+ const StrikethroughCharacterRun& preRun = *preIt;
+ const CharacterIndex& preCharacterIndex = preRun.characterRun.characterIndex;
+ const Length& preNumberOfCharacters = preRun.characterRun.numberOfCharacters;
+
+ if((preCharacterIndex <= characterIndex) &&
+ ((characterIndex + numberOfCharacters) <= (preCharacterIndex + preNumberOfCharacters)))
+ {
+ it->properties.CopyIfNotDefined(preIt->properties);
+ }
+
+ it++;
+ preIt++;
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_STRIKETHROUGH_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_STRIKETHROUGH_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/strikethrough-character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct Attribute;
+struct StrikethroughCharacterRun;
+
+/**
+ * @brief Fill the strikethrough character run with the color attribute value.
+ *
+ * @param[in] attribute the color attribute.
+ * @param[out] strikethroughCharacterRun The strikethrough character run
+ */
+void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughCharacterRun);
+
+/**
+ * @brief Fill the strikethrough character run with the height attribute value.
+ *
+ * @param[in] attribute the height attribute.
+ * @param[out] strikethroughRun The strikethrough character run
+ */
+void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun);
+
+/**
+ * @brief Retrieves the strikethrough run info from the tag and sets it to the strikethrough run.
+ *
+ * @param[in] tag The strikethrough tag and its attributes.
+ * @param[in,out] strikethroughRun The strikethrough run.
+ */
+void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun);
+
+/**
+ * @brief Override the run's attributes which contained in the previous run. This is to handle the nested tags.
+ *
+ * @param[in,out] strikethroughCharacterRun The list of strikethrough character run
+ */
+void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_STRIKETHROUGH_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-underline.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-attribute-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const unsigned int MAX_TYPE_ATTRIBUTE_SIZE = 7u; ///< The maximum length of any of the possible 'type' values.
+
+} // namespace
+
+void ProcessTypeAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ underlinedCharacterRun.properties.typeDefined = ProcessEnumerationAttribute<Text::Underline::Type>(attribute,
+ MAX_TYPE_ATTRIBUTE_SIZE,
+ &StringToUnderlineType,
+ underlinedCharacterRun.properties.type);
+}
+
+void ProcessDashGapAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ underlinedCharacterRun.properties.dashGap = ProcessFloatAttribute(attribute);
+ underlinedCharacterRun.properties.dashGapDefined = true;
+}
+
+void ProcessDashWidthAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ underlinedCharacterRun.properties.dashWidth = ProcessFloatAttribute(attribute);
+ underlinedCharacterRun.properties.dashWidthDefined = true;
+}
+void ProcessHeightAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ underlinedCharacterRun.properties.height = ProcessFloatAttribute(attribute);
+ underlinedCharacterRun.properties.heightDefined = true;
+}
+
+void ProcessColorAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, underlinedCharacterRun.properties.color);
+ underlinedCharacterRun.properties.colorDefined = true;
+}
+
+void ProcessUnderlineTag(const Tag& tag, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+
+ if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::COLOR, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessColorAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::HEIGHT, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessHeightAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::TYPE, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessTypeAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::DASH_GAP, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessDashGapAttribute(attribute, underlinedCharacterRun);
+ }
+ else if(TokenComparison(MARKUP::UNDERLINE_ATTRIBUTES::DASH_WIDTH, attribute.nameBuffer, attribute.nameLength))
+ {
+ ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
+ }
+ }
+}
+
+void OverrideNestedUnderlinedCharacterRuns(Vector<UnderlinedCharacterRun>& underlinedCharacterRuns)
+{
+ // Handle nested tags
+ // The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag.
+ // Example:
+ // <u height='5.0f' color='blue'> outer tag before <u color='green'> inner tag </u> outer tag after </u>
+ // "outer tag before" and "outer tag after" have height = 5.0f and color = 'blue'
+ // "inner tag" has height = 5.0f and color = 'green'
+
+ if(underlinedCharacterRuns.Count() > 0u)
+ {
+ Vector<UnderlinedCharacterRun>::ConstIterator preIt = underlinedCharacterRuns.Begin();
+
+ Vector<UnderlinedCharacterRun>::Iterator it = underlinedCharacterRuns.Begin() + 1;
+ Vector<UnderlinedCharacterRun>::ConstIterator endIt = underlinedCharacterRuns.End();
+
+ while(it != endIt)
+ {
+ const UnderlinedCharacterRun& run = *it;
+ const CharacterIndex& characterIndex = run.characterRun.characterIndex;
+ const Length& numberOfCharacters = run.characterRun.numberOfCharacters;
+
+ const UnderlinedCharacterRun& preRun = *preIt;
+ const CharacterIndex& preCharacterIndex = preRun.characterRun.characterIndex;
+ const Length& preNumberOfCharacters = preRun.characterRun.numberOfCharacters;
+
+ if((preCharacterIndex <= characterIndex) &&
+ ((characterIndex + numberOfCharacters) <= (preCharacterIndex + preNumberOfCharacters)))
+ {
+ it->properties.CopyIfNotDefined(preIt->properties);
+ }
+
+ it++;
+ preIt++;
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/underlined-character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct Attribute;
+
+/**
+ * @brief Fill the underlined character run with the type attribute value.
+ *
+ * @param[in] attribute the type attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessTypeAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the dash-gap attribute value.
+ *
+ * @param[in] attribute the dash-gap attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessDashGapAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the dash-width attribute value.
+ *
+ * @param[in] attribute the dash-width attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessDashWidthAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the height attribute value.
+ *
+ * @param[in] attribute the height attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessHeightAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the color attribute value.
+ *
+ * @param[in] attribute the color attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessColorAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Retrieves the underline run info from the tag and sets it to the underline run.
+ *
+ * @param[in] tag The underline tag and its attributes.
+ * @param[in,out] underlinedCharacterRun The underlined character run
+ */
+void ProcessUnderlineTag(const Tag& tag, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Override the run's attributes which contained in the previous run. This is to handle the nested tags.
+ *
+ * @param[in,out] underlinedCharacterRuns The list of underlined character run
+ */
+void OverrideNestedUnderlinedCharacterRuns(Vector<UnderlinedCharacterRun>& underlinedCharacterRuns);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <climits> // for ULONG_MAX
+#include <functional>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-background.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-character-spacing.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-color.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-embedded-item.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-font.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-paragraph.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-span.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-strikethrough.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-underline.h>
+#include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
+#include <dali-toolkit/internal/text/xhtml-entities.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const char LESS_THAN = '<';
+const char GREATER_THAN = '>';
+const char EQUAL = '=';
+const char QUOTATION_MARK = '\'';
+const char SLASH = '/';
+const char BACK_SLASH = '\\';
+const char AMPERSAND = '&';
+const char HASH = '#';
+const char SEMI_COLON = ';';
+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
+// Range 3 0x10000u < XHTML_DECIMAL_ENTITY_RANGE <= 0x10FFFFu
+const unsigned long XHTML_DECIMAL_ENTITY_RANGE[] = {0x0u, 0xD7FFu, 0xE000u, 0xFFFDu, 0x10000u, 0x10FFFFu};
+
+// The MAX_NUM_OF_ATTRIBUTES is the number of attributes in span tag "markup-processor-span.cpp". Because it contains the maximum number of attributes in all tags.
+const unsigned int MAX_NUM_OF_ATTRIBUTES = 14u; ///< The span tag has the 'font-family', 'font-size' 'font-weight', 'font-width', 'font-slant','text-color', 'u-color', 'u-height','u-type','u-dash-gap', 'u-dash-width', 's-color', 's-height' and 'char-space-value' attrubutes.
+const unsigned int DEFAULT_VECTOR_SIZE = 16u; ///< Default size of run vectors.
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MARKUP_PROCESSOR");
+#endif
+
+typedef VectorBase::SizeType RunIndex;
+
+/**
+ * @brief Struct used to retrieve the style runs from the mark-up string.
+ */
+template<typename StyleStackType>
+struct StyleStack
+{
+ Vector<StyleStackType> stack; ///< Use a vector as a style stack.
+ unsigned int topIndex; ///< Points the top of the stack.
+
+ StyleStack()
+ : stack(),
+ topIndex(0u)
+ {
+ stack.Resize(DEFAULT_VECTOR_SIZE);
+ }
+
+ void Push(StyleStackType item)
+ {
+ // Check if there is space inside the style stack.
+ const VectorBase::SizeType size = stack.Count();
+ if(topIndex >= size)
+ {
+ // Resize the style stack.
+ stack.Resize(2u * size);
+ }
+
+ // Set the item in the top of the stack.
+ *(stack.Begin() + topIndex) = item;
+
+ // Reposition the pointer to the top of the stack.
+ ++topIndex;
+ }
+
+ StyleStackType Pop()
+ {
+ // Pop the top of the stack.
+ --topIndex;
+ return *(stack.Begin() + topIndex);
+ }
+};
+
+/**
+ * @brief Struct used to retrieve spans from the mark-up string.
+ */
+struct Span
+{
+ RunIndex colorRunIndex;
+ RunIndex fontRunIndex;
+ RunIndex underlinedCharacterRunIndex;
+ RunIndex backgroundColorRunIndex;
+ RunIndex strikethroughCharacterRunIndex;
+ RunIndex characterSpacingCharacterRunIndex;
+
+ bool isColorDefined;
+ bool isFontDefined;
+ bool isUnderlinedCharacterDefined;
+ bool isBackgroundColorDefined;
+ bool isStrikethroughDefined;
+ bool isCharacterSpacingDefined;
+};
+
+/**
+ * @brief Initializes a font run description to its defaults.
+ *
+ * @param[in,out] fontRun The font description run to initialize.
+ */
+void Initialize(FontDescriptionRun& fontRun)
+{
+ fontRun.characterRun.characterIndex = 0u;
+ fontRun.characterRun.numberOfCharacters = 0u;
+ fontRun.familyName = NULL;
+ fontRun.familyLength = 0u;
+ fontRun.weight = TextAbstraction::FontWeight::NORMAL;
+ fontRun.width = TextAbstraction::FontWidth::NORMAL;
+ fontRun.slant = TextAbstraction::FontSlant::NORMAL;
+ fontRun.size = 0u;
+ fontRun.familyDefined = false;
+ fontRun.weightDefined = false;
+ fontRun.widthDefined = false;
+ fontRun.slantDefined = false;
+ fontRun.sizeDefined = false;
+}
+
+/**
+ * @brief Initializes a color run description to its defaults.
+ *
+ * @param[in,out] colorRun The font description run to initialize.
+ */
+void Initialize(ColorRun& colorRun)
+{
+ colorRun.characterRun.characterIndex = 0u;
+ colorRun.characterRun.numberOfCharacters = 0u;
+}
+
+/**
+ * @brief Initializes a underlined character run to its defaults.
+ *
+ * @param[in,out] underlinedCharacterRun The underelined character run to initialize.
+ */
+void Initialize(UnderlinedCharacterRun& underlinedCharacterRun)
+{
+ underlinedCharacterRun.characterRun.characterIndex = 0u;
+ underlinedCharacterRun.characterRun.numberOfCharacters = 0u;
+}
+
+/**
+ * @brief Initializes a span to its defaults.
+ *
+ * @param[in,out] span The span to be initialized.
+ */
+void Initialize(Span& span)
+{
+ span.colorRunIndex = 0u;
+ span.isColorDefined = false;
+
+ span.fontRunIndex = 0u;
+ span.isFontDefined = false;
+
+ span.underlinedCharacterRunIndex = 0u;
+ span.isUnderlinedCharacterDefined = false;
+ span.backgroundColorRunIndex = 0u;
+ span.isBackgroundColorDefined = false;
+
+ //strikethrough
+ span.strikethroughCharacterRunIndex = 0u;
+ span.isStrikethroughDefined = false;
+
+ //characterSpacing
+ span.characterSpacingCharacterRunIndex = 0u;
+ span.isCharacterSpacingDefined = false;
+}
+
+/**
+ * @brief Initializes a strikethrough character run to its defaults.
+ *
+ * @param[in,out] strikethroughCharacterRun The strikethrough character run to initialize.
+ */
+void Initialize(StrikethroughCharacterRun& strikethroughCharacterRun)
+{
+ strikethroughCharacterRun.characterRun.characterIndex = 0u;
+ strikethroughCharacterRun.characterRun.numberOfCharacters = 0u;
+ strikethroughCharacterRun.properties.colorDefined = false;
+}
+
+/**
+ * @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 Initializes a character-spacing run to its defaults.
+ *
+ * @param[in,out] characterSpacingCharacterRun The character-spacing run to initialize.
+ */
+void Initialize(CharacterSpacingCharacterRun& characterSpacingCharacterRun)
+{
+ characterSpacingCharacterRun.characterRun.characterIndex = 0u;
+ characterSpacingCharacterRun.characterRun.numberOfCharacters = 0u;
+ characterSpacingCharacterRun.value = 0.0f;
+}
+
+/**
+ * @brief Splits the tag string into the tag name and its attributes.
+ *
+ * The attributes are stored in a vector in the tag.
+ *
+ * @param[in,out] tag The tag.
+ */
+void ParseAttributes(Tag& tag)
+{
+ if(tag.buffer == NULL)
+ {
+ return;
+ }
+
+ tag.attributes.Resize(MAX_NUM_OF_ATTRIBUTES);
+
+ // Find first the tag name.
+ bool isQuotationOpen = false;
+
+ const char* tagBuffer = tag.buffer;
+ const char* const tagEndBuffer = tagBuffer + tag.length;
+ tag.length = 0u;
+ for(; tagBuffer < tagEndBuffer; ++tagBuffer)
+ {
+ const char character = *tagBuffer;
+ if(WHITE_SPACE < character)
+ {
+ ++tag.length;
+ }
+ else
+ {
+ // Stops counting the length of the tag when a white space is found.
+ // @note a white space is the WHITE_SPACE character and anything below as 'tab', 'return' or 'control characters'.
+ break;
+ }
+ }
+ SkipWhiteSpace(tagBuffer, tagEndBuffer);
+
+ // Find the attributes.
+ unsigned int attributeIndex = 0u;
+ const char* nameBuffer = NULL;
+ const char* valueBuffer = NULL;
+ Length nameLength = 0u;
+ Length valueLength = 0u;
+
+ bool addToNameValue = true;
+ Length numberOfWhiteSpace = 0u;
+ for(; tagBuffer < tagEndBuffer; ++tagBuffer)
+ {
+ const char character = *tagBuffer;
+ if((WHITE_SPACE >= character) && !isQuotationOpen)
+ {
+ if(NULL != valueBuffer)
+ {
+ // Remove white spaces at the end of the value.
+ valueLength -= numberOfWhiteSpace;
+ }
+
+ if((NULL != nameBuffer) && (NULL != valueBuffer))
+ {
+ // Every time a white space is found, a new attribute is created and stored in the attributes vector.
+ Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
+ ++attributeIndex;
+
+ attribute.nameBuffer = nameBuffer;
+ attribute.valueBuffer = valueBuffer;
+ attribute.nameLength = nameLength;
+ attribute.valueLength = valueLength;
+
+ nameBuffer = NULL;
+ valueBuffer = NULL;
+ nameLength = 0u;
+ valueLength = 0u;
+
+ addToNameValue = true; // next read characters will be added to the name.
+ }
+ }
+ else if(EQUAL == character) // '='
+ {
+ addToNameValue = false; // next read characters will be added to the value.
+ SkipWhiteSpace(tagBuffer, tagEndBuffer);
+ }
+ else if(QUOTATION_MARK == character) // '\''
+ {
+ // Do not add quotation marks to neither name nor value.
+ isQuotationOpen = !isQuotationOpen;
+
+ if(isQuotationOpen)
+ {
+ ++tagBuffer;
+ SkipWhiteSpace(tagBuffer, tagEndBuffer);
+ --tagBuffer;
+ }
+ }
+ else
+ {
+ // Adds characters to the name or the value.
+ if(addToNameValue)
+ {
+ if(NULL == nameBuffer)
+ {
+ nameBuffer = tagBuffer;
+ }
+ ++nameLength;
+ }
+ else
+ {
+ if(isQuotationOpen)
+ {
+ if(WHITE_SPACE >= character)
+ {
+ ++numberOfWhiteSpace;
+ }
+ else
+ {
+ numberOfWhiteSpace = 0u;
+ }
+ }
+ if(NULL == valueBuffer)
+ {
+ valueBuffer = tagBuffer;
+ }
+ ++valueLength;
+ }
+ }
+ }
+
+ if(NULL != valueBuffer)
+ {
+ // Remove white spaces at the end of the value.
+ valueLength -= numberOfWhiteSpace;
+ }
+
+ if((NULL != nameBuffer) && (NULL != valueBuffer))
+ {
+ // Checks if the last attribute needs to be added.
+ Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
+ ++attributeIndex;
+
+ attribute.nameBuffer = nameBuffer;
+ attribute.valueBuffer = valueBuffer;
+ attribute.nameLength = nameLength;
+ attribute.valueLength = valueLength;
+ }
+
+ // Resize the vector of attributes.
+ tag.attributes.Resize(attributeIndex);
+}
+
+/**
+ * @brief It parses a tag and its attributes if the given iterator @e it is pointing at a tag beginning.
+ *
+ * @param[in,out] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
+ * @param[in] markupStringEndBuffer Pointer to one character after the end of the mark-up string buffer.
+ * @param[out] tag The tag with its attributes.
+ *
+ * @return @e true if the iterator @e it is pointing a mark-up tag. Otherwise @e false.
+ */
+bool IsTag(const char*& markupStringBuffer,
+ const char* const markupStringEndBuffer,
+ Tag& tag)
+{
+ bool isTag = false;
+ bool isQuotationOpen = false;
+ bool attributesFound = false;
+ tag.isEndTag = false;
+ bool isPreviousLessThan = false;
+ bool isPreviousSlash = false;
+
+ const char character = *markupStringBuffer;
+ if(LESS_THAN == character) // '<'
+ {
+ tag.buffer = NULL;
+ tag.length = 0u;
+ isPreviousLessThan = true;
+
+ // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed.
+ ++markupStringBuffer;
+ if(markupStringBuffer < markupStringEndBuffer)
+ {
+ SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
+
+ for(; (!isTag) && (markupStringBuffer < markupStringEndBuffer); ++markupStringBuffer)
+ {
+ const char character = *markupStringBuffer;
+
+ if(!isQuotationOpen && (SLASH == character)) // '/'
+ {
+ if(isPreviousLessThan)
+ {
+ tag.isEndTag = true;
+ }
+ else
+ {
+ // if the tag has a '/' it may be an end tag.
+ isPreviousSlash = true;
+ }
+
+ isPreviousLessThan = false;
+ if((markupStringBuffer + 1u < markupStringEndBuffer) && (WHITE_SPACE >= *(markupStringBuffer + 1u)))
+ {
+ ++markupStringBuffer;
+ SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
+ --markupStringBuffer;
+ }
+ }
+ else if(GREATER_THAN == character) // '>'
+ {
+ isTag = true;
+ if(isPreviousSlash)
+ {
+ tag.isEndTag = true;
+ }
+
+ isPreviousSlash = false;
+ isPreviousLessThan = false;
+ }
+ else if(QUOTATION_MARK == character)
+ {
+ isQuotationOpen = !isQuotationOpen;
+ ++tag.length;
+
+ isPreviousSlash = false;
+ isPreviousLessThan = false;
+ }
+ else if(WHITE_SPACE >= character) // ' '
+ {
+ // If the tag contains white spaces then it may have attributes.
+ if(!isQuotationOpen)
+ {
+ attributesFound = true;
+ }
+ ++tag.length;
+ }
+ else
+ {
+ if(NULL == tag.buffer)
+ {
+ tag.buffer = markupStringBuffer;
+ }
+
+ // If it's not any of the 'special' characters then just add it to the tag string.
+ ++tag.length;
+
+ isPreviousSlash = false;
+ isPreviousLessThan = false;
+ }
+ }
+ }
+
+ // If the tag string has white spaces, then parse the attributes is needed.
+ if(attributesFound)
+ {
+ ParseAttributes(tag);
+ }
+ }
+
+ return isTag;
+}
+
+/**
+ * @brief Returns length of XHTML entity by parsing the text. It also determines if it is XHTML entity or not.
+ *
+ * @param[in] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
+ * @param[in] markupStringEndBuffer Pointing to end of mark-up string buffer.
+ *
+ * @return Length of markupText in case of XHTML entity otherwise return 0.
+ */
+unsigned int GetXHTMLEntityLength(const char*& markupStringBuffer,
+ const char* const markupStringEndBuffer)
+{
+ char character = *markupStringBuffer;
+ if(AMPERSAND == character) // '&'
+ {
+ // if the iterator is pointing to a '&' character, then check for ';' to find end to XHTML entity.
+ ++markupStringBuffer;
+ if(markupStringBuffer < markupStringEndBuffer)
+ {
+ unsigned int len = 1u;
+ for(; markupStringBuffer < markupStringEndBuffer; ++markupStringBuffer)
+ {
+ character = *markupStringBuffer;
+ ++len;
+ if(SEMI_COLON == character) // ';'
+ {
+ // found end of XHTML entity
+ ++markupStringBuffer;
+ return len;
+ }
+ else if((AMPERSAND == character) || (BACK_SLASH == character) || (LESS_THAN == character))
+ {
+ return 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief It parses a XHTML string which has hex/decimal entity and fill its corresponging utf-8 string.
+ *
+ * @param[in] markupText The mark-up text buffer.
+ * @param[out] utf-8 text Corresponding to markup Text
+ *
+ * @return true if string is successfully parsed otherwise false
+ */
+bool XHTMLNumericEntityToUtf8(const char* markupText, char* utf8)
+{
+ bool result = false;
+
+ if(NULL != markupText)
+ {
+ bool isHex = false;
+
+ // check if hex or decimal entity
+ if((CHAR_ARRAY_END != *markupText) && (HEX_CODE == *markupText))
+ {
+ isHex = true;
+ ++markupText;
+ }
+
+ char* end = NULL;
+ unsigned long l = strtoul(markupText, &end, (isHex ? 16 : 10)); // l contains UTF-32 code in case of correct XHTML entity
+
+ // check for valid XHTML numeric entities (between '#' or "#x" and ';')
+ if((l > 0) && (l < ULONG_MAX) && (*end == SEMI_COLON)) // in case wrong XHTML entity is set eg. "abcdefs;" in that case *end will be 'a'
+ {
+ /* characters XML 1.1 permits */
+ if(((XHTML_DECIMAL_ENTITY_RANGE[0] < l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[1])) ||
+ ((XHTML_DECIMAL_ENTITY_RANGE[2] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[3])) ||
+ ((XHTML_DECIMAL_ENTITY_RANGE[4] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[5])))
+ {
+ // Convert UTF32 code to UTF8
+ Utf32ToUtf8(reinterpret_cast<const uint32_t* const>(&l), 1, reinterpret_cast<uint8_t*>(utf8));
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * @brief Processes a particular tag for the required run (color-run, font-run or underlined-character-run).
+ *
+ * @tparam RunType Whether ColorRun , FontDescriptionRun or UnderlinedCharacterRun
+ *
+ * @param[in/out] runsContainer The container containing all the runs
+ * @param[in/out] styleStack The style stack
+ * @param[in] tag The tag we are currently processing
+ * @param[in] characterIndex The current character index
+ * @param[in/out] runIndex The run index
+ * @param[in/out] tagReference The tagReference we should increment/decrement
+ * @param[in] parameterSettingFunction This function will be called to set run specific parameters
+ */
+template<typename RunType>
+void ProcessTagForRun(
+ Vector<RunType>& runsContainer,
+ StyleStack<RunIndex>& styleStack,
+ const Tag& tag,
+ const CharacterIndex characterIndex,
+ RunIndex& runIndex,
+ int& tagReference,
+ std::function<void(const Tag&, RunType&)> parameterSettingFunction)
+{
+ if(!tag.isEndTag)
+ {
+ // Create a new run.
+ RunType run;
+ Initialize(run);
+
+ // Fill the run with the parameters.
+ run.characterRun.characterIndex = characterIndex;
+ parameterSettingFunction(tag, run);
+
+ // Push the run in the logical model.
+ runsContainer.PushBack(run);
+
+ // Push the index of the run into the stack.
+ styleStack.Push(runIndex);
+
+ // Point the next free run.
+ ++runIndex;
+
+ // Increase reference
+ ++tagReference;
+ }
+ else
+ {
+ if(tagReference > 0)
+ {
+ // Pop the top of the stack and set the number of characters of the run.
+ RunType& run = *(runsContainer.Begin() + styleStack.Pop());
+ run.characterRun.numberOfCharacters = characterIndex - run.characterRun.characterIndex;
+ --tagReference;
+ }
+ }
+}
+
+/**
+ * @brief Processes the item tag
+ *
+ * @param[in/out] markupProcessData The markup process data
+ * @param[in] tag The current tag
+ * @param[in/out] characterIndex The current character index
+ */
+void ProcessItemTag(
+ MarkupProcessData& markupProcessData,
+ const Tag tag,
+ CharacterIndex& characterIndex)
+{
+ if(tag.isEndTag)
+ {
+ // Create an embedded item instance.
+ EmbeddedItem item;
+ item.characterIndex = characterIndex;
+ ProcessEmbeddedItem(tag, item);
+
+ markupProcessData.items.PushBack(item);
+
+ // Insert white space character that will be replaced by the item.
+ markupProcessData.markupProcessedText.append(1u, WHITE_SPACE);
+ ++characterIndex;
+ }
+}
+
+/**
+ * @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
+ * @param[in] tag The current tag
+ * @param[in/out] characterIndex The current character index
+ */
+void ProcessAnchorTag(
+ MarkupProcessData& markupProcessData,
+ const Tag tag,
+ CharacterIndex& characterIndex)
+{
+ if(!tag.isEndTag)
+ {
+ // Create an anchor instance.
+ Anchor anchor;
+ anchor.startIndex = characterIndex;
+ anchor.endIndex = 0u;
+ ProcessAnchor(tag, anchor);
+ markupProcessData.anchors.PushBack(anchor);
+ }
+ else
+ {
+ // Update end index.
+ unsigned int count = markupProcessData.anchors.Count();
+ if(count > 0)
+ {
+ markupProcessData.anchors[count - 1].endIndex = characterIndex;
+ }
+ }
+}
+
+/**
+ * @brief Processes span tag for the color-run & font-run.
+ *
+ * @param[in] spanTag The tag we are currently processing
+ * @param[inout] spanStack The spans stack
+ * @param[inout] colorRuns The container containing all the color runs
+ * @param[inout] fontRuns The container containing all the font description runs
+ * @param[inout] underlinedCharacterRuns The container containing all the underlined character runs
+ * @param[inout] strikethroughCharacterRuns The container containing all the strikethroughed character runs
+ * @param[inout] colorRunIndex The color run index
+ * @param[inout] fontRunIndex The font run index
+ * @param[inout] underlinedCharacterRunIndex The underlined character run index
+ * @param[inout] strikethroughCharacterRunIndex The strikethroughed character run index
+ * @param[in] characterIndex The current character index
+ * @param[in] tagReference The tagReference we should increment/decrement
+ */
+void ProcessSpanForRun(
+ const Tag& spanTag,
+ StyleStack<Span>& spanStack,
+ Vector<ColorRun>& colorRuns,
+ Vector<FontDescriptionRun>& fontRuns,
+ Vector<UnderlinedCharacterRun>& underlinedCharacterRuns,
+ Vector<ColorRun>& backgroundColorRuns,
+ Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns,
+ Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns,
+ RunIndex& colorRunIndex,
+ RunIndex& fontRunIndex,
+ RunIndex& underlinedCharacterRunIndex,
+ RunIndex& backgroundColorRunIndex,
+ RunIndex& strikethroughCharacterRunIndex,
+ RunIndex& characterSpacingCharacterRunIndex,
+ const CharacterIndex characterIndex,
+ int& tagReference)
+{
+ if(!spanTag.isEndTag)
+ {
+ // Create a new run.
+ ColorRun colorRun;
+ Initialize(colorRun);
+
+ FontDescriptionRun fontRun;
+ Initialize(fontRun);
+
+ UnderlinedCharacterRun underlinedCharacterRun;
+ Initialize(underlinedCharacterRun);
+
+ ColorRun backgroundColorRun;
+ Initialize(backgroundColorRun);
+
+ StrikethroughCharacterRun strikethroughCharacterRun;
+ Initialize(strikethroughCharacterRun);
+
+ CharacterSpacingCharacterRun characterSpacingCharacterRun;
+ Initialize(characterSpacingCharacterRun);
+
+ Span span;
+ Initialize(span);
+
+ // Fill the run with the parameters.
+ colorRun.characterRun.characterIndex = characterIndex;
+ fontRun.characterRun.characterIndex = characterIndex;
+ underlinedCharacterRun.characterRun.characterIndex = characterIndex;
+ backgroundColorRun.characterRun.characterIndex = characterIndex;
+ strikethroughCharacterRun.characterRun.characterIndex = characterIndex;
+ characterSpacingCharacterRun.characterRun.characterIndex = characterIndex;
+
+ span.colorRunIndex = colorRunIndex;
+ span.fontRunIndex = fontRunIndex;
+ span.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
+ span.backgroundColorRunIndex = backgroundColorRunIndex;
+ span.strikethroughCharacterRunIndex = strikethroughCharacterRunIndex;
+ span.characterSpacingCharacterRunIndex = characterSpacingCharacterRunIndex;
+
+ ProcessSpanTag(spanTag,
+ colorRun,
+ fontRun,
+ underlinedCharacterRun,
+ backgroundColorRun,
+ strikethroughCharacterRun,
+ characterSpacingCharacterRun,
+ span.isColorDefined,
+ span.isFontDefined,
+ span.isUnderlinedCharacterDefined,
+ span.isBackgroundColorDefined,
+ span.isStrikethroughDefined,
+ span.isCharacterSpacingDefined);
+
+ // Push the span into the stack.
+ spanStack.Push(span);
+
+ // Point the next free run.
+ if(span.isColorDefined)
+ {
+ // Push the run in the logical model.
+ colorRuns.PushBack(colorRun);
+ ++colorRunIndex;
+ }
+
+ if(span.isFontDefined)
+ {
+ // Push the run in the logical model.
+ fontRuns.PushBack(fontRun);
+ ++fontRunIndex;
+ }
+
+ if(span.isUnderlinedCharacterDefined)
+ {
+ // Push the run in the logical model.
+ underlinedCharacterRuns.PushBack(underlinedCharacterRun);
+ ++underlinedCharacterRunIndex;
+ }
+
+ if(span.isBackgroundColorDefined)
+ {
+ // Push the run in the logical model.
+ backgroundColorRuns.PushBack(backgroundColorRun);
+ ++backgroundColorRunIndex;
+ }
+
+ if(span.isStrikethroughDefined)
+ {
+ // Push the run in the logical model.
+ strikethroughCharacterRuns.PushBack(strikethroughCharacterRun);
+ ++strikethroughCharacterRunIndex;
+ }
+
+ if(span.isCharacterSpacingDefined)
+ {
+ // Push the run in the logical model.
+ characterSpacingCharacterRuns.PushBack(characterSpacingCharacterRun);
+ ++characterSpacingCharacterRunIndex;
+ }
+
+ // Increase reference
+ ++tagReference;
+ }
+ else
+ {
+ if(tagReference > 0)
+ {
+ // Pop the top of the stack and set the number of characters of the run.
+ Span span = spanStack.Pop();
+
+ if(span.isColorDefined)
+ {
+ ColorRun& colorRun = *(colorRuns.Begin() + span.colorRunIndex);
+ colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
+ }
+
+ if(span.isFontDefined)
+ {
+ FontDescriptionRun& fontRun = *(fontRuns.Begin() + span.fontRunIndex);
+ fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
+ }
+
+ if(span.isUnderlinedCharacterDefined)
+ {
+ UnderlinedCharacterRun& underlinedCharacterRun = *(underlinedCharacterRuns.Begin() + span.underlinedCharacterRunIndex);
+ underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
+ }
+
+ if(span.isBackgroundColorDefined)
+ {
+ ColorRun& backgroundColorRun = *(backgroundColorRuns.Begin() + span.backgroundColorRunIndex);
+ backgroundColorRun.characterRun.numberOfCharacters = characterIndex - backgroundColorRun.characterRun.characterIndex;
+ }
+
+ if(span.isStrikethroughDefined)
+ {
+ StrikethroughCharacterRun& strikethroughCharacterRun = *(strikethroughCharacterRuns.Begin() + span.strikethroughCharacterRunIndex);
+ strikethroughCharacterRun.characterRun.numberOfCharacters = characterIndex - strikethroughCharacterRun.characterRun.characterIndex;
+ }
+
+ if(span.isCharacterSpacingDefined)
+ {
+ CharacterSpacingCharacterRun& characterSpacingCharacterRun = *(characterSpacingCharacterRuns.Begin() + span.characterSpacingCharacterRunIndex);
+ characterSpacingCharacterRun.characterRun.numberOfCharacters = characterIndex - characterSpacingCharacterRun.characterRun.characterIndex;
+ }
+
+ --tagReference;
+ }
+ }
+}
+
+/**
+ * @brief Resizes the model's vectors
+ *
+ * @param[inout] markupProcessData The markup process data
+ * @param[in] fontRunIndex The font run index
+ * @param[in] colorRunIndex The color run index
+ * @param[in] underlinedCharacterRunIndex The underlined character run index
+ * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
+ * @param[in] backgroundRunIndex The background run index
+ * @param[in] boundedParagraphRunIndex The bounded paragraph run index
+ * @param[in] characterSpacingCharacterRunIndex The character-spacing character run index
+ *
+ */
+void ResizeModelVectors(MarkupProcessData& markupProcessData,
+ const RunIndex fontRunIndex,
+ const RunIndex colorRunIndex,
+ const RunIndex underlinedCharacterRunIndex,
+ const RunIndex strikethroughCharacterRunIndex,
+ const RunIndex backgroundRunIndex,
+ const RunIndex boundedParagraphRunIndex,
+ const RunIndex characterSpacingCharacterRunIndex)
+{
+ markupProcessData.fontRuns.Resize(fontRunIndex);
+ markupProcessData.colorRuns.Resize(colorRunIndex);
+ markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
+ markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
+ markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
+ markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
+ markupProcessData.characterSpacingCharacterRuns.Resize(characterSpacingCharacterRunIndex);
+
+#ifdef DEBUG_ENABLED
+ if(gLogFilter->IsEnabledFor(Debug::Verbose))
+ {
+ for(uint32_t i = 0; i < colorRunIndex; ++i)
+ {
+ ColorRun& run = markupProcessData.colorRuns[i];
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "run[%d] index: %d, length: %d, color %f,%f,%f,%f\n", i, run.characterRun.characterIndex, run.characterRun.numberOfCharacters, run.color.r, run.color.g, run.color.b, run.color.a);
+ }
+ }
+#endif
+}
+
+/**
+ * @brief Processes the markup string buffer
+ *
+ * @param[in/out] markupProcessData The markup process data
+ * @param[in/out] markupStringBuffer The markup string buffer pointer
+ * @param[in] markupStringEndBuffer The markup string end buffer pointer
+ * @param[in/out] characterIndex The current character index
+ */
+void ProcessMarkupStringBuffer(
+ MarkupProcessData& markupProcessData,
+ const char*& markupStringBuffer,
+ const char* const markupStringEndBuffer,
+ CharacterIndex& characterIndex)
+{
+ unsigned char character = *markupStringBuffer;
+ const char* markupBuffer = markupStringBuffer;
+ unsigned char count = GetUtf8Length(character);
+ char utf8[8];
+
+ if((BACK_SLASH == character) && (markupStringBuffer + 1u < markupStringEndBuffer))
+ {
+ // Adding < , > or & special character.
+ const unsigned char nextCharacter = *(markupStringBuffer + 1u);
+ if((LESS_THAN == nextCharacter) || (GREATER_THAN == nextCharacter) || (AMPERSAND == nextCharacter))
+ {
+ character = nextCharacter;
+ ++markupStringBuffer;
+
+ count = GetUtf8Length(character);
+ markupBuffer = markupStringBuffer;
+ }
+ }
+ else // checking if contains XHTML entity or not
+ {
+ const unsigned int len = GetXHTMLEntityLength(markupStringBuffer, markupStringEndBuffer);
+
+ // Parse markupStringTxt if it contains XHTML Entity between '&' and ';'
+ if(len > 0)
+ {
+ char* entityCode = NULL;
+ bool result = false;
+ count = 0;
+
+ // Checking if XHTML Numeric Entity
+ if(HASH == *(markupBuffer + 1u))
+ {
+ entityCode = &utf8[0];
+ // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#'
+ result = XHTMLNumericEntityToUtf8((markupBuffer + 2u), entityCode);
+ }
+ else // Checking if XHTML Named Entity
+ {
+ entityCode = const_cast<char*>(NamedEntityToUtf8(markupBuffer, len));
+ result = (entityCode != NULL);
+ }
+ if(result)
+ {
+ markupBuffer = entityCode; //utf8 text assigned to markupBuffer
+ character = markupBuffer[0];
+ }
+ else
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer);
+ markupBuffer = NULL;
+ }
+ }
+ else // in case string conatins Start of XHTML Entity('&') but not its end character(';')
+ {
+ if(character == AMPERSAND)
+ {
+ markupBuffer = NULL;
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n");
+ }
+ }
+ }
+
+ if(markupBuffer != NULL)
+ {
+ const unsigned char numberOfBytes = GetUtf8Length(character);
+ markupProcessData.markupProcessedText.push_back(character);
+
+ for(unsigned char i = 1u; i < numberOfBytes; ++i)
+ {
+ ++markupBuffer;
+ markupProcessData.markupProcessedText.push_back(*markupBuffer);
+ }
+
+ ++characterIndex;
+ markupStringBuffer += count;
+ }
+}
+
+} // namespace
+
+void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData)
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str());
+
+ // Reserve space for the plain text.
+ const Length markupStringSize = markupString.size();
+ markupProcessData.markupProcessedText.reserve(markupStringSize);
+
+ // Stores a struct with the index to the first character of the run, the type of run and its parameters.
+ StyleStack<RunIndex> styleStack;
+
+ // Stores a struct with the index to the first character of the color run & color font for the span.
+ StyleStack<Span> spanStack;
+
+ // Points the next free position in the vector of runs.
+ RunIndex colorRunIndex = 0u;
+ RunIndex fontRunIndex = 0u;
+ RunIndex underlinedCharacterRunIndex = 0u;
+ RunIndex backgroundRunIndex = 0u;
+ RunIndex strikethroughCharacterRunIndex = 0u;
+ RunIndex boundedParagraphRunIndex = 0u;
+ RunIndex characterSpacingCharacterRunIndex = 0u;
+
+ // check tag reference
+ int colorTagReference = 0u;
+ int fontTagReference = 0u;
+ int iTagReference = 0u;
+ int bTagReference = 0u;
+ int uTagReference = 0u;
+ int backgroundTagReference = 0u;
+ int spanTagReference = 0u;
+ int sTagReference = 0u;
+ int pTagReference = 0u;
+ int characterSpacingTagReference = 0u;
+
+ // Give an initial default value to the model's vectors.
+ markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
+ markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
+ markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
+ markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
+ markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
+ markupProcessData.characterSpacingCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
+
+ // Get the mark-up string buffer.
+ const char* markupStringBuffer = markupString.c_str();
+ const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
+
+ Tag tag;
+ CharacterIndex characterIndex = 0u;
+ for(; markupStringBuffer < markupStringEndBuffer;)
+ {
+ tag.attributes.Clear();
+ if(IsTag(markupStringBuffer,
+ markupStringEndBuffer,
+ tag))
+ {
+ if(TokenComparison(MARKUP::TAG::COLOR, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<ColorRun>(
+ markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) { ProcessColorTag(tag, run); });
+ } // <color></color>
+ else if(TokenComparison(MARKUP::TAG::ITALIC, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<FontDescriptionRun>(
+ markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, iTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
+ fontRun.slant = TextAbstraction::FontSlant::ITALIC;
+ fontRun.slantDefined = true;
+ });
+ } // <i></i>
+ else if(TokenComparison(MARKUP::TAG::UNDERLINE, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<UnderlinedCharacterRun>(
+ markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { ProcessUnderlineTag(tag, run); });
+ } // <u></u>
+ else if(TokenComparison(MARKUP::TAG::BOLD, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<FontDescriptionRun>(
+ markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, bTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
+ fontRun.weight = TextAbstraction::FontWeight::BOLD;
+ fontRun.weightDefined = true;
+ });
+ } // <b></b>
+ else if(TokenComparison(MARKUP::TAG::FONT, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<FontDescriptionRun>(
+ markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, fontTagReference, [](const Tag& tag, FontDescriptionRun& fontRun) { ProcessFontTag(tag, fontRun); });
+ } // <font></font>
+ else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length))
+ {
+ /* Anchor */
+ ProcessAnchorTag(markupProcessData, tag, characterIndex);
+ /* Color */
+ ProcessTagForRun<ColorRun>(
+ markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) {
+ run.color = Color::BLUE;
+ ProcessColorTag(tag, run);
+ });
+ /* Underline */
+ ProcessTagForRun<UnderlinedCharacterRun>(
+ markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) {
+ run.properties.color = Color::BLUE;
+ run.properties.colorDefined = true;
+ ProcessUnderlineTag(tag, run);
+ });
+ } // <a href=https://www.tizen.org>tizen</a>
+ else if(TokenComparison(MARKUP::TAG::SHADOW, tag.buffer, tag.length))
+ {
+ // TODO: If !tag.isEndTag, then create a new shadow run.
+ // else Pop the top of the stack and set the number of characters of the run.
+ } // <shadow></shadow>
+ else if(TokenComparison(MARKUP::TAG::GLOW, tag.buffer, tag.length))
+ {
+ // TODO: If !tag.isEndTag, then create a new glow run.
+ // else Pop the top of the stack and set the number of characters of the run.
+ } // <glow></glow>
+ else if(TokenComparison(MARKUP::TAG::OUTLINE, tag.buffer, tag.length))
+ {
+ // TODO: If !tag.isEndTag, then create a new outline run.
+ // else Pop the top of the stack and set the number of characters of the run.
+ } // <outline></outline>
+ else if(TokenComparison(MARKUP::TAG::EMBEDDED_ITEM, tag.buffer, tag.length))
+ {
+ ProcessItemTag(markupProcessData, tag, characterIndex);
+ }
+ else if(TokenComparison(MARKUP::TAG::BACKGROUND, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<ColorRun>(
+ markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
+ }
+ else if(TokenComparison(MARKUP::TAG::SPAN, tag.buffer, tag.length))
+ {
+ ProcessSpanForRun(tag,
+ spanStack,
+ markupProcessData.colorRuns,
+ markupProcessData.fontRuns,
+ markupProcessData.underlinedCharacterRuns,
+ markupProcessData.backgroundColorRuns,
+ markupProcessData.strikethroughCharacterRuns,
+ markupProcessData.characterSpacingCharacterRuns,
+ colorRunIndex,
+ fontRunIndex,
+ underlinedCharacterRunIndex,
+ backgroundRunIndex,
+ strikethroughCharacterRunIndex,
+ characterSpacingCharacterRunIndex,
+ characterIndex,
+ spanTagReference);
+ }
+ else if(TokenComparison(MARKUP::TAG::STRIKETHROUGH, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<StrikethroughCharacterRun>(
+ markupProcessData.strikethroughCharacterRuns, styleStack, tag, characterIndex, strikethroughCharacterRunIndex, sTagReference, [](const Tag& tag, StrikethroughCharacterRun& run) { ProcessStrikethroughTag(tag, run); });
+ } // <s></s>
+ else if(TokenComparison(MARKUP::TAG::PARAGRAPH, tag.buffer, tag.length))
+ {
+ ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex);
+ ProcessTagForRun<BoundedParagraphRun>(
+ markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
+ } // <p></p>
+ else if(TokenComparison(MARKUP::TAG::CHARACTER_SPACING, tag.buffer, tag.length))
+ {
+ ProcessTagForRun<CharacterSpacingCharacterRun>(
+ markupProcessData.characterSpacingCharacterRuns, styleStack, tag, characterIndex, characterSpacingCharacterRunIndex, characterSpacingTagReference, [](const Tag& tag, CharacterSpacingCharacterRun& run) { ProcessCharacterSpacingTag(tag, run); });
+ } // <char-spacing></char-spacing>
+ } // end if( IsTag() )
+ else if(markupStringBuffer < markupStringEndBuffer)
+ {
+ ProcessMarkupStringBuffer(markupProcessData, markupStringBuffer, markupStringEndBuffer, characterIndex);
+ }
+ }
+
+ // Resize the model's vectors.
+ ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex, characterSpacingCharacterRunIndex);
+
+ // Handle the nested tags
+ OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
+ OverrideNestedStrikethroughCharacterRuns(markupProcessData.strikethroughCharacterRuns);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/anchor.h>
+#include <dali-toolkit/internal/text/bounded-paragraph-run.h>
+#include <dali-toolkit/internal/text/character-spacing-character-run.h>
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/embedded-item.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/strikethrough-character-run.h>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Keeps the plain text and references to vectors from the model which stores runs with text styles.
+ */
+struct MarkupProcessData
+{
+ MarkupProcessData(Vector<ColorRun>& colorRuns,
+ Vector<FontDescriptionRun>& fontRuns,
+ Vector<EmbeddedItem>& items,
+ Vector<Anchor>& anchors,
+ Vector<UnderlinedCharacterRun>& underlinedCharacterRuns,
+ Vector<ColorRun>& backgroundColorRuns,
+ Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns,
+ Vector<BoundedParagraphRun>& boundedParagraphRuns,
+ Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns)
+ : colorRuns(colorRuns),
+ fontRuns(fontRuns),
+ items(items),
+ anchors(anchors),
+ underlinedCharacterRuns(underlinedCharacterRuns),
+ backgroundColorRuns(backgroundColorRuns),
+ strikethroughCharacterRuns(strikethroughCharacterRuns),
+ boundedParagraphRuns(boundedParagraphRuns),
+ characterSpacingCharacterRuns(characterSpacingCharacterRuns),
+ markupProcessedText()
+ {
+ }
+
+ Vector<ColorRun>& colorRuns; ///< The color runs.
+ Vector<FontDescriptionRun>& fontRuns; ///< The font description runs.
+ Vector<EmbeddedItem>& items; ///< The embedded items.
+ Vector<Anchor>& anchors; ///< The anchors.
+ Vector<UnderlinedCharacterRun>& underlinedCharacterRuns; ///< The underlined character runs.
+ Vector<ColorRun>& backgroundColorRuns; ///< The background color runs.
+ Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns; ///< The strikethrough character runs.
+ Vector<BoundedParagraphRun>& boundedParagraphRuns; ///< The bounded paragraph runs
+ Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns; ///< The character-spacing runs
+
+ std::string markupProcessedText; ///< The mark-up string.
+};
+
+/**
+ * @brief Process the mark-up string.
+ *
+ * @param[in] markupString The mark-up string.
+ * @param[out] markupProcessData The plain text and the style.
+ */
+void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_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.
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/builder/json-parser.h>
#include <dali-toolkit/devel-api/builder/tree-node.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
namespace Dali
{
+++ /dev/null
-/*
- * 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.
- *
- */
-
-// HEADER
-#include <dali-toolkit/internal/text/text-controller-background-actor.h>
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/rendering/renderer.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
-#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
-#include <dali-toolkit/internal/text/text-view.h>
-
-namespace Dali::Toolkit::Text
-{
-namespace
-{
-struct BackgroundVertex
-{
- Vector2 mPosition; ///< Vertex posiiton
- Vector4 mColor; ///< Vertex color
-};
-
-struct BackgroundMesh
-{
- Vector<BackgroundVertex> mVertices; ///< container of vertices
- Vector<unsigned short> mIndices; ///< container of indices
-};
-} // unnamed namespace
-
-Length CalculateBackgroundLineHeight(LineRun lineRun)
-{
- Length height = lineRun.ascender + -(lineRun.descender);
-
- if(lineRun.lineSpacing > 0)
- {
- height += lineRun.lineSpacing;
- }
-
- return height;
-}
-
-Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground)
-{
- // NOTE: Currently we only support background color for left-to-right text.
-
- Actor actor;
-
- Length numberOfGlyphs = textView.GetNumberOfGlyphs();
- if(numberOfGlyphs > 0u)
- {
- Vector<GlyphInfo> glyphs;
- glyphs.Resize(numberOfGlyphs);
-
- Vector<Vector2> positions;
- positions.Resize(numberOfGlyphs);
-
- // Get the line where the glyphs are laid-out.
- const LineRun* lineRun = textVisualModel->mLines.Begin();
- float alignmentOffset = lineRun->alignmentOffset;
- numberOfGlyphs = textView.GetGlyphs(glyphs.Begin(),
- positions.Begin(),
- alignmentOffset,
- 0u,
- numberOfGlyphs);
-
- glyphs.Resize(numberOfGlyphs);
- positions.Resize(numberOfGlyphs);
-
- const GlyphInfo* const glyphsBuffer = glyphs.Begin();
- const Vector2* const positionsBuffer = positions.Begin();
-
- BackgroundMesh mesh;
- mesh.mVertices.Reserve(4u * glyphs.Size());
- mesh.mIndices.Reserve(6u * glyphs.Size());
-
- const Vector2 textSize = textView.GetLayoutSize();
-
- const float offsetX = alignmentOffset + textSize.width * 0.5f;
- const float offsetY = textSize.height * 0.5f;
-
- const Vector4* const backgroundColorsBuffer = textView.GetBackgroundColors();
- const ColorIndex* const backgroundColorIndicesBuffer = textView.GetBackgroundColorIndices();
- const Vector4& defaultBackgroundColor = textVisualModel->IsBackgroundEnabled() ? textVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
- const float modelCharacterSpacing = textVisualModel->GetCharacterSpacing();
- Vector<CharacterIndex>& glyphToCharacterMap = textVisualModel->mGlyphsToCharacters;
- const CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
- float calculatedAdvance = 0.f;
-
- // Get the character-spacing runs.
- const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = textVisualModel->GetCharacterSpacingGlyphRuns();
-
- Vector4 quad;
- uint32_t numberOfQuads = 0u;
- Length yLineOffset = 0;
- Length prevLineIndex = 0;
- LineIndex lineIndex;
-
- for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
- {
- const GlyphInfo& glyph = *(glyphsBuffer + i);
-
- // Get the background color of the character.
- // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
- const bool isMarkupBackground = textView.IsMarkupBackgroundColorSet();
- const ColorIndex backgroundColorIndex = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
- const bool isDefaultBackgroundColor = (0u == backgroundColorIndex);
- const Vector4& backgroundColor = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
-
- lineIndex = textVisualModel->GetLineOfGlyph(i);
- Length lineHeight = CalculateBackgroundLineHeight(lineRun[lineIndex]);
-
- if(lineIndex != prevLineIndex)
- {
- yLineOffset += CalculateBackgroundLineHeight(lineRun[prevLineIndex]);
-
- if(lineRun[prevLineIndex].lineSpacing < 0)
- {
- yLineOffset += lineRun[prevLineIndex].lineSpacing;
- }
- }
-
- // Only create quads for glyphs with a background color
- if(backgroundColor != Color::TRANSPARENT)
- {
- const float characterSpacing = GetGlyphCharacterSpacing(i, characterSpacingGlyphRuns, modelCharacterSpacing);
-
- const Vector2 position = *(positionsBuffer + i);
- calculatedAdvance = GetCalculatedAdvance(*(textLogicalModel->mText.Begin() + (*(glyphToCharacterMapBuffer + i))), characterSpacing, glyph.advance);
-
- if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
- {
- quad.x = position.x;
- quad.y = yLineOffset;
- quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
- quad.w = lineHeight;
- }
- else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
- {
- quad.x = position.x;
- quad.y = yLineOffset;
- quad.z = quad.x - glyph.xBearing + calculatedAdvance;
- quad.w = quad.y + lineHeight;
- }
- else if(i == glyphSize - 1u) // The last glyph in the whole text
- {
- quad.x = position.x - glyph.xBearing;
- quad.y = yLineOffset;
- quad.z = quad.x + std::max(calculatedAdvance, glyph.xBearing + glyph.width);
- quad.w = quad.y + lineHeight;
- }
- else // The glyph in the middle of the text
- {
- quad.x = position.x - glyph.xBearing;
- quad.y = yLineOffset;
- quad.z = quad.x + calculatedAdvance;
- quad.w = quad.y + lineHeight;
- }
-
- BackgroundVertex vertex;
-
- // Top left
- vertex.mPosition.x = quad.x - offsetX;
- vertex.mPosition.y = quad.y - offsetY;
- vertex.mColor = backgroundColor;
- mesh.mVertices.PushBack(vertex);
-
- // Top right
- vertex.mPosition.x = quad.z - offsetX;
- vertex.mPosition.y = quad.y - offsetY;
- vertex.mColor = backgroundColor;
- mesh.mVertices.PushBack(vertex);
-
- // Bottom left
- vertex.mPosition.x = quad.x - offsetX;
- vertex.mPosition.y = quad.w - offsetY;
- vertex.mColor = backgroundColor;
- mesh.mVertices.PushBack(vertex);
-
- // Bottom right
- vertex.mPosition.x = quad.z - offsetX;
- vertex.mPosition.y = quad.w - offsetY;
- vertex.mColor = backgroundColor;
- mesh.mVertices.PushBack(vertex);
-
- // Six indices in counter clockwise winding
- mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
- mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
- mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
- mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
- mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
- mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
-
- numberOfQuads++;
- }
-
- if(lineIndex != prevLineIndex)
- {
- prevLineIndex = lineIndex;
- }
- }
-
- // Only create the background actor if there are glyphs with background color
- if(mesh.mVertices.Count() > 0u)
- {
- Property::Map quadVertexFormat;
- quadVertexFormat["aPosition"] = Property::VECTOR2;
- quadVertexFormat["aColor"] = Property::VECTOR4;
-
- VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
- quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
-
- Geometry quadGeometry = Geometry::New();
- quadGeometry.AddVertexBuffer(quadVertices);
- quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
-
- if(!textShaderBackground)
- {
- textShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
- }
-
- Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, textShaderBackground);
- renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
- renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
-
- actor = Actor::New();
- actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
- actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
- actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
- actor.SetProperty(Actor::Property::SIZE, textSize);
- actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
- actor.AddRenderer(renderer);
- }
- }
-
- return actor;
-}
-
-} // namespace Dali::Toolkit::Text
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_BACKGROUND_ACTOR_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_BACKGROUND_ACTOR_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/actors/actor.h>
-#include <dali/public-api/rendering/shader.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/logical-model-impl.h>
-#include <dali-toolkit/internal/text/visual-model-impl.h>
-
-namespace Dali::Toolkit::Text
-{
-class View;
-
-/**
- * @brief Create an actor that renders the text background color
- *
- * @param[in] textView The text view.
- * @param[in] textVisualModel The text visual model.
- * @param[in] textLogicalModel The text logical model.
- * @param[in] textShaderBackground The text shader for background.
- *
- * @return the created actor or an empty handle if no background color needs to be rendered.
- */
-Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground);
-
-} // namespace Dali::Toolkit::Text
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_BACKGROUND_ACTOR_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-event-handler.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
-#include <dali/devel-api/adaptor-framework/key-devel.h>
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
-#include <dali-toolkit/internal/text/text-controller-text-updater.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-const std::string KEY_C_NAME = "c";
-const std::string KEY_V_NAME = "v";
-const std::string KEY_X_NAME = "x";
-const std::string KEY_A_NAME = "a";
-const std::string KEY_INSERT_NAME = "Insert";
-
-} // namespace
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void Controller::EventHandler::KeyboardFocusGainEvent(Controller& controller)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected KeyboardFocusGainEvent");
-
- if(NULL != controller.mImpl->mEventData)
- {
- if((EventData::INACTIVE == controller.mImpl->mEventData->mState) ||
- (EventData::INTERRUPTED == controller.mImpl->mEventData->mState))
- {
- controller.mImpl->ChangeState(EventData::EDITING);
- controller.mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
- controller.mImpl->mEventData->mUpdateInputStyle = true;
- controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
- }
- controller.mImpl->NotifyInputMethodContextMultiLineStatus();
- if(controller.mImpl->IsShowingPlaceholderText())
- {
- // Show alternative placeholder-text when editing
- PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
- }
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-void Controller::EventHandler::KeyboardFocusLostEvent(Controller& controller)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected KeyboardFocusLostEvent");
-
- if(NULL != controller.mImpl->mEventData)
- {
- if(EventData::INTERRUPTED != controller.mImpl->mEventData->mState)
- {
- // Init selection position
- if(controller.mImpl->mEventData->mState == EventData::SELECTING)
- {
- uint32_t oldStart, oldEnd;
- oldStart = controller.mImpl->mEventData->mLeftSelectionPosition;
- oldEnd = controller.mImpl->mEventData->mRightSelectionPosition;
-
- controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
- controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
-
- if(controller.mImpl->mSelectableControlInterface != nullptr)
- {
- controller.mImpl->mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, controller.mImpl->mEventData->mPrimaryCursorPosition, controller.mImpl->mEventData->mPrimaryCursorPosition);
- }
- }
-
- controller.mImpl->ChangeState(EventData::INACTIVE);
-
- if(!controller.mImpl->IsShowingRealText())
- {
- // Revert to regular placeholder-text when not editing
- PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
- }
- }
- }
- controller.mImpl->RequestRelayout();
-}
-
-bool Controller::EventHandler::KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected KeyEvent");
-
- bool textChanged = false;
- bool relayoutNeeded = false;
- bool isEditable = controller.IsEditable() && controller.IsUserInteractionEnabled();
-
- if((NULL != controller.mImpl->mEventData) &&
- (keyEvent.GetState() == KeyEvent::DOWN))
- {
- int keyCode = keyEvent.GetKeyCode();
- const std::string& keyString = keyEvent.GetKeyString();
- const std::string keyName = keyEvent.GetKeyName();
- // Key will produce same logical-key value when ctrl
- // is down, regardless of language layout
- const std::string logicalKey = keyEvent.GetLogicalKey();
-
- const bool isNullKey = (0 == keyCode) && (keyString.empty());
-
- // Pre-process to separate modifying events from non-modifying input events.
- if(isNullKey)
- {
- // In some platforms arrive key events with no key code.
- // Do nothing.
- return false;
- }
- else if(Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode)
- {
- // Do nothing
- return false;
- }
- else if((Dali::DALI_KEY_CURSOR_LEFT == keyCode) ||
- (Dali::DALI_KEY_CURSOR_RIGHT == keyCode) ||
- (Dali::DALI_KEY_CURSOR_UP == keyCode) ||
- (Dali::DALI_KEY_CURSOR_DOWN == keyCode))
- {
- // If don't have any text, do nothing.
- if(!controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters || !isEditable)
- {
- return false;
- }
-
- uint32_t cursorPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
- uint32_t numberOfCharacters = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- uint32_t cursorLine = controller.mImpl->mModel->mVisualModel->GetLineOfCharacter(cursorPosition);
- uint32_t numberOfLines = controller.mImpl->mModel->GetNumberOfLines();
-
- // Logic to determine whether this text control will lose focus or not.
- if((Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier()) ||
- (Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier()) ||
- (Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines - 1) ||
- (Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine - 1 == numberOfLines - 1) ||
- (Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0) ||
- (Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1))
- {
- // Release the active highlight.
- if(controller.mImpl->mEventData->mState == EventData::SELECTING)
- {
- uint32_t oldStart, oldEnd;
- oldStart = controller.mImpl->mEventData->mLeftSelectionPosition;
- oldEnd = controller.mImpl->mEventData->mRightSelectionPosition;
-
- controller.mImpl->ChangeState(EventData::EDITING);
-
- // Update selection position.
- controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
- controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
- controller.mImpl->mEventData->mUpdateCursorPosition = true;
-
- if(controller.mImpl->mSelectableControlInterface != nullptr)
- {
- controller.mImpl->mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, controller.mImpl->mEventData->mLeftSelectionPosition, controller.mImpl->mEventData->mRightSelectionPosition);
- }
-
- controller.mImpl->RequestRelayout();
- }
- return false;
- }
-
- controller.mImpl->mEventData->mCheckScrollAmount = true;
- Event event(Event::CURSOR_KEY_EVENT);
- event.p1.mInt = keyCode;
- event.p2.mBool = keyEvent.IsShiftModifier();
- controller.mImpl->mEventData->mEventQueue.push_back(event);
-
- // Will request for relayout.
- relayoutNeeded = true;
- }
- else if(Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode)
- {
- // Left or Right Control key event is received before Ctrl-C/V/X key event is received
- // If not handle it here, any selected text will be deleted
-
- // Do nothing
- return false;
- }
- else if(keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier() && isEditable)
- {
- bool consumed = false;
- if(keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME || logicalKey == KEY_C_NAME || logicalKey == KEY_INSERT_NAME)
- {
- // Ctrl-C or Ctrl+Insert to copy the selected text
- controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::COPY);
- consumed = true;
- }
- else if(keyName == KEY_V_NAME || logicalKey == KEY_V_NAME)
- {
- // Ctrl-V to paste the copied text
- controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::PASTE);
- consumed = true;
- }
- else if(keyName == KEY_X_NAME || logicalKey == KEY_X_NAME)
- {
- // Ctrl-X to cut the selected text
- controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::CUT);
- consumed = true;
- }
- else if(keyName == KEY_A_NAME || logicalKey == KEY_A_NAME)
- {
- // Ctrl-A to select All the text
- controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::SELECT_ALL);
- consumed = true;
- }
- return consumed;
- }
- else if((Dali::DALI_KEY_BACKSPACE == keyCode) ||
- (Dali::DevelKey::DALI_KEY_DELETE == keyCode))
- {
- textChanged = DeleteEvent(controller, keyCode);
-
- // Will request for relayout.
- relayoutNeeded = true;
- }
- else if(IsKey(keyEvent, Dali::DALI_KEY_POWER) ||
- IsKey(keyEvent, Dali::DALI_KEY_MENU) ||
- IsKey(keyEvent, Dali::DALI_KEY_HOME))
- {
- // Power key/Menu/Home key behaviour does not allow edit mode to resume.
- controller.mImpl->ChangeState(EventData::INACTIVE);
-
- // Will request for relayout.
- relayoutNeeded = true;
-
- // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
- }
- else if((Dali::DALI_KEY_SHIFT_LEFT == keyCode) || (Dali::DALI_KEY_SHIFT_RIGHT == keyCode))
- {
- // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled
- // and a character is typed after the type of a upper case latin character.
-
- // Do nothing.
- return false;
- }
- else if((Dali::DALI_KEY_VOLUME_UP == keyCode) || (Dali::DALI_KEY_VOLUME_DOWN == keyCode))
- {
- // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
- // Do nothing.
- return false;
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", &controller, keyString.c_str());
- if(!isEditable) return false;
-
- std::string refinedKey = keyString;
- if(controller.mImpl->mInputFilter != NULL && !refinedKey.empty())
- {
- bool accepted = false;
- bool rejected = false;
- accepted = controller.mImpl->mInputFilter->Contains(Toolkit::InputFilter::Property::ACCEPTED, keyString);
- rejected = controller.mImpl->mInputFilter->Contains(Toolkit::InputFilter::Property::REJECTED, keyString);
-
- if(!accepted)
- {
- // The filtered key is set to empty.
- refinedKey = "";
- // Signal emits when the character to be inserted is filtered by the accepted filter.
- controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::ACCEPTED);
- }
- if(rejected)
- {
- // The filtered key is set to empty.
- refinedKey = "";
- // Signal emits when the character to be inserted is filtered by the rejected filter.
- controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::REJECTED);
- }
- }
-
- if(!refinedKey.empty())
- {
- // InputMethodContext is no longer handling key-events
- controller.mImpl->ClearPreEditFlag();
-
- TextUpdater::InsertText(controller, refinedKey, COMMIT);
-
- textChanged = true;
-
- // Will request for relayout.
- relayoutNeeded = true;
- }
- }
-
- if((controller.mImpl->mEventData->mState != EventData::INTERRUPTED) &&
- (controller.mImpl->mEventData->mState != EventData::INACTIVE) &&
- (!isNullKey) &&
- (Dali::DALI_KEY_SHIFT_LEFT != keyCode) &&
- (Dali::DALI_KEY_SHIFT_RIGHT != keyCode) &&
- (Dali::DALI_KEY_VOLUME_UP != keyCode) &&
- (Dali::DALI_KEY_VOLUME_DOWN != keyCode))
- {
- // Should not change the state if the key is the shift send by the InputMethodContext.
- // Otherwise, when the state is SELECTING the text controller can't send the right
- // surrounding info to the InputMethodContext.
- controller.mImpl->ChangeState(EventData::EDITING);
-
- // Will request for relayout.
- relayoutNeeded = true;
- }
-
- if(relayoutNeeded)
- {
- controller.mImpl->RequestRelayout();
- }
- }
- else if((NULL != controller.mImpl->mEventData) && (keyEvent.GetState() == KeyEvent::UP))
- {
- // Handles specific keys that require event propagation.
- if(Dali::DALI_KEY_BACK == keyEvent.GetKeyCode())
- {
- // Do nothing
- return false;
- }
- }
-
- if(textChanged &&
- (NULL != controller.mImpl->mEditableControlInterface))
- {
- // Do this last since it provides callbacks into application code
- controller.mImpl->mEditableControlInterface->TextChanged(false);
- }
-
- return true;
-}
-
-void Controller::EventHandler::AnchorEvent(Controller& controller, float x, float y)
-{
- if(!controller.mImpl->mMarkupProcessorEnabled ||
- !controller.mImpl->mModel->mLogicalModel->mAnchors.Count() ||
- !controller.mImpl->IsShowingRealText())
- {
- return;
- }
-
- CharacterIndex cursorPosition = 0u;
-
- // Convert from control's coords to text's coords.
- const float xPosition = x - controller.mImpl->mModel->mScrollPosition.x;
- const float yPosition = y - controller.mImpl->mModel->mScrollPosition.y;
-
- // Whether to touch point hits on a glyph.
- bool matchedCharacter = false;
- cursorPosition = Text::GetClosestCursorIndex(controller.mImpl->mModel->mVisualModel,
- controller.mImpl->mModel->mLogicalModel,
- controller.mImpl->mMetrics,
- xPosition,
- yPosition,
- CharacterHitTest::TAP,
- matchedCharacter);
-
- for(const auto& anchor : controller.mImpl->mModel->mLogicalModel->mAnchors)
- {
- // Anchor clicked if the calculated cursor position is within the range of anchor.
- if(cursorPosition >= anchor.startIndex && cursorPosition < anchor.endIndex)
- {
- if(controller.mImpl->mAnchorControlInterface && anchor.href)
- {
- std::string href(anchor.href);
- controller.mImpl->mAnchorControlInterface->AnchorClicked(href);
- break;
- }
- }
- }
-}
-
-void Controller::EventHandler::TapEvent(Controller& controller, unsigned int tapCount, float x, float y)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected TapEvent");
-
- if(NULL != controller.mImpl->mEventData)
- {
- DALI_LOG_INFO(gLogFilter, Debug::Concise, "TapEvent state:%d \n", controller.mImpl->mEventData->mState);
- EventData::State state(controller.mImpl->mEventData->mState);
- bool relayoutNeeded(false); // to avoid unnecessary relayouts when tapping an empty text-field
-
- if(controller.mImpl->IsClipboardVisible())
- {
- if(EventData::INACTIVE == state || EventData::EDITING == state)
- {
- controller.mImpl->ChangeState(EventData::EDITING_WITH_GRAB_HANDLE);
- }
- relayoutNeeded = true;
- }
- else if(1u == tapCount)
- {
- if(EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state)
- {
- controller.mImpl->ChangeState(EventData::EDITING_WITH_GRAB_HANDLE); // If Popup shown hide it here so can be shown again if required.
- }
-
- if(controller.mImpl->IsShowingRealText() && (EventData::INACTIVE != state))
- {
- controller.mImpl->ChangeState(EventData::EDITING_WITH_GRAB_HANDLE);
- relayoutNeeded = true;
- }
- else
- {
- if(controller.mImpl->IsShowingPlaceholderText() && !controller.mImpl->IsFocusedPlaceholderAvailable())
- {
- // Hide placeholder text
- TextUpdater::ResetText(controller);
- }
-
- if(EventData::INACTIVE == state)
- {
- controller.mImpl->ChangeState(EventData::EDITING);
- }
- else if(!controller.mImpl->IsClipboardEmpty())
- {
- controller.mImpl->ChangeState(EventData::EDITING_WITH_POPUP);
- }
- relayoutNeeded = true;
- }
- }
- else if(2u == tapCount)
- {
- if(controller.mImpl->mEventData->mSelectionEnabled &&
- controller.mImpl->IsShowingRealText())
- {
- relayoutNeeded = true;
- controller.mImpl->mEventData->mIsLeftHandleSelected = true;
- controller.mImpl->mEventData->mIsRightHandleSelected = true;
- }
- }
-
- // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
- if(relayoutNeeded)
- {
- Event event(Event::TAP_EVENT);
- event.p1.mUint = tapCount;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
-
- controller.mImpl->RequestRelayout();
- }
- }
-
- // Reset keyboard as tap event has occurred.
- controller.mImpl->ResetInputMethodContext();
-}
-
-void Controller::EventHandler::PanEvent(Controller& controller, GestureState state, const Vector2& displacement)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected PanEvent");
-
- if(NULL != controller.mImpl->mEventData)
- {
- Event event(Event::PAN_EVENT);
- event.p1.mInt = static_cast<int>(state);
- event.p2.mFloat = displacement.x;
- event.p3.mFloat = displacement.y;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-void Controller::EventHandler::LongPressEvent(Controller& controller, GestureState state, float x, float y)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected LongPressEvent");
-
- if((state == GestureState::STARTED) &&
- (NULL != controller.mImpl->mEventData))
- {
- // The 1st long-press on inactive text-field is treated as tap
- if(EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- controller.mImpl->ChangeState(EventData::EDITING);
-
- Event event(Event::TAP_EVENT);
- event.p1.mUint = 1;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
-
- controller.mImpl->RequestRelayout();
- }
- else if(!controller.mImpl->IsShowingRealText())
- {
- Event event(Event::LONG_PRESS_EVENT);
- event.p1.mInt = static_cast<int>(state);
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- controller.mImpl->RequestRelayout();
- }
- else if(!controller.mImpl->IsClipboardVisible())
- {
- // Reset the InputMethodContext to commit the pre-edit before selecting the text.
- controller.mImpl->ResetInputMethodContext();
-
- Event event(Event::LONG_PRESS_EVENT);
- event.p1.mInt = static_cast<int>(state);
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- controller.mImpl->RequestRelayout();
-
- controller.mImpl->mEventData->mIsLeftHandleSelected = true;
- controller.mImpl->mEventData->mIsRightHandleSelected = true;
- }
- }
-}
-
-void Controller::EventHandler::SelectEvent(Controller& controller, float x, float y, SelectionType selectType)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SelectEvent\n");
-
- if(NULL != controller.mImpl->mEventData)
- {
- if(selectType == SelectionType::ALL)
- {
- Event event(Event::SELECT_ALL);
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- }
- else if(selectType == SelectionType::NONE)
- {
- Event event(Event::SELECT_NONE);
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- }
- else
- {
- Event event(Event::SELECT);
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- }
-
- controller.mImpl->mEventData->mCheckScrollAmount = true;
- controller.mImpl->mEventData->mIsLeftHandleSelected = true;
- controller.mImpl->mEventData->mIsRightHandleSelected = true;
- controller.mImpl->RequestRelayout();
- }
-}
-
-void Controller::EventHandler::SelectEvent(Controller& controller, const uint32_t start, const uint32_t end, SelectionType selectType)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SelectEvent\n");
-
- if(NULL != controller.mImpl->mEventData)
- {
- if(selectType == SelectionType::RANGE)
- {
- Event event(Event::SELECT_RANGE);
- event.p2.mUint = start;
- event.p3.mUint = end;
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- }
-
- controller.mImpl->mEventData->mCheckScrollAmount = true;
- controller.mImpl->mEventData->mIsLeftHandleSelected = true;
- controller.mImpl->mEventData->mIsRightHandleSelected = true;
- controller.mImpl->RequestRelayout();
- }
-}
-
-void Controller::EventHandler::ProcessModifyEvents(Controller& controller)
-{
- Vector<ModifyEvent>& events = controller.mImpl->mModifyEvents;
-
- if(0u == events.Count())
- {
- // Nothing to do.
- return;
- }
-
- for(Vector<ModifyEvent>::ConstIterator it = events.Begin(),
- endIt = events.End();
- it != endIt;
- ++it)
- {
- const ModifyEvent& event = *it;
-
- if(ModifyEvent::TEXT_REPLACED == event.type)
- {
- // A (single) replace event should come first, otherwise we wasted time processing NOOP events
- DALI_ASSERT_DEBUG(it == events.Begin() && "Unexpected TEXT_REPLACED event");
-
- TextReplacedEvent(controller);
- }
- else if(ModifyEvent::TEXT_INSERTED == event.type)
- {
- TextInsertedEvent(controller);
- }
- else if(ModifyEvent::TEXT_DELETED == event.type)
- {
- // Placeholder-text cannot be deleted
- if(!controller.mImpl->IsShowingPlaceholderText())
- {
- TextDeletedEvent(controller);
- }
- }
- }
-
- if(NULL != controller.mImpl->mEventData)
- {
- uint32_t oldStart, oldEnd;
- oldStart = controller.mImpl->mEventData->mLeftSelectionPosition;
- oldEnd = controller.mImpl->mEventData->mRightSelectionPosition;
-
- // When the text is being modified, delay cursor blinking
- controller.mImpl->mEventData->mDecorator->DelayCursorBlink();
-
- // Update selection position after modifying the text
- controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
- controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition;
-
- if(controller.mImpl->mSelectableControlInterface != nullptr && controller.mImpl->mEventData->mState == EventData::SELECTING)
- {
- controller.mImpl->mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, controller.mImpl->mEventData->mLeftSelectionPosition, controller.mImpl->mEventData->mRightSelectionPosition);
- }
- }
-
- // DISCARD temporary text
- events.Clear();
-}
-
-void Controller::EventHandler::TextReplacedEvent(Controller& controller)
-{
- // The natural size needs to be re-calculated.
- controller.mImpl->mRecalculateNaturalSize = true;
-
- // The text direction needs to be updated.
- controller.mImpl->mUpdateTextDirection = true;
-
- // Apply modifications to the model
- controller.mImpl->mOperationsPending = ALL_OPERATIONS;
-}
-
-void Controller::EventHandler::TextInsertedEvent(Controller& controller)
-{
- DALI_ASSERT_DEBUG(NULL != controller.mImpl->mEventData && "Unexpected TextInsertedEvent");
-
- if(NULL == controller.mImpl->mEventData)
- {
- return;
- }
-
- controller.mImpl->mEventData->mCheckScrollAmount = true;
-
- // The natural size needs to be re-calculated.
- controller.mImpl->mRecalculateNaturalSize = true;
-
- // The text direction needs to be updated.
- controller.mImpl->mUpdateTextDirection = true;
-
- // Apply modifications to the model; TODO - Optimize this
- controller.mImpl->mOperationsPending = ALL_OPERATIONS;
-}
-
-void Controller::EventHandler::TextDeletedEvent(Controller& controller)
-{
- DALI_ASSERT_DEBUG(NULL != controller.mImpl->mEventData && "Unexpected TextDeletedEvent");
-
- if(NULL == controller.mImpl->mEventData)
- {
- return;
- }
-
- if(!controller.IsEditable()) return;
-
- controller.mImpl->mEventData->mCheckScrollAmount = true;
-
- // The natural size needs to be re-calculated.
- controller.mImpl->mRecalculateNaturalSize = true;
-
- // The text direction needs to be updated.
- controller.mImpl->mUpdateTextDirection = true;
-
- // Apply modifications to the model; TODO - Optimize this
- controller.mImpl->mOperationsPending = ALL_OPERATIONS;
-}
-
-bool Controller::EventHandler::DeleteEvent(Controller& controller, int keyCode)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", &controller, keyCode);
-
- bool removed = false;
-
- if(NULL == controller.mImpl->mEventData)
- {
- return removed;
- }
-
- if(!controller.IsEditable()) return false;
-
- // InputMethodContext is no longer handling key-events
- controller.mImpl->ClearPreEditFlag();
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- removed = TextUpdater::RemoveSelectedText(controller);
- }
- else if((controller.mImpl->mEventData->mPrimaryCursorPosition > 0) && (keyCode == Dali::DALI_KEY_BACKSPACE))
- {
- // Remove the character before the current cursor position
- removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE);
- }
- else if((controller.mImpl->mEventData->mPrimaryCursorPosition < controller.mImpl->mModel->mLogicalModel->mText.Count()) &&
- (keyCode == Dali::DevelKey::DALI_KEY_DELETE))
- {
- // Remove the character after the current cursor position
- removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE);
- }
-
- if(removed)
- {
- if((0u != controller.mImpl->mModel->mLogicalModel->mText.Count()) ||
- !controller.mImpl->IsPlaceholderAvailable())
- {
- controller.mImpl->QueueModifyEvent(ModifyEvent::TEXT_DELETED);
- }
- else
- {
- PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
- }
- controller.mImpl->mEventData->mUpdateCursorPosition = true;
- controller.mImpl->mEventData->mScrollAfterDelete = true;
- }
-
- return removed;
-}
-
-InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextEvent(Controller& controller, InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
-{
- // Whether the text needs to be relaid-out.
- bool requestRelayout = false;
-
- // Whether to retrieve the text and cursor position to be sent to the InputMethodContext.
- bool retrieveText = false;
- bool retrieveCursor = false;
-
- switch(inputMethodContextEvent.eventName)
- {
- case InputMethodContext::COMMIT:
- {
- TextUpdater::InsertText(controller, inputMethodContextEvent.predictiveString, Text::Controller::COMMIT);
- requestRelayout = true;
- retrieveCursor = true;
- break;
- }
- case InputMethodContext::PRE_EDIT:
- {
- TextUpdater::InsertText(controller, inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT);
- requestRelayout = true;
- retrieveCursor = true;
- break;
- }
- case InputMethodContext::DELETE_SURROUNDING:
- {
- const bool textDeleted = TextUpdater::RemoveText(controller,
- inputMethodContextEvent.cursorOffset,
- inputMethodContextEvent.numberOfChars,
- DONT_UPDATE_INPUT_STYLE);
-
- if(textDeleted)
- {
- if((0u != controller.mImpl->mModel->mLogicalModel->mText.Count()) ||
- !controller.mImpl->IsPlaceholderAvailable())
- {
- controller.mImpl->QueueModifyEvent(ModifyEvent::TEXT_DELETED);
- }
- else
- {
- PlaceholderHandler::ShowPlaceholderText(*controller.mImpl);
- }
- controller.mImpl->mEventData->mUpdateCursorPosition = true;
- controller.mImpl->mEventData->mScrollAfterDelete = true;
-
- requestRelayout = true;
- }
- break;
- }
- case InputMethodContext::GET_SURROUNDING:
- {
- retrieveText = true;
- retrieveCursor = true;
- break;
- }
- case InputMethodContext::PRIVATE_COMMAND:
- {
- // PRIVATECOMMAND event is just for getting the private command message
- retrieveText = true;
- retrieveCursor = true;
- break;
- }
- case InputMethodContext::SELECTION_SET:
- {
- uint32_t start = static_cast<uint32_t>(inputMethodContextEvent.startIndex);
- uint32_t end = static_cast<uint32_t>(inputMethodContextEvent.endIndex);
- if(start == end)
- {
- controller.SetPrimaryCursorPosition(start, true);
- }
- else
- {
- controller.SelectText(start, end);
- }
-
- break;
- }
- case InputMethodContext::VOID:
- {
- // do nothing
- break;
- }
- } // end switch
-
- if(requestRelayout)
- {
- controller.mImpl->mOperationsPending = ALL_OPERATIONS;
- controller.mImpl->RequestRelayout();
- }
-
- std::string text;
- CharacterIndex cursorPosition = 0u;
- Length numberOfWhiteSpaces = 0u;
-
- if(retrieveCursor)
- {
- numberOfWhiteSpaces = controller.mImpl->GetNumberOfWhiteSpaces(0u);
-
- cursorPosition = controller.mImpl->GetLogicalCursorPosition();
-
- if(cursorPosition < numberOfWhiteSpaces)
- {
- cursorPosition = 0u;
- }
- else
- {
- cursorPosition -= numberOfWhiteSpaces;
- }
- }
-
- if(retrieveText)
- {
- if(!controller.mImpl->IsShowingPlaceholderText())
- {
- // Retrieves the normal text string.
- controller.mImpl->GetText(numberOfWhiteSpaces, text);
- }
- else
- {
- // When the current text is Placeholder Text, the surrounding text should be empty string.
- // It means DALi should send empty string ("") to IME.
- text = "";
- }
- }
-
- InputMethodContext::CallbackData callbackData((retrieveText || retrieveCursor), cursorPosition, text, false);
-
- if(requestRelayout &&
- (NULL != controller.mImpl->mEditableControlInterface))
- {
- // Do this last since it provides callbacks into application code
- controller.mImpl->mEditableControlInterface->TextChanged(false);
- }
-
- return callbackData;
-}
-
-void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller)
-{
- // Retrieve the clipboard contents first
- ClipboardEventNotifier notifier(ClipboardEventNotifier::Get());
- std::string stringToPaste(notifier.GetContent());
-
- // Commit the current pre-edit text; the contents of the clipboard should be appended
- controller.mImpl->ResetInputMethodContext();
-
- // Temporary disable hiding clipboard
- controller.mImpl->SetClipboardHideEnable(false);
-
- // Paste
- TextUpdater::PasteText(controller, stringToPaste);
-
- controller.mImpl->SetClipboardHideEnable(true);
-}
-
-void Controller::EventHandler::DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y)
-{
- DALI_ASSERT_DEBUG(controller.mImpl->mEventData && "Unexpected DecorationEvent");
-
- if(NULL != controller.mImpl->mEventData)
- {
- switch(handleType)
- {
- case GRAB_HANDLE:
- {
- Event event(Event::GRAB_HANDLE_EVENT);
- event.p1.mUint = state;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
-
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- break;
- }
- case LEFT_SELECTION_HANDLE:
- {
- Event event(Event::LEFT_SELECTION_HANDLE_EVENT);
- event.p1.mUint = state;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
-
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- break;
- }
- case RIGHT_SELECTION_HANDLE:
- {
- Event event(Event::RIGHT_SELECTION_HANDLE_EVENT);
- event.p1.mUint = state;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
-
- controller.mImpl->mEventData->mEventQueue.push_back(event);
- break;
- }
- case LEFT_SELECTION_HANDLE_MARKER:
- case RIGHT_SELECTION_HANDLE_MARKER:
- {
- // Markers do not move the handles.
- break;
- }
- case HANDLE_TYPE_COUNT:
- {
- DALI_ASSERT_DEBUG(!"Controller::HandleEvent. Unexpected handle type");
- }
- }
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-void Controller::EventHandler::TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button)
-{
- if(NULL == controller.mImpl->mEventData)
- {
- return;
- }
-
- switch(button)
- {
- case Toolkit::TextSelectionPopup::CUT:
- {
- controller.CutText();
- break;
- }
- case Toolkit::TextSelectionPopup::COPY:
- {
- controller.CopyText();
- break;
- }
- case Toolkit::TextSelectionPopup::PASTE:
- {
- controller.PasteText();
- break;
- }
- case Toolkit::TextSelectionPopup::SELECT:
- {
- const Vector2& currentCursorPosition = controller.mImpl->mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
-
- if(controller.mImpl->mEventData->mSelectionEnabled)
- {
- // Creates a SELECT event.
- SelectEvent(controller, currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE);
- }
- break;
- }
- case Toolkit::TextSelectionPopup::SELECT_ALL:
- {
- // Creates a SELECT_ALL event
- SelectEvent(controller, 0.f, 0.f, SelectionType::ALL);
- break;
- }
- case Toolkit::TextSelectionPopup::CLIPBOARD:
- {
- controller.mImpl->ShowClipboard();
- break;
- }
- case Toolkit::TextSelectionPopup::NONE:
- {
- // Nothing to do.
- break;
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/input-method-context.h>
-#include <dali/public-api/events/gesture-enumerations.h>
-#include <dali/public-api/events/key-event.h>
-#include <dali/public-api/math/vector2.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
-#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-#include <dali-toolkit/internal/text/text-controller.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Controller::EventHandler
-{
- /// @copydoc Text::Controller::KeyboardFocusGainEvent
- /// @param[in] controller A reference to the controller class
- static void KeyboardFocusGainEvent(Controller& controller);
-
- /// @copydoc Text::Controller::KeyboardFocusLostEvent
- /// @param[in] controller A reference to the controller class
- static void KeyboardFocusLostEvent(Controller& controller);
-
- /// @copydoc Text::Controller::KeyEvent
- /// @param[in] controller A reference to the controller class
- static bool KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent);
-
- /// @copydoc Text::Controller::AnchorEvent
- /// @param[in] controller A reference to the controller class
- static void AnchorEvent(Controller& controller, float x, float y);
-
- /// @copydoc Text::Controller::TapEvent
- /// @param[in] controller A reference to the controller class
- static void TapEvent(Controller& controller, unsigned int tapCount, float x, float y);
-
- /// @copydoc Text::Controller::PanEvent
- /// @param[in] controller A reference to the controller class
- static void PanEvent(Controller& controller, GestureState state, const Vector2& displacement);
-
- /// @copydoc Text::Controller::LongPressEvent
- /// @param[in] controller A reference to the controller class
- static void LongPressEvent(Controller& controller, GestureState state, float x, float y);
-
- /// @copydoc Text::Controller::SelectEvent
- /// @param[in] controller A reference to the controller class
- static void SelectEvent(Controller& controller, float x, float y, SelectionType selectType);
-
- /**
- * @brief Creates a selection event with a selection index.
- *
- * It could be called from the SelectText().
- * The start and end parameters are passed through the event.
- *
- * @param[in] controller A reference to the controller class
- * @param[in] start The start selection position.
- * @param[in] end The end selection position.
- * @param[in] selection type like the range.
- */
- static void SelectEvent(Controller& controller, const uint32_t start, const uint32_t end, SelectionType selectType);
-
- /**
- * @brief Process queued events which modify the model.
- * @param[in] controller A reference to the controller class
- */
- static void ProcessModifyEvents(Controller& controller);
-
- /**
- * @brief Used to process an event queued from SetText()
- * @param[in] controller A reference to the controller class
- */
- static void TextReplacedEvent(Controller& controller);
-
- /**
- * @brief Used to process an event queued from key events etc.
- * @param[in] controller A reference to the controller class
- */
- static void TextInsertedEvent(Controller& controller);
-
- /**
- * @brief Used to process an event queued from backspace key etc.
- * @param[in] controller A reference to the controller class
- */
- static void TextDeletedEvent(Controller& controller);
-
- /**
- * @brief Helper to KeyEvent() to handle the backspace or delete key case.
- *
- * @param[in] controller A reference to the controller class
- * @param[in] keyCode The keycode for the key pressed
- * @return True if a character was deleted.
- */
- static bool DeleteEvent(Controller& controller, int keyCode);
-
- static InputMethodContext::CallbackData OnInputMethodContextEvent(Controller& controller,
- InputMethodContext& inputMethodContext,
- const InputMethodContext::EventData& inputMethodContextEvent);
-
- static void PasteClipboardItemEvent(Controller& controller);
- static void DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y);
- static void TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button);
-};
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-run-container.h>
-
-namespace Dali::Toolkit::Text
-{
-
-void ControllerImplDataClearer::ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations)
-{
- ModelPtr& model = impl.mModel;
-
- if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
- {
- model->mLogicalModel->mLineBreakInfo.Clear();
- model->mLogicalModel->mParagraphInfo.Clear();
- }
-
- if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations))
- {
- model->mLogicalModel->mScriptRuns.Clear();
- }
-
- if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations))
- {
- model->mLogicalModel->mFontRuns.Clear();
- }
-
- if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count())
- {
- if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
- {
- model->mLogicalModel->mBidirectionalParagraphInfo.Clear();
- model->mLogicalModel->mCharacterDirections.Clear();
- }
-
- if(Controller::NO_OPERATION != (Controller::REORDER & operations))
- {
- // Free the allocated memory used to store the conversion table in the bidirectional line info run.
- for(Vector<BidirectionalLineInfoRun>::Iterator it = model->mLogicalModel->mBidirectionalLineInfo.Begin(),
- endIt = model->mLogicalModel->mBidirectionalLineInfo.End();
- it != endIt;
- ++it)
- {
- BidirectionalLineInfoRun& bidiLineInfo = *it;
-
- free(bidiLineInfo.visualToLogicalMap);
- bidiLineInfo.visualToLogicalMap = NULL;
- }
- model->mLogicalModel->mBidirectionalLineInfo.Clear();
- }
- }
-
- if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
- {
- model->mVisualModel->mGlyphs.Clear();
- model->mVisualModel->mGlyphsToCharacters.Clear();
- model->mVisualModel->mCharactersToGlyph.Clear();
- model->mVisualModel->mCharactersPerGlyph.Clear();
- model->mVisualModel->mGlyphsPerCharacter.Clear();
- model->mVisualModel->mGlyphPositions.Clear();
- }
-
- if(Controller::NO_OPERATION != (Controller::LAYOUT & operations))
- {
- model->mVisualModel->mLines.Clear();
- }
-
- if(Controller::NO_OPERATION != (Controller::COLOR & operations))
- {
- model->mVisualModel->mColorIndices.Clear();
- model->mVisualModel->mBackgroundColorIndices.Clear();
- }
-}
-
-void ControllerImplDataClearer::ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
-{
- const CharacterIndex endIndexPlusOne = endIndex + 1u;
- ModelPtr& model = impl.mModel;
-
- if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
- {
- // Clear the line break info.
- LineBreakInfo* lineBreakInfoBuffer = model->mLogicalModel->mLineBreakInfo.Begin();
-
- model->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
- lineBreakInfoBuffer + endIndexPlusOne);
-
- // Clear the paragraphs.
- ClearCharacterRuns(startIndex,
- endIndex,
- model->mLogicalModel->mParagraphInfo);
- }
-
- if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations))
- {
- // Clear the scripts.
- ClearCharacterRuns(startIndex,
- endIndex,
- model->mLogicalModel->mScriptRuns);
- }
-
- if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations))
- {
- // Clear the fonts.
- ClearCharacterRuns(startIndex,
- endIndex,
- model->mLogicalModel->mFontRuns);
- }
-
- if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count())
- {
- if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
- {
- // Clear the bidirectional paragraph info.
- ClearCharacterRuns(startIndex,
- endIndex,
- model->mLogicalModel->mBidirectionalParagraphInfo);
-
- // Clear the character's directions.
- CharacterDirection* characterDirectionsBuffer = model->mLogicalModel->mCharacterDirections.Begin();
-
- model->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
- characterDirectionsBuffer + endIndexPlusOne);
- }
-
- if(Controller::NO_OPERATION != (Controller::REORDER & operations))
- {
- uint32_t startRemoveIndex = model->mLogicalModel->mBidirectionalLineInfo.Count();
- uint32_t endRemoveIndex = startRemoveIndex;
- ClearCharacterRuns(startIndex,
- endIndex,
- model->mLogicalModel->mBidirectionalLineInfo,
- startRemoveIndex,
- endRemoveIndex);
-
- BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = model->mLogicalModel->mBidirectionalLineInfo.Begin();
-
- // Free the allocated memory used to store the conversion table in the bidirectional line info run.
- for(Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
- endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
- it != endIt;
- ++it)
- {
- BidirectionalLineInfoRun& bidiLineInfo = *it;
-
- free(bidiLineInfo.visualToLogicalMap);
- bidiLineInfo.visualToLogicalMap = NULL;
- }
-
- model->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
- bidirectionalLineInfoBuffer + endRemoveIndex);
- }
- }
-}
-
-void ControllerImplDataClearer::ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
-{
- const CharacterIndex endIndexPlusOne = endIndex + 1u;
- const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
- ModelPtr& model = impl.mModel;
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
-
-
- // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
- GlyphIndex* charactersToGlyphBuffer = model->mVisualModel->mCharactersToGlyph.Begin();
- Length* glyphsPerCharacterBuffer = model->mVisualModel->mGlyphsPerCharacter.Begin();
-
- const GlyphIndex endGlyphIndexPlusOne = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
- const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - textUpdateInfo.mStartGlyphIndex;
-
- if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
- {
- // Update the character to glyph indices.
- for(Vector<GlyphIndex>::Iterator it = charactersToGlyphBuffer + endIndexPlusOne,
- endIt = charactersToGlyphBuffer + model->mVisualModel->mCharactersToGlyph.Count();
- it != endIt;
- ++it)
- {
- CharacterIndex& index = *it;
- index -= numberOfGlyphsRemoved;
- }
-
- // Clear the character to glyph conversion table.
- model->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
- charactersToGlyphBuffer + endIndexPlusOne);
-
- // Clear the glyphs per character table.
- model->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
- glyphsPerCharacterBuffer + endIndexPlusOne);
-
- // Clear the glyphs buffer.
- GlyphInfo* glyphsBuffer = model->mVisualModel->mGlyphs.Begin();
- model->mVisualModel->mGlyphs.Erase(glyphsBuffer + textUpdateInfo.mStartGlyphIndex,
- glyphsBuffer + endGlyphIndexPlusOne);
-
- CharacterIndex* glyphsToCharactersBuffer = model->mVisualModel->mGlyphsToCharacters.Begin();
-
- // Update the glyph to character indices.
- for(Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
- endIt = glyphsToCharactersBuffer + model->mVisualModel->mGlyphsToCharacters.Count();
- it != endIt;
- ++it)
- {
- CharacterIndex& index = *it;
- index -= numberOfCharactersRemoved;
- }
-
- // Clear the glyphs to characters buffer.
- model->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + textUpdateInfo.mStartGlyphIndex,
- glyphsToCharactersBuffer + endGlyphIndexPlusOne);
-
- // Clear the characters per glyph buffer.
- Length* charactersPerGlyphBuffer = model->mVisualModel->mCharactersPerGlyph.Begin();
- model->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + textUpdateInfo.mStartGlyphIndex,
- charactersPerGlyphBuffer + endGlyphIndexPlusOne);
-
- // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
- if(0u != model->mVisualModel->mGlyphPositions.Count())
- {
- // Clear the positions buffer.
- Vector2* positionsBuffer = model->mVisualModel->mGlyphPositions.Begin();
- model->mVisualModel->mGlyphPositions.Erase(positionsBuffer + textUpdateInfo.mStartGlyphIndex,
- positionsBuffer + endGlyphIndexPlusOne);
- }
- }
-
- if(Controller::NO_OPERATION != (Controller::LAYOUT & operations))
- {
- // Clear the lines.
- uint32_t startRemoveIndex = model->mVisualModel->mLines.Count();
- uint32_t endRemoveIndex = startRemoveIndex;
- ClearCharacterRuns(startIndex,
- endIndex,
- model->mVisualModel->mLines,
- startRemoveIndex,
- endRemoveIndex);
-
- // Will update the glyph runs.
- startRemoveIndex = model->mVisualModel->mLines.Count();
- endRemoveIndex = startRemoveIndex;
- ClearGlyphRuns(textUpdateInfo.mStartGlyphIndex,
- endGlyphIndexPlusOne - 1u,
- model->mVisualModel->mLines,
- startRemoveIndex,
- endRemoveIndex);
-
- // Set the line index from where to insert the new laid-out lines.
- textUpdateInfo.mStartLineIndex = startRemoveIndex;
-
- LineRun* linesBuffer = model->mVisualModel->mLines.Begin();
- model->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
- linesBuffer + endRemoveIndex);
- }
-
- if(Controller::NO_OPERATION != (Controller::COLOR & operations))
- {
- if(0u != model->mVisualModel->mColorIndices.Count())
- {
- ColorIndex* colorIndexBuffer = model->mVisualModel->mColorIndices.Begin();
- model->mVisualModel->mColorIndices.Erase(colorIndexBuffer + textUpdateInfo.mStartGlyphIndex,
- colorIndexBuffer + endGlyphIndexPlusOne);
- }
-
- if(0u != model->mVisualModel->mBackgroundColorIndices.Count())
- {
- ColorIndex* backgroundColorIndexBuffer = model->mVisualModel->mBackgroundColorIndices.Begin();
- model->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + textUpdateInfo.mStartGlyphIndex,
- backgroundColorIndexBuffer + endGlyphIndexPlusOne);
- }
- }
-}
-
-void ControllerImplDataClearer::ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
-{
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
-
- if(textUpdateInfo.mClearAll ||
- ((0u == startIndex) &&
- (textUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
- {
- ClearFullModelData(impl, operations);
- }
- else
- {
- // Clear the model data related with characters.
- ClearCharacterModelData(impl, startIndex, endIndex, operations);
-
- // Clear the model data related with glyphs.
- ClearGlyphModelData(impl, startIndex, endIndex, operations);
- }
-
- ModelPtr& model = impl.mModel;
-
- // The estimated number of lines. Used to avoid reallocations when layouting.
- textUpdateInfo.mEstimatedNumberOfLines = std::max(model->mVisualModel->mLines.Count(), model->mLogicalModel->mParagraphInfo.Count());
-
- model->mVisualModel->ClearCaches();
-}
-
-} // namespace Dali::Toolkit::Text
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
-
-namespace Dali::Toolkit::Text
-{
-
-/// Provides methods to clear some of the model data in the Text::Controller::Impl
-struct ControllerImplDataClearer
-{
-
- /**
- * @brief Helper to clear completely the parts of the model specified by the given @p operations.
- *
- * @note It never clears the text stored in utf32.
- *
- * @param[in] impl The text controller impl.
- * @param[in] operations The operations required.
- */
- static void ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations);
-
- /**
- * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations.
- *
- * @note It never clears the text stored in utf32.
- *
- * @param[in] impl The text controller impl.
- * @param[in] startIndex Index to the first character to be cleared.
- * @param[in] endIndex Index to the last character to be cleared.
- * @param[in] operations The operations required.
- */
- static void ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
-
- /**
- * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations.
- *
- * @note It never clears the text stored in utf32.
- * @note Character indices are transformed to glyph indices.
- *
- * @param[in] impl The text controller impl.
- * @param[in] startIndex Index to the first character to be cleared.
- * @param[in] endIndex Index to the last character to be cleared.
- * @param[in] operations The operations required.
- */
- static void ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
-
- /**
- * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
- *
- * @note It never clears the text stored in utf32.
- *
- * @param[in] impl The text controller impl.
- * @param[in] startIndex Index to the first character to be cleared.
- * @param[in] endIndex Index to the last character to be cleared.
- * @param[in] operations The operations required.
- */
- static void ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
-};
-
-} // namespace Dali::Toolkit::Text
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <dali/public-api/adaptor-framework/key.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-
-using namespace Dali;
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-} // namespace
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-bool ControllerImplEventHandler::ProcessInputEvents(Controller::Impl& impl)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n");
-
- EventData*& eventData = impl.mEventData;
- if(NULL == eventData)
- {
- // Nothing to do if there is no text input.
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n");
- return false;
- }
-
- unsigned int oldPos = eventData->mPrimaryCursorPosition;
-
- if(eventData->mDecorator)
- {
- for(std::vector<Event>::iterator iter = eventData->mEventQueue.begin();
- iter != eventData->mEventQueue.end();
- ++iter)
- {
- switch(iter->type)
- {
- case Event::CURSOR_KEY_EVENT:
- {
- OnCursorKeyEvent(impl, *iter);
- break;
- }
- case Event::TAP_EVENT:
- {
- OnTapEvent(impl, *iter);
- break;
- }
- case Event::LONG_PRESS_EVENT:
- {
- OnLongPressEvent(impl, *iter);
- break;
- }
- case Event::PAN_EVENT:
- {
- OnPanEvent(impl, *iter);
- break;
- }
- case Event::GRAB_HANDLE_EVENT:
- case Event::LEFT_SELECTION_HANDLE_EVENT:
- case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
- {
- OnHandleEvent(impl, *iter);
- break;
- }
- case Event::SELECT:
- {
- OnSelectEvent(impl, *iter);
- break;
- }
- case Event::SELECT_ALL:
- {
- OnSelectAllEvent(impl);
- break;
- }
- case Event::SELECT_NONE:
- {
- OnSelectNoneEvent(impl);
- break;
- }
- case Event::SELECT_RANGE:
- {
- OnSelectRangeEvent(impl, *iter);
- break;
- }
- }
- }
- }
-
- if(eventData->mUpdateCursorPosition ||
- eventData->mUpdateHighlightBox)
- {
- impl.NotifyInputMethodContext();
- }
-
- // The cursor must also be repositioned after inserts into the model
- if(eventData->mUpdateCursorPosition)
- {
- // Updates the cursor position and scrolls the text to make it visible.
- CursorInfo cursorInfo;
-
- // Calculate the cursor position from the new cursor index.
- impl.GetCursorPosition(eventData->mPrimaryCursorPosition, cursorInfo);
-
- //only emit the event if the cursor is moved in current function.
- if(nullptr != impl.mEditableControlInterface && eventData->mEventQueue.size() > 0)
- {
- impl.mEditableControlInterface->CursorPositionChanged(oldPos, eventData->mPrimaryCursorPosition);
- }
-
- if(eventData->mUpdateCursorHookPosition)
- {
- // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
- eventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
- eventData->mUpdateCursorHookPosition = false;
- }
-
- // Scroll first the text after delete ...
- if(eventData->mScrollAfterDelete)
- {
- impl.ScrollTextToMatchCursor(cursorInfo);
- }
-
- // ... then, text can be scrolled to make the cursor visible.
- if(eventData->mScrollAfterUpdatePosition)
- {
- const Vector2 currentCursorPosition(cursorInfo.primaryPosition.x, cursorInfo.lineOffset);
- impl.ScrollToMakePositionVisible(currentCursorPosition, cursorInfo.lineHeight);
- }
- eventData->mScrollAfterUpdatePosition = false;
- eventData->mScrollAfterDelete = false;
-
- impl.UpdateCursorPosition(cursorInfo);
-
- eventData->mDecoratorUpdated = true;
- eventData->mUpdateCursorPosition = false;
- eventData->mUpdateGrabHandlePosition = false;
- }
-
- if(eventData->mUpdateHighlightBox ||
- eventData->mUpdateLeftSelectionPosition ||
- eventData->mUpdateRightSelectionPosition)
- {
- CursorInfo leftHandleInfo;
- CursorInfo rightHandleInfo;
-
- if(eventData->mUpdateHighlightBox)
- {
- impl.GetCursorPosition(eventData->mLeftSelectionPosition, leftHandleInfo);
-
- impl.GetCursorPosition(eventData->mRightSelectionPosition, rightHandleInfo);
-
- if(eventData->mScrollAfterUpdatePosition && (eventData->mIsLeftHandleSelected ? eventData->mUpdateLeftSelectionPosition : eventData->mUpdateRightSelectionPosition))
- {
- if(eventData->mIsLeftHandleSelected && eventData->mIsRightHandleSelected)
- {
- CursorInfo& infoLeft = leftHandleInfo;
-
- const Vector2 currentCursorPositionLeft(infoLeft.primaryPosition.x, infoLeft.lineOffset);
- impl.ScrollToMakePositionVisible(currentCursorPositionLeft, infoLeft.lineHeight);
-
- CursorInfo& infoRight = rightHandleInfo;
-
- const Vector2 currentCursorPositionRight(infoRight.primaryPosition.x, infoRight.lineOffset);
- impl.ScrollToMakePositionVisible(currentCursorPositionRight, infoRight.lineHeight);
- }
- else
- {
- CursorInfo& info = eventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
-
- const Vector2 currentCursorPosition(info.primaryPosition.x, info.lineOffset);
- impl.ScrollToMakePositionVisible(currentCursorPosition, info.lineHeight);
- }
- }
- }
-
- if(eventData->mUpdateLeftSelectionPosition)
- {
- impl.UpdateSelectionHandle(LEFT_SELECTION_HANDLE, leftHandleInfo);
-
- impl.SetPopupButtons();
- eventData->mDecoratorUpdated = true;
- eventData->mUpdateLeftSelectionPosition = false;
- }
-
- if(eventData->mUpdateRightSelectionPosition)
- {
- impl.UpdateSelectionHandle(RIGHT_SELECTION_HANDLE, rightHandleInfo);
-
- impl.SetPopupButtons();
- eventData->mDecoratorUpdated = true;
- eventData->mUpdateRightSelectionPosition = false;
- }
-
- if(eventData->mUpdateHighlightBox)
- {
- impl.RepositionSelectionHandles();
-
- eventData->mUpdateLeftSelectionPosition = false;
- eventData->mUpdateRightSelectionPosition = false;
- eventData->mUpdateHighlightBox = false;
- eventData->mIsLeftHandleSelected = false;
- eventData->mIsRightHandleSelected = false;
- }
-
- eventData->mScrollAfterUpdatePosition = false;
- }
-
- if(eventData->mUpdateInputStyle)
- {
- // Keep a copy of the current input style.
- InputStyle currentInputStyle;
- currentInputStyle.Copy(eventData->mInputStyle);
-
- // Set the default style first.
- impl.RetrieveDefaultInputStyle(eventData->mInputStyle);
-
- // Get the character index from the cursor index.
- const CharacterIndex styleIndex = (eventData->mPrimaryCursorPosition > 0u) ? eventData->mPrimaryCursorPosition - 1u : 0u;
-
- // Retrieve the style from the style runs stored in the logical model.
- impl.mModel->mLogicalModel->RetrieveStyle(styleIndex, eventData->mInputStyle);
-
- // Compare if the input style has changed.
- const bool hasInputStyleChanged = !currentInputStyle.Equal(eventData->mInputStyle);
-
- if(hasInputStyleChanged)
- {
- const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(eventData->mInputStyle);
- // Queue the input style changed signal.
- eventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
- }
-
- eventData->mUpdateInputStyle = false;
- }
-
- eventData->mEventQueue.clear();
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n");
-
- const bool decoratorUpdated = eventData->mDecoratorUpdated;
- eventData->mDecoratorUpdated = false;
-
- return decoratorUpdated;
-}
-
-void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const Event& event)
-{
- if(NULL == impl.mEventData || !impl.IsShowingRealText())
- {
- // Nothing to do if there is no text input.
- return;
- }
-
- int keyCode = event.p1.mInt;
- bool isShiftModifier = event.p2.mBool;
- EventData& eventData = *impl.mEventData;
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
- VisualModelPtr& visualModel = model->mVisualModel;
- uint32_t oldSelStart = eventData.mLeftSelectionPosition;
- uint32_t oldSelEnd = eventData.mRightSelectionPosition;
-
- CharacterIndex& primaryCursorPosition = eventData.mPrimaryCursorPosition;
- CharacterIndex previousPrimaryCursorPosition = primaryCursorPosition;
-
- if(Dali::DALI_KEY_CURSOR_LEFT == keyCode)
- {
- if(primaryCursorPosition > 0u)
- {
- if(!isShiftModifier && eventData.mDecorator->IsHighlightVisible())
- {
- primaryCursorPosition = std::min(eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- else
- {
- primaryCursorPosition = impl.CalculateNewCursorIndex(primaryCursorPosition - 1u);
- }
- }
- }
- else if(Dali::DALI_KEY_CURSOR_RIGHT == keyCode)
- {
- if(logicalModel->mText.Count() > primaryCursorPosition)
- {
- if(!isShiftModifier && eventData.mDecorator->IsHighlightVisible())
- {
- primaryCursorPosition = std::max(eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- else
- {
- primaryCursorPosition = impl.CalculateNewCursorIndex(primaryCursorPosition);
- }
- }
- }
- else if(Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier)
- {
- // Ignore Shift-Up for text selection for now.
-
- // Get first the line index of the current cursor position index.
- CharacterIndex characterIndex = 0u;
-
- if(primaryCursorPosition > 0u)
- {
- characterIndex = primaryCursorPosition - 1u;
- }
-
- const LineIndex lineIndex = visualModel->GetLineOfCharacter(characterIndex);
- const LineIndex previousLineIndex = (lineIndex > 0 ? lineIndex - 1u : lineIndex);
- const LineIndex lastLineIndex = (visualModel->mLines.Size() > 0 ? visualModel->mLines.Size() - 1u : 0);
- const bool isLastLine = (previousLineIndex == lastLineIndex);
-
- // Retrieve the cursor position info.
- CursorInfo cursorInfo;
- impl.GetCursorPosition(primaryCursorPosition,
- cursorInfo);
-
- // Get the line above.
- const LineRun& line = *(visualModel->mLines.Begin() + previousLineIndex);
-
- // Get the next hit 'y' point.
- const float hitPointY = cursorInfo.lineOffset - 0.5f * GetLineHeight(line, isLastLine);
-
- // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
- bool matchedCharacter = false;
- primaryCursorPosition = Text::GetClosestCursorIndex(visualModel,
- logicalModel,
- impl.mMetrics,
- eventData.mCursorHookPositionX,
- hitPointY,
- CharacterHitTest::TAP,
- matchedCharacter);
- }
- else if(Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier)
- {
- // Ignore Shift-Down for text selection for now.
-
- // Get first the line index of the current cursor position index.
- CharacterIndex characterIndex = 0u;
-
- if(primaryCursorPosition > 0u)
- {
- characterIndex = primaryCursorPosition - 1u;
- }
-
- const LineIndex lineIndex = visualModel->GetLineOfCharacter(characterIndex);
-
- if(lineIndex + 1u < visualModel->mLines.Count())
- {
- // Retrieve the cursor position info.
- CursorInfo cursorInfo;
- impl.GetCursorPosition(primaryCursorPosition, cursorInfo);
-
- // Get the line below.
- const LineRun& nextline = *(visualModel->mLines.Begin() + lineIndex + 1u);
- const LineRun& currline = *(visualModel->mLines.Begin() + lineIndex);
-
- // Get last line index
- const LineIndex lastLineIndex = (visualModel->mLines.Size() > 0 ? visualModel->mLines.Size() - 1u : 0);
- const bool isLastLine = (lineIndex + 1u == lastLineIndex);
-
- // Get the next hit 'y' point.
- const float hitPointY = cursorInfo.lineOffset + GetLineHeight(currline, false) + 0.5f * GetLineHeight(nextline, isLastLine);
-
- // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
- bool matchedCharacter = false;
- primaryCursorPosition = Text::GetClosestCursorIndex(visualModel,
- logicalModel,
- impl.mMetrics,
- eventData.mCursorHookPositionX,
- hitPointY,
- CharacterHitTest::TAP,
- matchedCharacter);
- }
- }
-
- if(!isShiftModifier && eventData.mState != EventData::SELECTING)
- {
- // Update selection position after moving the cursor
- eventData.mLeftSelectionPosition = primaryCursorPosition;
- eventData.mRightSelectionPosition = primaryCursorPosition;
-
- if(impl.mSelectableControlInterface != nullptr && eventData.mDecorator->IsHighlightVisible())
- {
- impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- }
-
- if(isShiftModifier && impl.IsShowingRealText() && eventData.mShiftSelectionFlag)
- {
- // Handle text selection
- bool selecting = false;
-
- if(Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode)
- {
- // Shift-Left/Right to select the text
- int cursorPositionDelta = primaryCursorPosition - previousPrimaryCursorPosition;
- if(cursorPositionDelta > 0 || eventData.mRightSelectionPosition > 0u) // Check the boundary
- {
- eventData.mRightSelectionPosition += cursorPositionDelta;
- eventData.mPrimaryCursorPosition = eventData.mRightSelectionPosition;
-
- if(impl.mSelectableControlInterface != nullptr)
- {
- impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- }
-
- if(impl.mSelectableControlInterface != nullptr && eventData.mLeftSelectionPosition == eventData.mRightSelectionPosition)
- {
- // If left selection position and right selection position are the same, the selection is canceled.
- selecting = false;
- }
- else
- {
- selecting = true;
- }
- }
- else if(eventData.mLeftSelectionPosition != eventData.mRightSelectionPosition)
- {
- // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
- selecting = true;
- }
-
- if(selecting)
- {
- // Notify the cursor position to the InputMethodContext.
- if(eventData.mInputMethodContext)
- {
- eventData.mInputMethodContext.SetCursorPosition(primaryCursorPosition);
- eventData.mInputMethodContext.NotifyCursorPosition();
- }
-
- impl.ChangeState(EventData::SELECTING);
-
- eventData.mUpdateLeftSelectionPosition = true;
- eventData.mUpdateRightSelectionPosition = true;
- eventData.mUpdateGrabHandlePosition = true;
- eventData.mUpdateHighlightBox = true;
-
- // Hide the text selection popup if select the text using keyboard instead of moving grab handles
- if(eventData.mGrabHandlePopupEnabled)
- {
- eventData.mDecorator->SetPopupActive(false);
- }
- }
- else
- {
- // If no selection, set a normal cursor.
- impl.ChangeState(EventData::EDITING);
- eventData.mUpdateCursorPosition = true;
- }
- }
- else
- {
- // Handle normal cursor move
- impl.ChangeState(EventData::EDITING);
- eventData.mUpdateCursorPosition = true;
- }
-
- eventData.mUpdateInputStyle = true;
- eventData.mScrollAfterUpdatePosition = true;
-}
-
-void ControllerImplEventHandler::OnTapEvent(Controller::Impl& impl, const Event& event)
-{
- if(impl.mEventData)
- {
- const unsigned int tapCount = event.p1.mUint;
- EventData& eventData = *impl.mEventData;
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
- VisualModelPtr& visualModel = model->mVisualModel;
-
- if(1u == tapCount)
- {
- if(impl.IsShowingRealText())
- {
- // Convert from control's coords to text's coords.
- const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
- const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
- uint32_t oldSelStart = eventData.mLeftSelectionPosition;
- uint32_t oldSelEnd = eventData.mRightSelectionPosition;
-
- // Keep the tap 'x' position. Used to move the cursor.
- eventData.mCursorHookPositionX = xPosition;
-
- // Whether to touch point hits on a glyph.
- bool matchedCharacter = false;
- eventData.mPrimaryCursorPosition = Text::GetClosestCursorIndex(visualModel,
- logicalModel,
- impl.mMetrics,
- xPosition,
- yPosition,
- CharacterHitTest::TAP,
- matchedCharacter);
-
- if(impl.mSelectableControlInterface != nullptr && eventData.mDecorator->IsHighlightVisible())
- {
- impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mPrimaryCursorPosition, eventData.mPrimaryCursorPosition);
- }
-
- // When the cursor position is changing, delay cursor blinking
- eventData.mDecorator->DelayCursorBlink();
- }
- else
- {
- eventData.mPrimaryCursorPosition = 0u;
- }
-
- // Update selection position after tapping
- eventData.mLeftSelectionPosition = eventData.mPrimaryCursorPosition;
- eventData.mRightSelectionPosition = eventData.mPrimaryCursorPosition;
-
- eventData.mUpdateCursorPosition = true;
- eventData.mUpdateGrabHandlePosition = true;
- eventData.mScrollAfterUpdatePosition = true;
- eventData.mUpdateInputStyle = true;
-
- // Notify the cursor position to the InputMethodContext.
- if(eventData.mInputMethodContext)
- {
- eventData.mInputMethodContext.SetCursorPosition(eventData.mPrimaryCursorPosition);
- eventData.mInputMethodContext.NotifyCursorPosition();
- }
- }
- else if(2u == tapCount)
- {
- if(eventData.mSelectionEnabled)
- {
- // Convert from control's coords to text's coords.
- const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
- const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
-
- // Calculates the logical position from the x,y coords.
- impl.RepositionSelectionHandles(xPosition, yPosition, eventData.mDoubleTapAction);
- }
- }
- }
-}
-
-void ControllerImplEventHandler::OnPanEvent(Controller::Impl& impl, const Event& event)
-{
- if(impl.mEventData)
- {
- EventData& eventData = *impl.mEventData;
- DecoratorPtr& decorator = eventData.mDecorator;
-
- const bool isHorizontalScrollEnabled = decorator->IsHorizontalScrollEnabled();
- const bool isVerticalScrollEnabled = decorator->IsVerticalScrollEnabled();
-
- if(!isHorizontalScrollEnabled && !isVerticalScrollEnabled)
- {
- // Nothing to do if scrolling is not enabled.
- return;
- }
-
- const GestureState state = static_cast<GestureState>(event.p1.mInt);
- switch(state)
- {
- case GestureState::STARTED:
- {
- // Will remove the cursor, handles or text's popup, ...
- impl.ChangeState(EventData::TEXT_PANNING);
- break;
- }
- case GestureState::CONTINUING:
- {
- ModelPtr& model = impl.mModel;
-
- const Vector2& layoutSize = model->mVisualModel->GetLayoutSize();
- Vector2& scrollPosition = model->mScrollPosition;
- const Vector2 currentScroll = scrollPosition;
-
- if(isHorizontalScrollEnabled)
- {
- const float displacementX = event.p2.mFloat;
- scrollPosition.x += displacementX;
-
- impl.ClampHorizontalScroll(layoutSize);
- }
-
- if(isVerticalScrollEnabled)
- {
- const float displacementY = event.p3.mFloat;
- scrollPosition.y += displacementY;
-
- impl.ClampVerticalScroll(layoutSize);
- }
-
- decorator->UpdatePositions(scrollPosition - currentScroll);
- break;
- }
- case GestureState::FINISHED:
- case GestureState::CANCELLED: // FALLTHROUGH
- {
- // Will go back to the previous state to show the cursor, handles, the text's popup, ...
- impl.ChangeState(eventData.mPreviousState);
- break;
- }
- default:
- break;
- }
- }
-}
-
-void ControllerImplEventHandler::OnLongPressEvent(Controller::Impl& impl, const Event& event)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::OnLongPressEvent\n");
-
- if(impl.mEventData)
- {
- EventData& eventData = *impl.mEventData;
-
- if(!impl.IsShowingRealText() && (EventData::EDITING == eventData.mState))
- {
- impl.ChangeState(EventData::EDITING_WITH_POPUP);
- eventData.mDecoratorUpdated = true;
- eventData.mUpdateInputStyle = true;
- }
- else
- {
- if(eventData.mSelectionEnabled)
- {
- ModelPtr& model = impl.mModel;
-
- // Convert from control's coords to text's coords.
- const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
- const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
-
- // Calculates the logical position from the x,y coords.
- impl.RepositionSelectionHandles(xPosition, yPosition, eventData.mLongPressAction);
- }
- }
- }
-}
-
-void ControllerImplEventHandler::OnHandleEvent(Controller::Impl& impl, const Event& event)
-{
- if(impl.mEventData)
- {
- const unsigned int state = event.p1.mUint;
- const bool handleStopScrolling = (HANDLE_STOP_SCROLLING == state);
- const bool isSmoothHandlePanEnabled = impl.mEventData->mDecorator->IsSmoothHandlePanEnabled();
-
- if(HANDLE_PRESSED == state)
- {
- OnHandlePressed(impl, event, isSmoothHandlePanEnabled);
- } // end ( HANDLE_PRESSED == state )
- else if((HANDLE_RELEASED == state) ||
- handleStopScrolling)
- {
- OnHandleReleased(impl, event, isSmoothHandlePanEnabled, handleStopScrolling);
- } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
- else if(HANDLE_SCROLLING == state)
- {
- OnHandleScrolling(impl, event, isSmoothHandlePanEnabled);
- } // end ( HANDLE_SCROLLING == state )
- }
-}
-
-void ControllerImplEventHandler::OnSelectEvent(Controller::Impl& impl, const Event& event)
-{
- if(impl.mEventData && impl.mEventData->mSelectionEnabled)
- {
- ModelPtr& model = impl.mModel;
- const Vector2& scrollPosition = model->mScrollPosition;
-
- // Convert from control's coords to text's coords.
- const float xPosition = event.p2.mFloat - scrollPosition.x;
- const float yPosition = event.p3.mFloat - scrollPosition.y;
-
- // Calculates the logical position from the x,y coords.
- impl.RepositionSelectionHandles(xPosition, yPosition, Controller::NoTextTap::HIGHLIGHT);
- }
-}
-
-void ControllerImplEventHandler::OnSelectAllEvent(Controller::Impl& impl)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", impl.mEventData->mSelectionEnabled ? "true" : "false");
-
- if(impl.mEventData)
- {
- EventData& eventData = *impl.mEventData;
- if(eventData.mSelectionEnabled && eventData.mState != EventData::INACTIVE)
- {
- ModelPtr& model = impl.mModel;
- const Vector2& scrollPosition = model->mScrollPosition;
-
- // Calculates the logical position from the start.
- impl.RepositionSelectionHandles(0.f - scrollPosition.x,
- 0.f - scrollPosition.y,
- Controller::NoTextTap::HIGHLIGHT);
-
- uint32_t oldStart = eventData.mLeftSelectionPosition;
- uint32_t oldEnd = eventData.mRightSelectionPosition;
-
- eventData.mLeftSelectionPosition = 0u;
- eventData.mRightSelectionPosition = model->mLogicalModel->mText.Count();
- eventData.mPrimaryCursorPosition = eventData.mRightSelectionPosition;
-
- if(impl.mSelectableControlInterface != nullptr)
- {
- impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- }
- }
-}
-
-void ControllerImplEventHandler::OnSelectNoneEvent(Controller::Impl& impl)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "OnSelectNoneEvent mEventData->mSelectionEnabled%s \n", impl.mEventData->mSelectionEnabled ? "true" : "false");
-
- if(impl.mEventData)
- {
- EventData& eventData = *impl.mEventData;
- if(eventData.mSelectionEnabled && eventData.mState == EventData::SELECTING)
- {
- uint32_t oldStart = eventData.mLeftSelectionPosition;
- uint32_t oldEnd = eventData.mRightSelectionPosition;
-
- eventData.mLeftSelectionPosition = eventData.mRightSelectionPosition = eventData.mPrimaryCursorPosition;
- impl.ChangeState(EventData::EDITING);
- eventData.mUpdateCursorPosition = true;
- eventData.mUpdateInputStyle = true;
- eventData.mScrollAfterUpdatePosition = true;
-
- if(impl.mSelectableControlInterface != nullptr)
- {
- impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- }
- }
-}
-
-void ControllerImplEventHandler::OnSelectRangeEvent(Controller::Impl& impl, const Event& event)
-{
- if(impl.mEventData && impl.mEventData->mSelectionEnabled && impl.mEventData->mState != EventData::INACTIVE)
- {
- ModelPtr& model = impl.mModel;
- const Vector2& scrollPosition = model->mScrollPosition;
-
- // Calculate the selection index.
- const uint32_t length = static_cast<uint32_t>(model->mLogicalModel->mText.Count());
- const uint32_t start = std::min(event.p2.mUint, length);
- const uint32_t end = std::min(event.p3.mUint, length);
-
- if(start != end)
- {
- uint32_t oldStart = impl.mEventData->mLeftSelectionPosition;
- uint32_t oldEnd = impl.mEventData->mRightSelectionPosition;
-
- // Calculates the logical position from the x,y coords.
- impl.RepositionSelectionHandles(0.f - scrollPosition.x, 0.f - scrollPosition.y, Controller::NoTextTap::HIGHLIGHT);
-
- impl.mEventData->mLeftSelectionPosition = start;
- impl.mEventData->mRightSelectionPosition = end;
- impl.mEventData->mPrimaryCursorPosition = end;
-
- if(impl.mSelectableControlInterface != nullptr)
- {
- impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
- }
- }
- }
-}
-
-void ControllerImplEventHandler::OnHandlePressed(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled)
-{
- ModelPtr& model = impl.mModel;
- const Vector2& scrollPosition = model->mScrollPosition;
-
- // Convert from decorator's coords to text's coords.
- const float xPosition = event.p2.mFloat - scrollPosition.x;
- const float yPosition = event.p3.mFloat - scrollPosition.y;
-
- // Need to calculate the handle's new position.
- bool matchedCharacter = false;
- const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex(model->mVisualModel,
- model->mLogicalModel,
- impl.mMetrics,
- xPosition,
- yPosition,
- CharacterHitTest::SCROLL,
- matchedCharacter);
-
- EventData& eventData = *impl.mEventData;
- uint32_t oldStart = eventData.mLeftSelectionPosition;
- uint32_t oldEnd = eventData.mRightSelectionPosition;
-
- if(Event::GRAB_HANDLE_EVENT == event.type)
- {
- impl.ChangeState(EventData::GRAB_HANDLE_PANNING);
-
- if(handleNewPosition != eventData.mPrimaryCursorPosition)
- {
- // Updates the cursor position if the handle's new position is different than the current one.
- eventData.mUpdateCursorPosition = true;
- // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
- eventData.mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
- eventData.mPrimaryCursorPosition = handleNewPosition;
- }
-
- // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
- eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
- }
- else if(Event::LEFT_SELECTION_HANDLE_EVENT == event.type)
- {
- impl.ChangeState(EventData::SELECTION_HANDLE_PANNING);
-
- if((handleNewPosition != eventData.mLeftSelectionPosition) &&
- (handleNewPosition != eventData.mRightSelectionPosition))
- {
- // Updates the highlight box if the handle's new position is different than the current one.
- eventData.mUpdateHighlightBox = true;
- // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
- eventData.mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
- eventData.mLeftSelectionPosition = handleNewPosition;
- }
-
- // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
- eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
-
- // Will define the order to scroll the text to match the handle position.
- eventData.mIsLeftHandleSelected = true;
- eventData.mIsRightHandleSelected = false;
- }
- else if(Event::RIGHT_SELECTION_HANDLE_EVENT == event.type)
- {
- impl.ChangeState(EventData::SELECTION_HANDLE_PANNING);
-
- if((handleNewPosition != eventData.mRightSelectionPosition) &&
- (handleNewPosition != eventData.mLeftSelectionPosition))
- {
- // Updates the highlight box if the handle's new position is different than the current one.
- eventData.mUpdateHighlightBox = true;
- // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
- eventData.mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
- eventData.mRightSelectionPosition = handleNewPosition;
- }
-
- // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
- eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
-
- // Will define the order to scroll the text to match the handle position.
- eventData.mIsLeftHandleSelected = false;
- eventData.mIsRightHandleSelected = true;
- }
-
- if((impl.mSelectableControlInterface != nullptr) && ((oldStart != eventData.mLeftSelectionPosition) || (oldEnd != eventData.mRightSelectionPosition)))
- {
- impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
-}
-
-void ControllerImplEventHandler::OnHandleReleased(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled, const bool handleStopScrolling)
-{
- CharacterIndex handlePosition = 0u;
- if(handleStopScrolling || isSmoothHandlePanEnabled)
- {
- ModelPtr& model = impl.mModel;
- const Vector2& scrollPosition = model->mScrollPosition;
-
- // Convert from decorator's coords to text's coords.
- const float xPosition = event.p2.mFloat - scrollPosition.x;
- const float yPosition = event.p3.mFloat - scrollPosition.y;
-
- bool matchedCharacter = false;
- handlePosition = Text::GetClosestCursorIndex(model->mVisualModel,
- model->mLogicalModel,
- impl.mMetrics,
- xPosition,
- yPosition,
- CharacterHitTest::SCROLL,
- matchedCharacter);
- }
-
- EventData& eventData = *impl.mEventData;
- uint32_t oldStart = eventData.mLeftSelectionPosition;
- uint32_t oldEnd = eventData.mRightSelectionPosition;
-
- if(Event::GRAB_HANDLE_EVENT == event.type)
- {
- eventData.mUpdateCursorPosition = true;
- eventData.mUpdateGrabHandlePosition = true;
- eventData.mUpdateInputStyle = true;
-
- if(!impl.IsClipboardEmpty())
- {
- impl.ChangeState(EventData::EDITING_WITH_PASTE_POPUP); // Moving grabhandle will show Paste Popup
- }
-
- if(handleStopScrolling || isSmoothHandlePanEnabled)
- {
- eventData.mScrollAfterUpdatePosition = true;
- eventData.mPrimaryCursorPosition = handlePosition;
- }
- }
- else if(Event::LEFT_SELECTION_HANDLE_EVENT == event.type)
- {
- impl.ChangeState(EventData::SELECTING);
-
- eventData.mUpdateHighlightBox = true;
- eventData.mUpdateLeftSelectionPosition = true;
- eventData.mUpdateRightSelectionPosition = true;
-
- if(handleStopScrolling || isSmoothHandlePanEnabled)
- {
- eventData.mScrollAfterUpdatePosition = true;
-
- if((handlePosition != eventData.mRightSelectionPosition) &&
- (handlePosition != eventData.mLeftSelectionPosition))
- {
- eventData.mLeftSelectionPosition = handlePosition;
- }
- }
- }
- else if(Event::RIGHT_SELECTION_HANDLE_EVENT == event.type)
- {
- impl.ChangeState(EventData::SELECTING);
-
- eventData.mUpdateHighlightBox = true;
- eventData.mUpdateRightSelectionPosition = true;
- eventData.mUpdateLeftSelectionPosition = true;
-
- if(handleStopScrolling || isSmoothHandlePanEnabled)
- {
- eventData.mScrollAfterUpdatePosition = true;
- if((handlePosition != eventData.mRightSelectionPosition) &&
- (handlePosition != eventData.mLeftSelectionPosition))
- {
- eventData.mRightSelectionPosition = handlePosition;
- }
- }
- }
-
- if((impl.mSelectableControlInterface != nullptr) && ((oldStart != eventData.mLeftSelectionPosition) || (oldEnd != eventData.mRightSelectionPosition)))
- {
- impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
-
- eventData.mDecoratorUpdated = true;
-}
-
-void ControllerImplEventHandler::OnHandleScrolling(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled)
-{
- ModelPtr& model = impl.mModel;
- Vector2& scrollPosition = model->mScrollPosition;
- VisualModelPtr& visualModel = model->mVisualModel;
-
- const float xSpeed = event.p2.mFloat;
- const float ySpeed = event.p3.mFloat;
- const Vector2& layoutSize = visualModel->GetLayoutSize();
- const Vector2 currentScrollPosition = scrollPosition;
-
- scrollPosition.x += xSpeed;
- scrollPosition.y += ySpeed;
-
- impl.ClampHorizontalScroll(layoutSize);
- impl.ClampVerticalScroll(layoutSize);
-
- EventData& eventData = *impl.mEventData;
- DecoratorPtr& decorator = eventData.mDecorator;
-
- bool endOfScroll = false;
- if(Vector2::ZERO == (currentScrollPosition - scrollPosition))
- {
- // Notify the decorator there is no more text to scroll.
- // The decorator won't send more scroll events.
- decorator->NotifyEndOfScroll();
- // Still need to set the position of the handle.
- endOfScroll = true;
- }
-
- // Set the position of the handle.
- const bool scrollRightDirection = xSpeed > 0.f;
- const bool scrollBottomDirection = ySpeed > 0.f;
- const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
- const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
-
- if(Event::GRAB_HANDLE_EVENT == event.type)
- {
- impl.ChangeState(EventData::GRAB_HANDLE_PANNING);
-
- // Get the grab handle position in decorator coords.
- Vector2 position = decorator->GetPosition(GRAB_HANDLE);
-
- if(decorator->IsHorizontalScrollEnabled())
- {
- // Position the grag handle close to either the left or right edge.
- position.x = scrollRightDirection ? 0.f : visualModel->mControlSize.width;
- }
-
- if(decorator->IsVerticalScrollEnabled())
- {
- position.x = eventData.mCursorHookPositionX;
-
- // Position the grag handle close to either the top or bottom edge.
- position.y = scrollBottomDirection ? 0.f : visualModel->mControlSize.height;
- }
-
- // Get the new handle position.
- // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
- bool matchedCharacter = false;
- const CharacterIndex handlePosition = Text::GetClosestCursorIndex(visualModel,
- impl.mModel->mLogicalModel,
- impl.mMetrics,
- position.x - scrollPosition.x,
- position.y - scrollPosition.y,
- CharacterHitTest::SCROLL,
- matchedCharacter);
-
- if(eventData.mPrimaryCursorPosition != handlePosition)
- {
- eventData.mUpdateCursorPosition = true;
- eventData.mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
- eventData.mScrollAfterUpdatePosition = true;
- eventData.mPrimaryCursorPosition = handlePosition;
- }
- eventData.mUpdateInputStyle = eventData.mUpdateCursorPosition;
-
- // Updates the decorator if the soft handle panning is enabled.
- eventData.mDecoratorUpdated = isSmoothHandlePanEnabled;
- }
- else if(leftSelectionHandleEvent || rightSelectionHandleEvent)
- {
- impl.ChangeState(EventData::SELECTION_HANDLE_PANNING);
-
- // Get the selection handle position in decorator coords.
- Vector2 position = decorator->GetPosition(leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE);
-
- if(decorator->IsHorizontalScrollEnabled())
- {
- // Position the selection handle close to either the left or right edge.
- position.x = scrollRightDirection ? 0.f : visualModel->mControlSize.width;
- }
-
- if(decorator->IsVerticalScrollEnabled())
- {
- position.x = eventData.mCursorHookPositionX;
-
- // Position the grag handle close to either the top or bottom edge.
- position.y = scrollBottomDirection ? 0.f : visualModel->mControlSize.height;
- }
-
- // Get the new handle position.
- // The selection handle's position is in decorator's coords. Need to transform to text's coords.
- bool matchedCharacter = false;
- const CharacterIndex handlePosition = Text::GetClosestCursorIndex(visualModel,
- impl.mModel->mLogicalModel,
- impl.mMetrics,
- position.x - scrollPosition.x,
- position.y - scrollPosition.y,
- CharacterHitTest::SCROLL,
- matchedCharacter);
- uint32_t oldStart = eventData.mLeftSelectionPosition;
- uint32_t oldEnd = eventData.mRightSelectionPosition;
-
- if(leftSelectionHandleEvent)
- {
- const bool differentHandles = (eventData.mLeftSelectionPosition != handlePosition) && (eventData.mRightSelectionPosition != handlePosition);
-
- if(differentHandles || endOfScroll)
- {
- eventData.mUpdateHighlightBox = true;
- eventData.mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
- eventData.mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
- eventData.mLeftSelectionPosition = handlePosition;
- }
- }
- else
- {
- const bool differentHandles = (eventData.mRightSelectionPosition != handlePosition) && (eventData.mLeftSelectionPosition != handlePosition);
- if(differentHandles || endOfScroll)
- {
- eventData.mUpdateHighlightBox = true;
- eventData.mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
- eventData.mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
- eventData.mRightSelectionPosition = handlePosition;
- }
- }
-
- if(eventData.mUpdateLeftSelectionPosition || eventData.mUpdateRightSelectionPosition)
- {
- impl.RepositionSelectionHandles();
-
- eventData.mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
-
- if(impl.mSelectableControlInterface != nullptr)
- {
- impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
- }
- }
- }
- eventData.mDecoratorUpdated = true;
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_EVENT_HANDLER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_EVENT_HANDLER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-/**
- * Contains all the event handling methods for Text::Controller::Impl
- */
-struct ControllerImplEventHandler
-{
- /**
- * @brief Processes input events
- *
- * @param[in] impl A reference to Controller::Impl
- * @return True if the decorator has been updated
- */
- static bool ProcessInputEvents(Controller::Impl& impl);
-
- /**
- * @brief Called by Controller::Impl when a cursor key event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnCursorKeyEvent(Controller::Impl& controllerImpl, const Event& event);
-
- /**
- * @brief Called by Controller::Impl when a tap event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnTapEvent(Controller::Impl& controllerImpl, const Event& event);
-
- /**
- * @brief Called by Controller::Impl when a pan event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnPanEvent(Controller::Impl& controllerImpl, const Event& event);
-
- /**
- * @brief Called by Controller::Impl when a long press event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnLongPressEvent(Controller::Impl& controllerImpl, const Event& event);
-
- /**
- * @brief Called by Controller::Impl when a handle event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnHandleEvent(Controller::Impl& controllerImpl, const Event& event);
-
- /**
- * @brief Called by Controller::Impl when a select event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnSelectEvent(Controller::Impl& controllerImpl, const Event& event);
-
- /**
- * @brief Called by Controller::Impl when a select all event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnSelectAllEvent(Controller::Impl& controllerImpl);
-
- /**
- * @brief Called by Controller::Impl when a select none event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnSelectNoneEvent(Controller::Impl& controllerImpl);
-
- /**
- * @brief Called by Controller::Impl when a select range event is received.
- *
- * @param controllerImpl A reference to Controller::Impl
- * @param event The event
- */
- static void OnSelectRangeEvent(Controller::Impl& controllerImpl, const Event& event);
-
-private:
- /**
- * @brief Called by OnHandleEvent when we are in the Pressed state.
- *
- * @param impl A reference to Controller::Impl
- * @param event The event
- * @param isSmoothHandlePanEnabled Whether smooth handle pan is enabled
- */
- static void OnHandlePressed(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled);
-
- /**
- * @brief Called by OnHandleEvent when we are in the Released state.
- *
- * @param impl A reference to Controller::Impl
- * @param event The event
- * @param isSmoothHandlePanEnabled Whether smooth handle pan is enabled
- * @param handleStopScrolling Whether we should handle stop scrolling or not
- */
- static void OnHandleReleased(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled, const bool handleStopScrolling);
-
- /**
- * @brief Called by OnHandleEvent when we are in the Scrolling state.
- *
- * @param impl A reference to Controller::Impl
- * @param event The event
- * @param isSmoothHandlePanEnabled Whether smooth handle pan is enabled
- */
- static void OnHandleScrolling(Controller::Impl& impl, const Event& event, const bool isSmoothHandlePanEnabled);
-};
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_EVENT_HANDLER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/bidirectional-support.h>
-#include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/color-segmentation.h>
-#include <dali-toolkit/internal/text/hyphenator.h>
-#include <dali-toolkit/internal/text/multi-language-support.h>
-#include <dali-toolkit/internal/text/segmentation.h>
-#include <dali-toolkit/internal/text/shaper.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-
-namespace Dali::Toolkit::Text
-{
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-// The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
-// based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
-constexpr float BRIGHTNESS_THRESHOLD = 0.179f;
-constexpr float CONSTANT_R = 0.2126f;
-constexpr float CONSTANT_G = 0.7152f;
-constexpr float CONSTANT_B = 0.0722f;
-constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
-constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
-constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
-constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
-constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
-constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
-constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
-} // namespace
-
-bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
-
- // Calculate the operations to be done.
- const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
-
- if(Controller::NO_OPERATION == operations)
- {
- // Nothing to do if no operations are pending and required.
- return false;
- }
-
- Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
- Vector<Character> displayCharacters;
- bool useHiddenText = false;
- if(impl.mHiddenInput && impl.mEventData != nullptr && !impl.mEventData->mIsShowingPlaceholderText)
- {
- impl.mHiddenInput->Substitute(srcCharacters, displayCharacters);
- useHiddenText = true;
- }
-
- Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
- const Length numberOfCharacters = utf32Characters.Count();
-
- // Index to the first character of the first paragraph to be updated.
- CharacterIndex startIndex = 0u;
- // Number of characters of the paragraphs to be removed.
- Length paragraphCharacters = 0u;
-
- impl.CalculateTextUpdateIndices(paragraphCharacters);
-
- // Check whether the indices for updating the text is valid
- if(numberOfCharacters > 0u &&
- (impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
- impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
- {
- std::string currentText;
- Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
-
- DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
- DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
-
- // Dump mTextUpdateInfo
- DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
- DALI_LOG_ERROR(" mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
- DALI_LOG_ERROR(" mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
- DALI_LOG_ERROR(" mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
- DALI_LOG_ERROR(" mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
- DALI_LOG_ERROR(" mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
- DALI_LOG_ERROR(" mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
- DALI_LOG_ERROR(" mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
- DALI_LOG_ERROR(" mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
- DALI_LOG_ERROR(" mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
-
- return false;
- }
-
- startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
-
- if(impl.mTextUpdateInfo.mClearAll ||
- (0u != paragraphCharacters))
- {
- impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
- }
-
- impl.mTextUpdateInfo.mClearAll = false;
-
- // Whether the model is updated.
- bool updated = false;
-
- Vector<LineBreakInfo>& lineBreakInfo = impl.mModel->mLogicalModel->mLineBreakInfo;
- const Length requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
-
- if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
- {
- // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
- // calculate the bidirectional info for each 'paragraph'.
- // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
- // is not shaped together).
- lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
-
- SetLineBreakInfo(utf32Characters,
- startIndex,
- requestedNumberOfCharacters,
- lineBreakInfo);
-
- if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
- impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
- {
- CharacterIndex end = startIndex + requestedNumberOfCharacters;
- LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-
- for(CharacterIndex index = startIndex; index < end; index++)
- {
- CharacterIndex wordEnd = index;
- while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
- {
- wordEnd++;
- }
-
- if((wordEnd + 1) == end) // add last char
- {
- wordEnd++;
- }
-
- Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
-
- for(CharacterIndex i = 0; i < (wordEnd - index); i++)
- {
- if(hyphens[i])
- {
- *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
- }
- }
-
- index = wordEnd;
- }
- }
-
- // Create the paragraph info.
- impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
- requestedNumberOfCharacters);
- updated = true;
- }
-
- const bool getScripts = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
- const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
-
- Vector<ScriptRun>& scripts = impl.mModel->mLogicalModel->mScriptRuns;
- Vector<FontRun>& validFonts = impl.mModel->mLogicalModel->mFontRuns;
-
- if(getScripts || validateFonts)
- {
- // Validates the fonts assigned by the application or assigns default ones.
- // It makes sure all the characters are going to be rendered by the correct font.
- MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-
- if(getScripts)
- {
- // Retrieves the scripts used in the text.
- multilanguageSupport.SetScripts(utf32Characters,
- startIndex,
- requestedNumberOfCharacters,
- scripts);
- }
-
- if(validateFonts)
- {
- // Validate the fonts set through the mark-up string.
- Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
-
- // Get the default font's description.
- TextAbstraction::FontDescription defaultFontDescription;
- TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.GetFontSizeScale();
-
- //Get the number of points per one unit of point-size
- uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
-
- if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
- {
- // If the placeholder font is set specifically, only placeholder font is changed.
- defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
- if(impl.mEventData->mPlaceholderFont->sizeDefined)
- {
- defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
- }
- }
- else if(nullptr != impl.mFontDefaults)
- {
- // Set the normal font and the placeholder font.
- defaultFontDescription = impl.mFontDefaults->mFontDescription;
-
- if(impl.mTextFitEnabled)
- {
- defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
- }
- else
- {
- defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.GetFontSizeScale() * numberOfPointsPerOneUnitOfPointSize;
- }
- }
-
- // Validates the fonts. If there is a character with no assigned font it sets a default one.
- // After this call, fonts are validated.
- multilanguageSupport.ValidateFonts(utf32Characters,
- scripts,
- fontDescriptionRuns,
- defaultFontDescription,
- defaultPointSize,
- startIndex,
- requestedNumberOfCharacters,
- validFonts);
- }
- updated = true;
- }
-
- Vector<Character> mirroredUtf32Characters;
- bool textMirrored = false;
- const Length numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
- if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
- {
- Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
- bidirectionalInfo.Reserve(numberOfParagraphs);
-
- // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
- SetBidirectionalInfo(utf32Characters,
- scripts,
- lineBreakInfo,
- startIndex,
- requestedNumberOfCharacters,
- bidirectionalInfo,
- (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
- impl.mLayoutDirection);
-
- if(0u != bidirectionalInfo.Count())
- {
- // Only set the character directions if there is right to left characters.
- Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
- GetCharactersDirection(bidirectionalInfo,
- numberOfCharacters,
- startIndex,
- requestedNumberOfCharacters,
- directions);
-
- // This paragraph has right to left text. Some characters may need to be mirrored.
- // TODO: consider if the mirrored string can be stored as well.
-
- textMirrored = GetMirroredText(utf32Characters,
- directions,
- bidirectionalInfo,
- startIndex,
- requestedNumberOfCharacters,
- mirroredUtf32Characters);
- }
- else
- {
- // There is no right to left characters. Clear the directions vector.
- impl.mModel->mLogicalModel->mCharacterDirections.Clear();
- }
- updated = true;
- }
-
- Vector<GlyphInfo>& glyphs = impl.mModel->mVisualModel->mGlyphs;
- Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
- Vector<Length>& charactersPerGlyph = impl.mModel->mVisualModel->mCharactersPerGlyph;
- Vector<GlyphIndex> newParagraphGlyphs;
- newParagraphGlyphs.Reserve(numberOfParagraphs);
-
- const Length currentNumberOfGlyphs = glyphs.Count();
- if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
- {
- const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
- // Shapes the text.
- ShapeText(textToShape,
- lineBreakInfo,
- scripts,
- validFonts,
- startIndex,
- impl.mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- glyphs,
- glyphsToCharactersMap,
- charactersPerGlyph,
- newParagraphGlyphs);
-
- // Create the 'number of glyphs' per character and the glyph to character conversion tables.
- impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
- impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
-
- updated = true;
- }
-
- const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
-
- if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
- {
- GlyphInfo* glyphsBuffer = glyphs.Begin();
- impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
-
- // Update the width and advance of all new paragraph characters.
- for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
- {
- const GlyphIndex index = *it;
- GlyphInfo& glyph = *(glyphsBuffer + index);
-
- glyph.xBearing = 0.f;
- glyph.width = 0.f;
- glyph.advance = 0.f;
- }
- updated = true;
- }
-
- if((nullptr != impl.mEventData) &&
- impl.mEventData->mPreEditFlag &&
- (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
- {
- Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
- impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
- Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
-
- // Check the type of preedit and run it.
- for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
- {
- Dali::InputMethodContext::PreeditAttributeData attrData = *it;
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
- type = attrData.preeditType;
-
- // Check the number of commit characters for the start position.
- unsigned int numberOfCommit = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
- Length numberOfIndices = attrData.endIndex - attrData.startIndex;
-
- switch(type)
- {
- case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
- {
- // Add the underline for the pre-edit text.
- UnderlinedGlyphRun underlineRun;
- underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
- impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::REVERSE:
- {
- Vector4 textColor = impl.mModel->mVisualModel->GetTextColor();
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = textColor;
- impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
- if(backgroundColor.a == 0) // There is no text background color.
- {
- // Try use the control's background color.
- if(nullptr != impl.mEditableControlInterface)
- {
- impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
- if(backgroundColor.a == 0) // There is no control background color.
- {
- // Determines black or white color according to text color.
- // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
- float L = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
- backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
- }
- }
- }
-
- Vector<ColorRun> colorRuns;
- colorRuns.Resize(1u);
- ColorRun& colorRun = *(colorRuns.Begin());
- colorRun.color = backgroundColor;
- colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- colorRun.characterRun.numberOfCharacters = numberOfIndices;
- impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
- {
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = LIGHT_BLUE;
- impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
- {
- // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB4;
- impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- UnderlinedGlyphRun underlineRun;
- underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
- impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
- {
- // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB5;
- impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- UnderlinedGlyphRun underlineRun;
- underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
- impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
- {
- // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB6;
- impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- UnderlinedGlyphRun underlineRun;
- underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
- impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
- {
- // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
- ColorRun backgroundColorRun;
- backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
- backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
- backgroundColorRun.color = BACKGROUND_SUB7;
- impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
- UnderlinedGlyphRun underlineRun;
- underlineRun.glyphRun.glyphIndex = attrData.startIndex + numberOfCommit;
- underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
- impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(false);
- }
- break;
- }
- case Dali::InputMethodContext::PreeditStyle::NONE:
- default:
- {
- break;
- }
- }
- }
- attrs.Clear();
- updated = true;
- }
-
- if(Controller::NO_OPERATION != (Controller::COLOR & operations))
- {
- // Set the color runs in glyphs.
- SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
- impl.mModel->mVisualModel->mCharactersToGlyph,
- impl.mModel->mVisualModel->mGlyphsPerCharacter,
- startIndex,
- impl.mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- impl.mModel->mVisualModel->mColors,
- impl.mModel->mVisualModel->mColorIndices);
-
- // Set the background color runs in glyphs.
- SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
- impl.mModel->mVisualModel->mCharactersToGlyph,
- impl.mModel->mVisualModel->mGlyphsPerCharacter,
- startIndex,
- impl.mTextUpdateInfo.mStartGlyphIndex,
- requestedNumberOfCharacters,
- impl.mModel->mVisualModel->mBackgroundColors,
- impl.mModel->mVisualModel->mBackgroundColorIndices);
-
- updated = true;
- }
-
- if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
- !((nullptr != impl.mEventData) &&
- impl.mEventData->mPreEditFlag &&
- (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
- {
- //Mark-up processor case
- if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
- {
- impl.CopyUnderlinedFromLogicalToVisualModels(true);
- impl.CopyStrikethroughFromLogicalToVisualModels();
- impl.CopyCharacterSpacingFromLogicalToVisualModels();
- }
-
- updated = true;
- }
-
- // The estimated number of lines. Used to avoid reallocations when layouting.
- impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
-
- // Set the previous number of characters for the next time the text is updated.
- impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
-
- return updated;
-}
-
-} // namespace Dali::Toolkit::Text
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-
-namespace Dali::Toolkit::Text
-{
-
-/**
- * Contains methods for updating the models in the TextController
- */
-struct ControllerImplModelUpdater
-{
- using OperationsMask = Controller::OperationsMask;
-
- /**
- * @brief Updates the logical and visual models. Updates the style runs in the visual model when the text's styles changes.
- *
- * @param[in] impl A reference to the Controller::Impl class
- * @param[in] operationsRequired The operations required
- * @return true if mode has been modified.
- */
- static bool Update(Controller::Impl& impl, OperationsMask operationsRequired);
-};
-
-} // namespace Dali::Toolkit::Text
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/window-devel.h>
-#include <dali/integration-api/debug.h>
-#include <dali/public-api/actors/layer.h>
-#include <dali/public-api/rendering/renderer.h>
-#include <cmath>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
-#include <dali-toolkit/internal/text/text-control-interface.h>
-#include <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
-#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
-#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
-#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
-#include <dali-toolkit/internal/text/text-controller-relayouter.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-#include <dali-toolkit/internal/text/text-enumerations-impl.h>
-#include <dali-toolkit/internal/text/text-run-container.h>
-#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
-#include <dali-toolkit/internal/text/underlined-glyph-run.h>
-
-using namespace Dali;
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
-
-const std::string EMPTY_STRING("");
-
-} // namespace
-
-namespace Dali::Toolkit::Text
-{
-namespace
-{
-void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const fontDefaults, const Vector4& textColor)
-{
- // Sets the default text's color.
- inputStyle.textColor = textColor;
- inputStyle.isDefaultColor = true;
-
- inputStyle.familyName.clear();
- inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
- inputStyle.width = TextAbstraction::FontWidth::NORMAL;
- inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
- inputStyle.size = 0.f;
-
- inputStyle.lineSpacing = 0.f;
-
- inputStyle.underlineProperties.clear();
- inputStyle.shadowProperties.clear();
- inputStyle.embossProperties.clear();
- inputStyle.outlineProperties.clear();
-
- inputStyle.isFamilyDefined = false;
- inputStyle.isWeightDefined = false;
- inputStyle.isWidthDefined = false;
- inputStyle.isSlantDefined = false;
- inputStyle.isSizeDefined = false;
-
- inputStyle.isLineSpacingDefined = false;
-
- inputStyle.isUnderlineDefined = false;
- inputStyle.isShadowDefined = false;
- inputStyle.isEmbossDefined = false;
- inputStyle.isOutlineDefined = false;
-
- // Sets the default font's family name, weight, width, slant and size.
- if(fontDefaults)
- {
- if(fontDefaults->familyDefined)
- {
- inputStyle.familyName = fontDefaults->mFontDescription.family;
- inputStyle.isFamilyDefined = true;
- }
-
- if(fontDefaults->weightDefined)
- {
- inputStyle.weight = fontDefaults->mFontDescription.weight;
- inputStyle.isWeightDefined = true;
- }
-
- if(fontDefaults->widthDefined)
- {
- inputStyle.width = fontDefaults->mFontDescription.width;
- inputStyle.isWidthDefined = true;
- }
-
- if(fontDefaults->slantDefined)
- {
- inputStyle.slant = fontDefaults->mFontDescription.slant;
- inputStyle.isSlantDefined = true;
- }
-
- if(fontDefaults->sizeDefined)
- {
- inputStyle.size = fontDefaults->mDefaultPointSize;
- inputStyle.isSizeDefined = true;
- }
- }
-}
-
-void ChangeTextControllerState(Controller::Impl& impl, EventData::State newState)
-{
- EventData* eventData = impl.mEventData;
-
- if(nullptr == eventData)
- {
- // Nothing to do if there is no text input.
- return;
- }
-
- DecoratorPtr& decorator = eventData->mDecorator;
- if(!decorator)
- {
- // Nothing to do if there is no decorator.
- return;
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d newstate:%d\n", eventData->mState, newState);
-
- if(eventData->mState != newState)
- {
- eventData->mPreviousState = eventData->mState;
- eventData->mState = newState;
-
- switch(eventData->mState)
- {
- case EventData::INACTIVE:
- {
- decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
- decorator->StopCursorBlink();
- decorator->SetHandleActive(GRAB_HANDLE, false);
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
- decorator->SetPopupActive(false);
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::INTERRUPTED:
- {
- decorator->SetHandleActive(GRAB_HANDLE, false);
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
- decorator->SetPopupActive(false);
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::SELECTING:
- {
- decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
- decorator->StopCursorBlink();
- decorator->SetHandleActive(GRAB_HANDLE, false);
- if(eventData->mGrabHandleEnabled)
- {
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
- }
- decorator->SetHighlightActive(true);
- if(eventData->mGrabHandlePopupEnabled)
- {
- impl.SetPopupButtons();
- decorator->SetPopupActive(true);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::EDITING:
- {
- decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
- if(eventData->mCursorBlinkEnabled)
- {
- decorator->StartCursorBlink();
- }
- // Grab handle is not shown until a tap is received whilst EDITING
- decorator->SetHandleActive(GRAB_HANDLE, false);
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
- if(eventData->mGrabHandlePopupEnabled)
- {
- decorator->SetPopupActive(false);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
- case EventData::EDITING_WITH_POPUP:
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
-
- decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
- if(eventData->mCursorBlinkEnabled)
- {
- decorator->StartCursorBlink();
- }
- if(eventData->mSelectionEnabled)
- {
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
- }
- else if(eventData->mGrabHandleEnabled)
- {
- decorator->SetHandleActive(GRAB_HANDLE, true);
- }
- if(eventData->mGrabHandlePopupEnabled)
- {
- impl.SetPopupButtons();
- decorator->SetPopupActive(true);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
- case EventData::EDITING_WITH_GRAB_HANDLE:
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
-
- decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
- if(eventData->mCursorBlinkEnabled)
- {
- decorator->StartCursorBlink();
- }
- // Grab handle is not shown until a tap is received whilst EDITING
- if(eventData->mGrabHandleEnabled)
- {
- decorator->SetHandleActive(GRAB_HANDLE, true);
- }
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
- if(eventData->mGrabHandlePopupEnabled)
- {
- decorator->SetPopupActive(false);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::SELECTION_HANDLE_PANNING:
- {
- decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
- decorator->StopCursorBlink();
- decorator->SetHandleActive(GRAB_HANDLE, false);
- if(eventData->mGrabHandleEnabled)
- {
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
- }
- decorator->SetHighlightActive(true);
- if(eventData->mGrabHandlePopupEnabled)
- {
- decorator->SetPopupActive(false);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::GRAB_HANDLE_PANNING:
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
-
- decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
- if(eventData->mCursorBlinkEnabled)
- {
- decorator->StartCursorBlink();
- }
- if(eventData->mGrabHandleEnabled)
- {
- decorator->SetHandleActive(GRAB_HANDLE, true);
- }
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
- if(eventData->mGrabHandlePopupEnabled)
- {
- decorator->SetPopupActive(false);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::EDITING_WITH_PASTE_POPUP:
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
-
- decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
- if(eventData->mCursorBlinkEnabled)
- {
- decorator->StartCursorBlink();
- }
-
- if(eventData->mGrabHandleEnabled)
- {
- decorator->SetHandleActive(GRAB_HANDLE, true);
- }
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(false);
-
- if(eventData->mGrabHandlePopupEnabled)
- {
- impl.SetPopupButtons();
- decorator->SetPopupActive(true);
- }
- eventData->mDecoratorUpdated = true;
- break;
- }
-
- case EventData::TEXT_PANNING:
- {
- decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
- decorator->StopCursorBlink();
- decorator->SetHandleActive(GRAB_HANDLE, false);
- if(eventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
- decorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
- {
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
- decorator->SetHighlightActive(true);
- }
-
- if(eventData->mGrabHandlePopupEnabled)
- {
- decorator->SetPopupActive(false);
- }
-
- eventData->mDecoratorUpdated = true;
- break;
- }
- }
- }
-}
-
-void UpdateCursorPositionForAlignment(Controller::Impl& impl, bool needFullAlignment)
-{
- EventData* eventData = impl.mEventData;
-
- // Set the flag to redo the alignment operation
- impl.mOperationsPending = static_cast<Controller::OperationsMask>(impl.mOperationsPending | Controller::OperationsMask::ALIGN);
-
- if(eventData)
- {
- // Note: mUpdateAlignment is currently only needed for horizontal alignment
- eventData->mUpdateAlignment = needFullAlignment;
-
- // Update the cursor if it's in editing mode
- if(EventData::IsEditingState(eventData->mState))
- {
- impl.ChangeState(EventData::EDITING);
- eventData->mUpdateCursorPosition = true;
- }
- }
-}
-
-} // unnamed Namespace
-
-EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
-: mDecorator(decorator),
- mInputMethodContext(inputMethodContext),
- mPlaceholderFont(nullptr),
- mPlaceholderTextActive(),
- mPlaceholderTextInactive(),
- mPlaceholderTextColor(0.8f, 0.8f, 0.8f, 0.8f), // This color has been published in the Public API (placeholder-properties.h).
- mEventQueue(),
- mInputStyleChangedQueue(),
- mPreviousState(INACTIVE),
- mState(INACTIVE),
- mPrimaryCursorPosition(0u),
- mLeftSelectionPosition(0u),
- mRightSelectionPosition(0u),
- mPreEditStartPosition(0u),
- mPreEditLength(0u),
- mCursorHookPositionX(0.f),
- mDoubleTapAction(Controller::NoTextTap::NO_ACTION),
- mLongPressAction(Controller::NoTextTap::SHOW_SELECTION_POPUP),
- mIsShowingPlaceholderText(false),
- mPreEditFlag(false),
- mDecoratorUpdated(false),
- mCursorBlinkEnabled(true),
- mGrabHandleEnabled(true),
- mGrabHandlePopupEnabled(true),
- mSelectionEnabled(true),
- mUpdateCursorHookPosition(false),
- mUpdateCursorPosition(false),
- mUpdateGrabHandlePosition(false),
- mUpdateLeftSelectionPosition(false),
- mUpdateRightSelectionPosition(false),
- mIsLeftHandleSelected(false),
- mIsRightHandleSelected(false),
- mUpdateHighlightBox(false),
- mScrollAfterUpdatePosition(false),
- mScrollAfterDelete(false),
- mAllTextSelected(false),
- mUpdateInputStyle(false),
- mPasswordInput(false),
- mCheckScrollAmount(false),
- mIsPlaceholderPixelSize(false),
- mIsPlaceholderElideEnabled(false),
- mPlaceholderEllipsisFlag(false),
- mShiftSelectionFlag(true),
- mUpdateAlignment(false),
- mEditingEnabled(true)
-{
-}
-
-bool Controller::Impl::ProcessInputEvents()
-{
- return ControllerImplEventHandler::ProcessInputEvents(*this);
-}
-
-void Controller::Impl::NotifyInputMethodContext()
-{
- if(mEventData && mEventData->mInputMethodContext)
- {
- CharacterIndex cursorPosition = GetLogicalCursorPosition();
-
- const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces(0u);
-
- // Update the cursor position by removing the initial white spaces.
- if(cursorPosition < numberOfWhiteSpaces)
- {
- cursorPosition = 0u;
- }
- else
- {
- cursorPosition -= numberOfWhiteSpaces;
- }
-
- mEventData->mInputMethodContext.SetCursorPosition(cursorPosition);
- mEventData->mInputMethodContext.NotifyCursorPosition();
- }
-}
-
-void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
-{
- if(mEventData && mEventData->mInputMethodContext)
- {
- Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
- mEventData->mInputMethodContext.NotifyTextInputMultiLine(layout == Text::Layout::Engine::MULTI_LINE_BOX);
- }
-}
-
-CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
-{
- CharacterIndex cursorPosition = 0u;
-
- if(mEventData)
- {
- if((EventData::SELECTING == mEventData->mState) ||
- (EventData::SELECTION_HANDLE_PANNING == mEventData->mState))
- {
- cursorPosition = std::min(mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition);
- }
- else
- {
- cursorPosition = mEventData->mPrimaryCursorPosition;
- }
- }
-
- return cursorPosition;
-}
-
-Length Controller::Impl::GetNumberOfWhiteSpaces(CharacterIndex index) const
-{
- Length numberOfWhiteSpaces = 0u;
-
- // Get the buffer to the text.
- Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
-
- const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
- for(; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces)
- {
- if(!TextAbstraction::IsWhiteSpace(*(utf32CharacterBuffer + index)))
- {
- break;
- }
- }
-
- return numberOfWhiteSpaces;
-}
-
-void Controller::Impl::GetText(std::string& text) const
-{
- if(!IsShowingPlaceholderText())
- {
- // Retrieves the text string.
- GetText(0u, text);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this);
- }
-}
-
-void Controller::Impl::GetText(CharacterIndex index, std::string& text) const
-{
- // Get the total number of characters.
- Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
-
- // Retrieve the text.
- if(0u != numberOfCharacters)
- {
- Utf32ToUtf8(mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text);
- }
-}
-
-Dali::LayoutDirection::Type Controller::Impl::GetLayoutDirection(Dali::Actor& actor) const
-{
- if(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
- (mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mIsLayoutDirectionChanged))
- {
- Window window = DevelWindow::Get(actor);
- return static_cast<Dali::LayoutDirection::Type>(window ? window.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>() : LayoutDirection::LEFT_TO_RIGHT);
- }
- else
- {
- return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
- }
-}
-
-Toolkit::DevelText::TextDirection::Type Controller::Impl::GetTextDirection()
-{
- if(mUpdateTextDirection)
- {
- // Operations that can be done only once until the text changes.
- const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
- GET_SCRIPTS |
- VALIDATE_FONTS |
- GET_LINE_BREAKS |
- BIDI_INFO |
- SHAPE_TEXT |
- GET_GLYPH_METRICS);
-
- // Set the update info to relayout the whole text.
- mTextUpdateInfo.mParagraphCharacterIndex = 0u;
- mTextUpdateInfo.mRequestedNumberOfCharacters = mModel->mLogicalModel->mText.Count();
-
- // Make sure the model is up-to-date before layouting
- UpdateModel(onlyOnceOperations);
-
- Vector3 naturalSize;
- Relayouter::DoRelayout(*this,
- Size(MAX_FLOAT, MAX_FLOAT),
- static_cast<OperationsMask>(onlyOnceOperations |
- LAYOUT | REORDER | UPDATE_DIRECTION),
- naturalSize.GetVectorXY());
-
- // Do not do again the only once operations.
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending & ~onlyOnceOperations);
-
- // Clear the update info. This info will be set the next time the text is updated.
- mTextUpdateInfo.Clear();
-
- // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
- mTextUpdateInfo.mFullRelayoutNeeded = true;
-
- mUpdateTextDirection = false;
- }
-
- return mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
-}
-
-void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
-{
- mTextUpdateInfo.mParagraphCharacterIndex = 0u;
- mTextUpdateInfo.mStartGlyphIndex = 0u;
- mTextUpdateInfo.mStartLineIndex = 0u;
- numberOfCharacters = 0u;
-
- const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
- if(0u == numberOfParagraphs)
- {
- mTextUpdateInfo.mParagraphCharacterIndex = 0u;
- numberOfCharacters = 0u;
-
- mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
-
- // Nothing else to do if there are no paragraphs.
- return;
- }
-
- // Find the paragraphs to be updated.
- Vector<ParagraphRunIndex> paragraphsToBeUpdated;
- if(mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters)
- {
- // Text is being added at the end of the current text.
- if(mTextUpdateInfo.mIsLastCharacterNewParagraph)
- {
- // Text is being added in a new paragraph after the last character of the text.
- mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
- numberOfCharacters = 0u;
- mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
-
- mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
- mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
-
- // Nothing else to do;
- return;
- }
-
- paragraphsToBeUpdated.PushBack(numberOfParagraphs - 1u);
- }
- else
- {
- Length numberOfCharactersToUpdate = 0u;
- if(mTextUpdateInfo.mFullRelayoutNeeded)
- {
- numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
- }
- else
- {
- numberOfCharactersToUpdate = (mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
- }
- mModel->mLogicalModel->FindParagraphs(mTextUpdateInfo.mCharacterIndex,
- numberOfCharactersToUpdate,
- paragraphsToBeUpdated);
- }
-
- if(0u != paragraphsToBeUpdated.Count())
- {
- const ParagraphRunIndex firstParagraphIndex = *(paragraphsToBeUpdated.Begin());
- const ParagraphRun& firstParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex);
- mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
-
- ParagraphRunIndex lastParagraphIndex = *(paragraphsToBeUpdated.End() - 1u);
- const ParagraphRun& lastParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex);
-
- if((mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) && // Some character are removed.
- (lastParagraphIndex < numberOfParagraphs - 1u) && // There is a next paragraph.
- ((lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters) == // The last removed character is the new paragraph character.
- (mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove)))
- {
- // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
- const ParagraphRun& lastParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u);
-
- numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
- }
- else
- {
- numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
- }
- }
-
- mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
- mTextUpdateInfo.mStartGlyphIndex = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex);
-}
-
-void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
-{
- ControllerImplDataClearer::ClearModelData(*this, startIndex, endIndex, operations);
-}
-
-bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
-{
- return ControllerImplModelUpdater::Update(*this, operationsRequired);
-}
-
-void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
-{
- SetDefaultInputStyle(inputStyle, mFontDefaults, mTextColor);
-}
-
-float Controller::Impl::GetDefaultFontLineHeight()
-{
- FontId defaultFontId = 0u;
- if(nullptr == mFontDefaults)
- {
- TextAbstraction::FontDescription fontDescription;
- defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * GetFontSizeScale());
- }
- else
- {
- defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * GetFontSizeScale());
- }
-
- Text::FontMetrics fontMetrics;
- mMetrics->GetFontMetrics(defaultFontId, fontMetrics);
-
- return (fontMetrics.ascender - fontMetrics.descender);
-}
-
-bool Controller::Impl::SetDefaultLineSpacing(float lineSpacing)
-{
- if(std::fabs(lineSpacing - mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
- {
- mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
-
- RelayoutAllCharacters();
- return true;
- }
- return false;
-}
-
-bool Controller::Impl::SetDefaultLineSize(float lineSize)
-{
- if(std::fabs(lineSize - mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
- {
- mLayoutEngine.SetDefaultLineSize(lineSize);
-
- RelayoutAllCharacters();
- return true;
- }
- return false;
-}
-
-bool Controller::Impl::SetRelativeLineSize(float relativeLineSize)
-{
- if(std::fabs(relativeLineSize - GetRelativeLineSize()) > Math::MACHINE_EPSILON_1000)
- {
- mLayoutEngine.SetRelativeLineSize(relativeLineSize);
-
- RelayoutAllCharacters();
- return true;
- }
- return false;
-}
-
-float Controller::Impl::GetRelativeLineSize()
-{
- return mLayoutEngine.GetRelativeLineSize();
-}
-
-string Controller::Impl::GetSelectedText()
-{
- string text;
- if(EventData::SELECTING == mEventData->mState)
- {
- RetrieveSelection(text, false);
- }
- return text;
-}
-
-string Controller::Impl::CopyText()
-{
- string text;
- RetrieveSelection(text, false);
- SendSelectionToClipboard(false); // Text not modified
-
- mEventData->mUpdateCursorPosition = true;
-
- RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
-
- return text;
-}
-
-string Controller::Impl::CutText()
-{
- string text;
- RetrieveSelection(text, false);
-
- if(!IsEditable())
- {
- return EMPTY_STRING;
- }
-
- SendSelectionToClipboard(true); // Synchronous call to modify text
- mOperationsPending = ALL_OPERATIONS;
-
- if((0u != mModel->mLogicalModel->mText.Count()) ||
- !IsPlaceholderAvailable())
- {
- QueueModifyEvent(ModifyEvent::TEXT_DELETED);
- }
- else
- {
- PlaceholderHandler::ShowPlaceholderText(*this);
- }
-
- mEventData->mUpdateCursorPosition = true;
- mEventData->mScrollAfterDelete = true;
-
- RequestRelayout();
-
- if(nullptr != mEditableControlInterface)
- {
- mEditableControlInterface->TextChanged(true);
- }
- return text;
-}
-
-void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
-{
- if(nullptr == mEventData)
- {
- // Nothing to do if there is no text.
- return;
- }
-
- if(mEventData->mSelectionEnabled && (pStart || pEnd))
- {
- uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
- uint32_t oldStart = mEventData->mLeftSelectionPosition;
- uint32_t oldEnd = mEventData->mRightSelectionPosition;
-
- if(pStart)
- {
- mEventData->mLeftSelectionPosition = std::min(*pStart, length);
- }
- if(pEnd)
- {
- mEventData->mRightSelectionPosition = std::min(*pEnd, length);
- }
-
- if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
- {
- ChangeState(EventData::EDITING);
- mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
- mEventData->mUpdateCursorPosition = true;
- }
- else
- {
- ChangeState(EventData::SELECTING);
- mEventData->mUpdateHighlightBox = true;
- mEventData->mUpdateLeftSelectionPosition = true;
- mEventData->mUpdateRightSelectionPosition = true;
- }
-
- if(mSelectableControlInterface != nullptr)
- {
- mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
- }
- }
-}
-
-CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
-{
- if(nullptr == mEventData)
- {
- return 0;
- }
- return mEventData->mPrimaryCursorPosition;
-}
-
-bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
-{
- if(nullptr == mEventData)
- {
- // Nothing to do if there is no text.
- return false;
- }
-
- if(mEventData->mPrimaryCursorPosition == index && mEventData->mState != EventData::SELECTING)
- {
- // Nothing for same cursor position.
- return false;
- }
-
- uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
- uint32_t oldCursorPos = mEventData->mPrimaryCursorPosition;
- mEventData->mPrimaryCursorPosition = std::min(index, length);
- // If there is no focus, only the value is updated.
- if(focused)
- {
- bool wasInSelectingState = mEventData->mState == EventData::SELECTING;
- uint32_t oldStart = mEventData->mLeftSelectionPosition;
- uint32_t oldEnd = mEventData->mRightSelectionPosition;
- ChangeState(EventData::EDITING);
- mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
- mEventData->mUpdateCursorPosition = true;
-
- if(mSelectableControlInterface != nullptr && wasInSelectingState)
- {
- mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
- }
-
- ScrollTextToMatchCursor();
- }
-
- if(nullptr != mEditableControlInterface)
- {
- mEditableControlInterface->CursorPositionChanged(oldCursorPos, mEventData->mPrimaryCursorPosition);
- }
-
- return true;
-}
-
-Uint32Pair Controller::Impl::GetTextSelectionRange() const
-{
- Uint32Pair range;
-
- if(mEventData)
- {
- range.first = mEventData->mLeftSelectionPosition;
- range.second = mEventData->mRightSelectionPosition;
- }
-
- return range;
-}
-
-bool Controller::Impl::IsEditable() const
-{
- return mEventData && mEventData->mEditingEnabled;
-}
-
-void Controller::Impl::SetEditable(bool editable)
-{
- if(mEventData)
- {
- mEventData->mEditingEnabled = editable;
-
- if(mEventData->mDecorator)
- {
- bool decoratorEditable = editable && mIsUserInteractionEnabled;
- mEventData->mDecorator->SetEditable(decoratorEditable);
- }
- }
-}
-
-void Controller::Impl::UpdateAfterFontChange(const std::string& newDefaultFont)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
-
- if(!mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
- {
- DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
- mFontDefaults->mFontDescription.family = newDefaultFont;
-
- ClearFontData();
-
- RequestRelayout();
- }
-}
-
-void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
-{
- if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
- {
- // Nothing to select if handles are in the same place.
- selectedText.clear();
- return;
- }
-
- const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
-
- //Get start and end position of selection
- const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
- const Length lengthOfSelectedText = (handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition) - startOfSelectedText;
-
- Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
- const Length numberOfCharacters = utf32Characters.Count();
-
- // Validate the start and end selection points
- if((startOfSelectedText + lengthOfSelectedText) <= numberOfCharacters)
- {
- //Get text as a UTF8 string
- Utf32ToUtf8(&utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText);
-
- if(deleteAfterRetrieval) // Only delete text if copied successfully
- {
- // Keep a copy of the current input style.
- InputStyle currentInputStyle;
- currentInputStyle.Copy(mEventData->mInputStyle);
-
- // Set as input style the style of the first deleted character.
- mModel->mLogicalModel->RetrieveStyle(startOfSelectedText, mEventData->mInputStyle);
-
- // Compare if the input style has changed.
- const bool hasInputStyleChanged = !currentInputStyle.Equal(mEventData->mInputStyle);
-
- if(hasInputStyleChanged)
- {
- const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mEventData->mInputStyle);
- // Queue the input style changed signal.
- mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
- }
-
- mModel->mLogicalModel->UpdateTextStyleRuns(startOfSelectedText, -static_cast<int>(lengthOfSelectedText));
-
- // Mark the paragraphs to be updated.
- if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
- {
- mTextUpdateInfo.mCharacterIndex = 0;
- mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
- mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
- mTextUpdateInfo.mClearAll = true;
- }
- else
- {
- mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- }
-
- // Delete text between handles
- Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
- Vector<Character>::Iterator last = first + lengthOfSelectedText;
- utf32Characters.Erase(first, last);
-
- // Will show the cursor at the first character of the selection.
- mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
- }
- else
- {
- // Will show the cursor at the last character of the selection.
- mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
- }
-
- mEventData->mDecoratorUpdated = true;
- }
-}
-
-void Controller::Impl::SetSelection(int start, int end)
-{
- uint32_t oldStart = mEventData->mLeftSelectionPosition;
- uint32_t oldEnd = mEventData->mRightSelectionPosition;
-
- mEventData->mLeftSelectionPosition = start;
- mEventData->mRightSelectionPosition = end;
- mEventData->mUpdateCursorPosition = true;
-
- if(mSelectableControlInterface != nullptr)
- {
- mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
- }
-}
-
-std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
-{
- return {mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition};
-}
-
-void Controller::Impl::ShowClipboard()
-{
- if(mClipboard)
- {
- mClipboard.ShowClipboard();
- }
-}
-
-void Controller::Impl::HideClipboard()
-{
- if(mClipboard && mClipboardHideEnabled)
- {
- mClipboard.HideClipboard();
- }
-}
-
-void Controller::Impl::SetClipboardHideEnable(bool enable)
-{
- mClipboardHideEnabled = enable;
-}
-
-bool Controller::Impl::CopyStringToClipboard(const std::string& source)
-{
- //Send string to clipboard
- return (mClipboard && mClipboard.SetItem(source));
-}
-
-void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
-{
- std::string selectedText;
- RetrieveSelection(selectedText, deleteAfterSending);
- CopyStringToClipboard(selectedText);
- ChangeState(EventData::EDITING);
-}
-
-void Controller::Impl::RequestGetTextFromClipboard()
-{
- if(mClipboard)
- {
- mClipboard.RequestItem();
- }
-}
-
-void Controller::Impl::RepositionSelectionHandles()
-{
- SelectionHandleController::Reposition(*this);
-}
-void Controller::Impl::RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action)
-{
- SelectionHandleController::Reposition(*this, visualX, visualY, action);
-}
-
-void Controller::Impl::SetPopupButtons()
-{
- /**
- * Sets the Popup buttons to be shown depending on State.
- *
- * If SELECTING : CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
- *
- * If EDITING_WITH_POPUP : SELECT & SELECT_ALL
- */
-
- bool isEditable = IsEditable();
- TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
-
- if(EventData::SELECTING == mEventData->mState)
- {
- buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::COPY);
- if(isEditable)
- {
- buttonsToShow = TextSelectionPopup::Buttons(buttonsToShow | TextSelectionPopup::CUT);
- }
-
- if(!IsClipboardEmpty())
- {
- if(isEditable)
- {
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
- }
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
- }
-
- if(!mEventData->mAllTextSelected)
- {
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::SELECT_ALL));
- }
- }
- else if(EventData::EDITING_WITH_POPUP == mEventData->mState)
- {
- if(mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
- {
- buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL);
- }
-
- if(!IsClipboardEmpty())
- {
- if(isEditable)
- {
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
- }
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
- }
- }
- else if(EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState)
- {
- if(!IsClipboardEmpty())
- {
- if(isEditable)
- {
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
- }
- buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
- }
- }
-
- mEventData->mDecorator->SetEnabledPopupButtons(buttonsToShow);
-}
-
-void Controller::Impl::ChangeState(EventData::State newState)
-{
- ChangeTextControllerState(*this, newState);
-}
-
-void Controller::Impl::GetCursorPosition(CharacterIndex logical,
- CursorInfo& cursorInfo)
-{
- if(!IsShowingRealText())
- {
- // Do not want to use the place-holder text to set the cursor position.
-
- // Use the line's height of the font's family set to set the cursor's size.
- // If there is no font's family set, use the default font.
- // Use the current alignment to place the cursor at the beginning, center or end of the box.
-
- cursorInfo.lineOffset = 0.f;
- cursorInfo.lineHeight = GetDefaultFontLineHeight();
- cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
-
- bool isRTL = false;
- if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
- {
- isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
- }
-
- switch(mModel->mHorizontalAlignment)
- {
- case Text::HorizontalAlignment::BEGIN:
- {
- if(isRTL)
- {
- cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
- }
- else
- {
- cursorInfo.primaryPosition.x = 0.f;
- }
- break;
- }
- case Text::HorizontalAlignment::CENTER:
- {
- cursorInfo.primaryPosition.x = floorf(0.5f * mModel->mVisualModel->mControlSize.width);
- break;
- }
- case Text::HorizontalAlignment::END:
- {
- if(isRTL)
- {
- cursorInfo.primaryPosition.x = 0.f;
- }
- else
- {
- cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
- }
- break;
- }
- }
-
- // Nothing else to do.
- return;
- }
-
- const bool isMultiLine = (Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout());
- GetCursorPositionParameters parameters;
- parameters.visualModel = mModel->mVisualModel;
- parameters.logicalModel = mModel->mLogicalModel;
- parameters.metrics = mMetrics;
- parameters.logical = logical;
- parameters.isMultiline = isMultiLine;
-
- float defaultFontLineHeight = GetDefaultFontLineHeight();
-
- Text::GetCursorPosition(parameters,
- defaultFontLineHeight,
- cursorInfo);
-
- // Adds Outline offset.
- const float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
- cursorInfo.primaryPosition.x += outlineWidth;
- cursorInfo.primaryPosition.y += outlineWidth;
- cursorInfo.secondaryPosition.x += outlineWidth;
- cursorInfo.secondaryPosition.y += outlineWidth;
-
- if(isMultiLine)
- {
- // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
-
- // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
- // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
-
- if(0.f > cursorInfo.primaryPosition.x)
- {
- cursorInfo.primaryPosition.x = 0.f;
- }
-
- const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>(mEventData->mDecorator->GetCursorWidth());
- if(cursorInfo.primaryPosition.x > edgeWidth)
- {
- cursorInfo.primaryPosition.x = edgeWidth;
- }
- }
-}
-
-CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
-{
- if(nullptr == mEventData)
- {
- // Nothing to do if there is no text input.
- return 0u;
- }
-
- CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
-
- const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
- const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
-
- GlyphIndex glyphIndex = *(charactersToGlyphBuffer + index);
- Length numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
-
- if(numberOfCharacters > 1u)
- {
- const Script script = mModel->mLogicalModel->GetScript(index);
- if(HasLigatureMustBreak(script))
- {
- // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
- numberOfCharacters = 1u;
- }
- }
- else
- {
- while(0u == numberOfCharacters)
- {
- ++glyphIndex;
- numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
- }
- }
-
- if(index < mEventData->mPrimaryCursorPosition)
- {
- cursorIndex -= numberOfCharacters;
- }
- else
- {
- cursorIndex += numberOfCharacters;
- }
-
- // Will update the cursor hook position.
- mEventData->mUpdateCursorHookPosition = true;
-
- return cursorIndex;
-}
-
-void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
- if(nullptr == mEventData)
- {
- // Nothing to do if there is no text input.
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
- return;
- }
-
- const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
-
- mEventData->mDecorator->SetGlyphOffset(PRIMARY_CURSOR, cursorInfo.glyphOffset);
-
- // Sets the cursor position.
- mEventData->mDecorator->SetPosition(PRIMARY_CURSOR,
- cursorPosition.x,
- cursorPosition.y,
- cursorInfo.primaryCursorHeight,
- cursorInfo.lineHeight);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y);
-
- if(mEventData->mUpdateGrabHandlePosition)
- {
- // Sets the grab handle position.
- mEventData->mDecorator->SetPosition(GRAB_HANDLE,
- cursorPosition.x,
- cursorInfo.lineOffset + mModel->mScrollPosition.y,
- cursorInfo.lineHeight);
- }
-
- if(cursorInfo.isSecondaryCursor)
- {
- mEventData->mDecorator->SetPosition(SECONDARY_CURSOR,
- cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
- cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
- cursorInfo.secondaryCursorHeight,
- cursorInfo.lineHeight);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y);
- }
-
- // Set which cursors are active according the state.
- if(EventData::IsEditingState(mEventData->mState) || (EventData::GRAB_HANDLE_PANNING == mEventData->mState))
- {
- if(cursorInfo.isSecondaryCursor)
- {
- mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_BOTH);
- }
- else
- {
- mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
- }
- }
- else
- {
- mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n");
-}
-
-void Controller::Impl::UpdateSelectionHandle(HandleType handleType,
- const CursorInfo& cursorInfo)
-{
- SelectionHandleController::Update(*this, handleType, cursorInfo);
-}
-
-void Controller::Impl::ClampHorizontalScroll(const Vector2& layoutSize)
-{
- // Clamp between -space & -alignment offset.
-
- if(layoutSize.width > mModel->mVisualModel->mControlSize.width)
- {
- const float space = (layoutSize.width - mModel->mVisualModel->mControlSize.width) + mModel->mAlignmentOffset;
- mModel->mScrollPosition.x = (mModel->mScrollPosition.x < -space) ? -space : mModel->mScrollPosition.x;
- mModel->mScrollPosition.x = (mModel->mScrollPosition.x > -mModel->mAlignmentOffset) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
-
- mEventData->mDecoratorUpdated = true;
- }
- else
- {
- mModel->mScrollPosition.x = 0.f;
- }
-}
-
-void Controller::Impl::ClampVerticalScroll(const Vector2& layoutSize)
-{
- if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
- {
- // Nothing to do if the text is single line.
- return;
- }
-
- // Clamp between -space & 0.
- if(layoutSize.height > mModel->mVisualModel->mControlSize.height)
- {
- const float space = (layoutSize.height - mModel->mVisualModel->mControlSize.height);
- mModel->mScrollPosition.y = (mModel->mScrollPosition.y < -space) ? -space : mModel->mScrollPosition.y;
- mModel->mScrollPosition.y = (mModel->mScrollPosition.y > 0.f) ? 0.f : mModel->mScrollPosition.y;
-
- mEventData->mDecoratorUpdated = true;
- }
- else
- {
- mModel->mScrollPosition.y = 0.f;
- }
-}
-
-void Controller::Impl::ScrollToMakePositionVisible(const Vector2& position, float lineHeight)
-{
- const float cursorWidth = mEventData->mDecorator ? static_cast<float>(mEventData->mDecorator->GetCursorWidth()) : 0.f;
-
- // position is in actor's coords.
- const float positionEndX = position.x + cursorWidth;
- const float positionEndY = position.y + lineHeight;
-
- // Transform the position to decorator coords.
- const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
- const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
-
- const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
- const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
-
- if(decoratorPositionBeginX < 0.f)
- {
- mModel->mScrollPosition.x = -position.x;
- }
- else if(decoratorPositionEndX > mModel->mVisualModel->mControlSize.width)
- {
- mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
- }
-
- if(Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout())
- {
- if(decoratorPositionBeginY < 0.f)
- {
- mModel->mScrollPosition.y = -position.y;
- }
- else if(decoratorPositionEndY > mModel->mVisualModel->mControlSize.height)
- {
- mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
- }
- else if(mModel->mLogicalModel->mText.Count() == 0u)
- {
- Relayouter::CalculateVerticalOffset(*this, mModel->mVisualModel->mControlSize);
- }
- }
-}
-
-void Controller::Impl::ScrollTextToMatchCursor(const CursorInfo& cursorInfo)
-{
- // Get the current cursor position in decorator coords.
- const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
-
- const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter(mEventData->mPrimaryCursorPosition);
-
- // Calculate the offset to match the cursor position before the character was deleted.
- mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
-
- //If text control has more than two lines and current line index is not last, calculate scrollpositionY
- if(mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() - 1u)
- {
- const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset(PRIMARY_CURSOR);
- mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
- }
-
- ClampHorizontalScroll(mModel->mVisualModel->GetLayoutSize());
- ClampVerticalScroll(mModel->mVisualModel->GetLayoutSize());
-
- // Makes the new cursor position visible if needed.
- ScrollToMakePositionVisible(cursorInfo.primaryPosition, cursorInfo.lineHeight);
-}
-
-void Controller::Impl::ScrollTextToMatchCursor()
-{
- CursorInfo cursorInfo;
- GetCursorPosition(mEventData->mPrimaryCursorPosition, cursorInfo);
- ScrollTextToMatchCursor(cursorInfo);
-}
-
-void Controller::Impl::RequestRelayout()
-{
- if(nullptr != mControlInterface)
- {
- mControlInterface->RequestTextRelayout();
- }
-}
-
-void Controller::Impl::RelayoutAllCharacters()
-{
- // relayout all characters
- mTextUpdateInfo.mCharacterIndex = 0;
- mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
- mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count();
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | LAYOUT);
-
- mTextUpdateInfo.mFullRelayoutNeeded = true;
-
- // Need to recalculate natural size
- mRecalculateNaturalSize = true;
-
- //remove selection
- if((mEventData != nullptr) && (mEventData->mState == EventData::SELECTING))
- {
- ChangeState(EventData::EDITING);
- }
-
- RequestRelayout();
-}
-
-bool Controller::Impl::IsInputStyleChangedSignalsQueueEmpty()
-{
- return (NULL == mEventData) || (0u == mEventData->mInputStyleChangedQueue.Count());
-}
-
-void Controller::Impl::ProcessInputStyleChangedSignals()
-{
- if(mEventData)
- {
- if(mEditableControlInterface)
- {
- // Emit the input style changed signal for each mask
- std::for_each(mEventData->mInputStyleChangedQueue.begin(),
- mEventData->mInputStyleChangedQueue.end(),
- [&](const auto mask) { mEditableControlInterface->InputStyleChanged(mask); });
- }
-
- mEventData->mInputStyleChangedQueue.Clear();
- }
-}
-
-void Controller::Impl::ScrollBy(Vector2 scroll)
-{
- if(mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
- {
- const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
- const Vector2 currentScroll = mModel->mScrollPosition;
-
- scroll.x = -scroll.x;
- scroll.y = -scroll.y;
-
- if(fabs(scroll.x) > Math::MACHINE_EPSILON_0)
- {
- mModel->mScrollPosition.x += scroll.x;
- ClampHorizontalScroll(layoutSize);
- }
-
- if(fabs(scroll.y) > Math::MACHINE_EPSILON_0)
- {
- mModel->mScrollPosition.y += scroll.y;
- ClampVerticalScroll(layoutSize);
- }
-
- if(mModel->mScrollPosition != currentScroll)
- {
- mEventData->mDecorator->UpdatePositions(mModel->mScrollPosition - currentScroll);
- RequestRelayout();
- }
- }
-}
-
-bool Controller::Impl::IsScrollable(const Vector2& displacement)
-{
- bool isScrollable = false;
- if(mEventData)
- {
- const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
- const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
- if(isHorizontalScrollEnabled ||isVerticalScrollEnabled)
- {
- const Vector2& targetSize = mModel->mVisualModel->mControlSize;
- const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
- const Vector2& scrollPosition = mModel->mScrollPosition;
-
- if(isHorizontalScrollEnabled)
- {
- const float displacementX = displacement.x;
- const float positionX = scrollPosition.x + displacementX;
- if(layoutSize.width > targetSize.width && -positionX > 0.f && -positionX < layoutSize.width - targetSize.width)
- {
- isScrollable = true;
- }
- }
-
- if(isVerticalScrollEnabled)
- {
- const float displacementY = displacement.y;
- const float positionY = scrollPosition.y + displacementY;
- if(layoutSize.height > targetSize.height && -positionY > 0 && -positionY < layoutSize.height - targetSize.height)
- {
- isScrollable = true;
- }
- }
- }
- }
- return isScrollable;
-}
-
-float Controller::Impl::GetHorizontalScrollPosition()
-{
- // Scroll values are negative internally so we convert them to positive numbers
- return mEventData ? -mModel->mScrollPosition.x : 0.0f;
-}
-
-float Controller::Impl::GetVerticalScrollPosition()
-{
- // Scroll values are negative internally so we convert them to positive numbers
- return mEventData ? -mModel->mScrollPosition.y : 0.0f;
-}
-
-Vector3 Controller::Impl::GetAnchorPosition(Anchor anchor) const
-{
- //TODO
- return Vector3(10.f, 10.f, 10.f);
-}
-
-Vector2 Controller::Impl::GetAnchorSize(Anchor anchor) const
-{
- //TODO
- return Vector2(10.f, 10.f);
-}
-
-Toolkit::TextAnchor Controller::Impl::CreateAnchorActor(Anchor anchor)
-{
- auto actor = Toolkit::TextAnchor::New();
- actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
- actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
- const Vector3 anchorPosition = GetAnchorPosition(anchor);
- actor.SetProperty(Actor::Property::POSITION, anchorPosition);
- const Vector2 anchorSize = GetAnchorSize(anchor);
- actor.SetProperty(Actor::Property::SIZE, anchorSize);
- std::string anchorText(mModel->mLogicalModel->mText.Begin() + anchor.startIndex, mModel->mLogicalModel->mText.Begin() + anchor.endIndex);
- actor.SetProperty(Actor::Property::NAME, anchorText);
- actor.SetProperty(Toolkit::TextAnchor::Property::URI, std::string(anchor.href));
- actor.SetProperty(Toolkit::TextAnchor::Property::START_CHARACTER_INDEX, static_cast<int>(anchor.startIndex));
- actor.SetProperty(Toolkit::TextAnchor::Property::END_CHARACTER_INDEX, static_cast<int>(anchor.endIndex));
- return actor;
-}
-
-void Controller::Impl::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
-{
- /* TODO: Now actors are created/destroyed in every "RenderText" function call. Even when we add just 1 character,
- we need to create and destroy potentially many actors. Some optimization can be considered here.
- Maybe a "dirty" flag in mLogicalModel? */
- anchorActors.clear();
- for(auto& anchor : mModel->mLogicalModel->mAnchors)
- {
- auto actor = CreateAnchorActor(anchor);
- anchorActors.push_back(actor);
- }
-}
-
-int32_t Controller::Impl::GetAnchorIndex(size_t characterOffset) const
-{
- Vector<Anchor>::Iterator it = mModel->mLogicalModel->mAnchors.Begin();
-
- while(it != mModel->mLogicalModel->mAnchors.End() && (it->startIndex > characterOffset || it->endIndex <= characterOffset))
- {
- it++;
- }
-
- return it == mModel->mLogicalModel->mAnchors.End() ? -1 : it - mModel->mLogicalModel->mAnchors.Begin();
-}
-
-void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
-{
- //Underlined character runs for markup-processor
- const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
- const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
- const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
-
- if(shouldClearPreUnderlineRuns)
- {
- mModel->mVisualModel->mUnderlineRuns.Clear();
- }
-
- for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
- {
- CharacterIndex characterIndex = it->characterRun.characterIndex;
- Length numberOfCharacters = it->characterRun.numberOfCharacters;
-
- if(numberOfCharacters == 0)
- {
- continue;
- }
-
- // Create one run for all glyphs of all run's characters that has same properties
- // This enhance performance and reduce the needed memory to store glyphs-runs
- UnderlinedGlyphRun underlineGlyphRun;
- underlineGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
- underlineGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
- //Copy properties (attributes)
- underlineGlyphRun.properties = it->properties;
-
- for(Length index = 1u; index < numberOfCharacters; index++)
- {
- underlineGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
- }
-
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
- }
-}
-
-void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels()
-{
- //Strikethrough character runs from markup-processor
- const Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns = mModel->mLogicalModel->mStrikethroughCharacterRuns;
- const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
- const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
-
- mModel->mVisualModel->mStrikethroughRuns.Clear();
-
- for(Vector<StrikethroughCharacterRun>::ConstIterator it = strikethroughCharacterRuns.Begin(), endIt = strikethroughCharacterRuns.End(); it != endIt; ++it)
- {
- CharacterIndex characterIndex = it->characterRun.characterIndex;
- Length numberOfCharacters = it->characterRun.numberOfCharacters;
-
- if(numberOfCharacters == 0)
- {
- continue;
- }
-
- StrikethroughGlyphRun strikethroughGlyphRun;
- strikethroughGlyphRun.properties = it->properties;
- strikethroughGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
- strikethroughGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
-
- for(Length index = 1u; index < numberOfCharacters; index++)
- {
- strikethroughGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
- }
-
- mModel->mVisualModel->mStrikethroughRuns.PushBack(strikethroughGlyphRun);
- }
-}
-
-void Controller::Impl::CopyCharacterSpacingFromLogicalToVisualModels()
-{
- //CharacterSpacing character runs from markup-processor
- const Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns = mModel->mLogicalModel->mCharacterSpacingCharacterRuns;
- const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
- const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
-
- mModel->mVisualModel->mCharacterSpacingRuns.Clear();
-
- for(Vector<CharacterSpacingCharacterRun>::ConstIterator it = characterSpacingCharacterRuns.Begin(), endIt = characterSpacingCharacterRuns.End(); it != endIt; ++it)
- {
- const CharacterIndex& characterIndex = it->characterRun.characterIndex;
- const Length& numberOfCharacters = it->characterRun.numberOfCharacters;
-
- if(numberOfCharacters == 0)
- {
- continue;
- }
-
- CharacterSpacingGlyphRun characterSpacingGlyphRun;
- characterSpacingGlyphRun.value = it->value;
- characterSpacingGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
- characterSpacingGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
-
- for(Length index = 1u; index < numberOfCharacters; index++)
- {
- characterSpacingGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
- }
-
- mModel->mVisualModel->mCharacterSpacingRuns.PushBack(characterSpacingGlyphRun);
- }
-}
-
-void Controller::Impl::SetAutoScrollEnabled(bool enable)
-{
- if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
- {
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
- LAYOUT |
- ALIGN |
- UPDATE_LAYOUT_SIZE |
- REORDER);
-
- if(enable)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | UPDATE_DIRECTION);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
- }
-
- mIsAutoScrollEnabled = enable;
- RequestRelayout();
- }
- else
- {
- DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
- mIsAutoScrollEnabled = false;
- }
-}
-
-void Controller::Impl::SetEnableCursorBlink(bool enable)
-{
- DALI_ASSERT_DEBUG(NULL != mEventData && "TextInput disabled");
-
- if(mEventData)
- {
- mEventData->mCursorBlinkEnabled = enable;
-
- if(!enable && mEventData->mDecorator)
- {
- mEventData->mDecorator->StopCursorBlink();
- }
- }
-}
-
-void Controller::Impl::SetMultiLineEnabled(bool enable)
-{
- const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
-
- if(layout != mLayoutEngine.GetLayout())
- {
- // Set the layout type.
- mLayoutEngine.SetLayout(layout);
-
- // Set the flags to redo the layout operations
- const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
- UPDATE_LAYOUT_SIZE |
- ALIGN |
- REORDER);
-
- mTextUpdateInfo.mFullRelayoutNeeded = true;
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | layoutOperations);
-
- // Need to recalculate natural size
- mRecalculateNaturalSize = true;
-
- RequestRelayout();
- }
-}
-
-void Controller::Impl::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
-{
- if(alignment != mModel->mHorizontalAlignment)
- {
- // Set the alignment.
- mModel->mHorizontalAlignment = alignment;
- UpdateCursorPositionForAlignment(*this, true);
- RequestRelayout();
- }
-}
-
-void Controller::Impl::SetVerticalAlignment(VerticalAlignment::Type alignment)
-{
- if(alignment != mModel->mVerticalAlignment)
- {
- // Set the alignment.
- mModel->mVerticalAlignment = alignment;
- UpdateCursorPositionForAlignment(*this, false);
- RequestRelayout();
- }
-}
-
-void Controller::Impl::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
-{
- if(lineWrapMode != mModel->mLineWrapMode)
- {
- // Update Text layout for applying wrap mode
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
- ALIGN |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER);
-
- if((mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
- (mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
- {
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | GET_LINE_BREAKS);
- }
-
- // Set the text wrap mode.
- mModel->mLineWrapMode = lineWrapMode;
-
- mTextUpdateInfo.mCharacterIndex = 0u;
- mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
- mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count();
-
- // Request relayout
- RequestRelayout();
- }
-}
-
-void Controller::Impl::SetDefaultColor(const Vector4& color)
-{
- mTextColor = color;
-
- if(!IsShowingPlaceholderText())
- {
- mModel->mVisualModel->SetTextColor(color);
- mModel->mLogicalModel->mColorRuns.Clear();
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | COLOR);
- RequestRelayout();
- }
-}
-
-void Controller::Impl::SetUserInteractionEnabled(bool enabled)
-{
- mIsUserInteractionEnabled = enabled;
-
- if(mEventData && mEventData->mDecorator)
- {
- bool editable = mEventData->mEditingEnabled && enabled;
- mEventData->mDecorator->SetEditable(editable);
- }
-}
-
-void Controller::Impl::ClearFontData()
-{
- if(mFontDefaults)
- {
- mFontDefaults->mFontId = 0u; // Remove old font ID
- }
-
- // Set flags to update the model.
- mTextUpdateInfo.mCharacterIndex = 0u;
- mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
- mTextUpdateInfo.mNumberOfCharactersToAdd = mModel->mLogicalModel->mText.Count();
-
- mTextUpdateInfo.mClearAll = true;
- mTextUpdateInfo.mFullRelayoutNeeded = true;
- mRecalculateNaturalSize = true;
-
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
- VALIDATE_FONTS |
- SHAPE_TEXT |
- BIDI_INFO |
- GET_GLYPH_METRICS |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER |
- ALIGN);
-}
-
-void Controller::Impl::ClearStyleData()
-{
- mModel->mLogicalModel->mColorRuns.Clear();
- mModel->mLogicalModel->ClearFontDescriptionRuns();
- mModel->mLogicalModel->ClearStrikethroughRuns();
-}
-
-void Controller::Impl::ResetScrollPosition()
-{
- if(mEventData)
- {
- // Reset the scroll position.
- mModel->mScrollPosition = Vector2::ZERO;
- mEventData->mScrollAfterUpdatePosition = true;
- }
-}
-
-} // namespace Dali::Toolkit::Text
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/clipboard.h>
-#include <dali/devel-api/text-abstraction/font-client.h>
-#include <dali/public-api/rendering/shader.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
-#include <dali-toolkit/internal/text/input-style.h>
-#include <dali-toolkit/internal/text/text-controller.h>
-#include <dali-toolkit/internal/text/text-model.h>
-#include <dali-toolkit/internal/text/text-view.h>
-#include <dali-toolkit/public-api/styling/style-manager.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-const float DEFAULT_TEXTFIT_MIN = 10.f;
-const float DEFAULT_TEXTFIT_MAX = 100.f;
-const float DEFAULT_TEXTFIT_STEP = 1.f;
-const float DEFAULT_FONT_SIZE_SCALE = 1.f;
-const float DEFAULT_DISABLED_COLOR_OPACITY = 0.3f;
-
-//Forward declarations
-struct CursorInfo;
-struct FontDefaults;
-struct ControllerImplEventHandler;
-struct ControllerImplModelUpdater;
-struct SelectionHandleController;
-
-class SelectableControlInterface;
-class AnchorControlInterface;
-
-struct Event
-{
- // Used to queue input events until DoRelayout()
- enum Type
- {
- CURSOR_KEY_EVENT,
- TAP_EVENT,
- PAN_EVENT,
- LONG_PRESS_EVENT,
- GRAB_HANDLE_EVENT,
- LEFT_SELECTION_HANDLE_EVENT,
- RIGHT_SELECTION_HANDLE_EVENT,
- SELECT,
- SELECT_ALL,
- SELECT_NONE,
- SELECT_RANGE,
- };
-
- union Param
- {
- int mInt;
- unsigned int mUint;
- float mFloat;
- bool mBool;
- };
-
- Event(Type eventType)
- : type(eventType)
- {
- p1.mInt = 0;
- p2.mInt = 0;
- p3.mInt = 0;
- }
-
- Type type;
- Param p1;
- Param p2;
- Param p3;
-};
-
-struct EventData
-{
- enum State
- {
- INACTIVE,
- INTERRUPTED,
- SELECTING,
- EDITING,
- EDITING_WITH_POPUP,
- EDITING_WITH_GRAB_HANDLE,
- EDITING_WITH_PASTE_POPUP,
- GRAB_HANDLE_PANNING,
- SELECTION_HANDLE_PANNING,
- TEXT_PANNING
- };
-
- EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext);
-
- ~EventData() = default;
-
- static bool IsEditingState(State stateToCheck)
- {
- return (stateToCheck == EDITING || stateToCheck == EDITING_WITH_POPUP || stateToCheck == EDITING_WITH_GRAB_HANDLE || stateToCheck == EDITING_WITH_PASTE_POPUP);
- }
-
- DecoratorPtr mDecorator; ///< Pointer to the decorator.
- InputMethodContext mInputMethodContext; ///< The Input Method Framework Manager.
- std::unique_ptr<FontDefaults> mPlaceholderFont; ///< The placeholder default font.
- std::string mPlaceholderTextActive; ///< The text to display when the TextField is empty with key-input focus.
- std::string mPlaceholderTextInactive; ///< The text to display when the TextField is empty and inactive.
- Vector4 mPlaceholderTextColor; ///< The in/active placeholder text color.
-
- /**
- * This is used to delay handling events until after the model has been updated.
- * The number of updates to the model is minimized to improve performance.
- */
- std::vector<Event> mEventQueue; ///< The queue of touch events etc.
-
- Vector<InputStyle::Mask> mInputStyleChangedQueue; ///< Queue of changes in the input style. Used to emit the signal in the iddle callback.
-
- InputStyle mInputStyle; ///< The style to be set to the new inputed text.
-
- State mPreviousState; ///< Stores the current state before it's updated with the new one.
- State mState; ///< Selection mode, edit mode etc.
-
- CharacterIndex mPrimaryCursorPosition; ///< Index into logical model for primary cursor.
- CharacterIndex mLeftSelectionPosition; ///< Index into logical model for left selection handle.
- CharacterIndex mRightSelectionPosition; ///< Index into logical model for right selection handle.
-
- CharacterIndex mPreEditStartPosition; ///< Used to remove the pre-edit text if necessary.
- Length mPreEditLength; ///< Used to remove the pre-edit text if necessary.
-
- float mCursorHookPositionX; ///< Used to move the cursor with the keys or when scrolling the text vertically with the handles.
-
- Controller::NoTextTap::Action mDoubleTapAction; ///< Action to be done when there is a double tap on top of 'no text'
- Controller::NoTextTap::Action mLongPressAction; ///< Action to be done when there is a long press on top of 'no text'
-
- bool mIsShowingPlaceholderText : 1; ///< True if the place-holder text is being displayed.
- bool mPreEditFlag : 1; ///< True if the model contains text in pre-edit state.
- bool mDecoratorUpdated : 1; ///< True if the decorator was updated during event processing.
- bool mCursorBlinkEnabled : 1; ///< True if cursor should blink when active.
- bool mGrabHandleEnabled : 1; ///< True if grab handle is enabled.
- bool mGrabHandlePopupEnabled : 1; ///< True if the grab handle popu-up should be shown.
- bool mSelectionEnabled : 1; ///< True if selection handles, highlight etc. are enabled.
- bool mUpdateCursorHookPosition : 1; ///< True if the cursor hook position must be updated. Used to move the cursor with the keys 'up' and 'down'.
- bool mUpdateCursorPosition : 1; ///< True if the visual position of the cursor must be recalculated.
- bool mUpdateGrabHandlePosition : 1; ///< True if the visual position of the grab handle must be recalculated.
- bool mUpdateLeftSelectionPosition : 1; ///< True if the visual position of the left selection handle must be recalculated.
- bool mUpdateRightSelectionPosition : 1; ///< True if the visual position of the right selection handle must be recalculated.
- bool mIsLeftHandleSelected : 1; ///< Whether is the left handle the one which is selected.
- bool mIsRightHandleSelected : 1; ///< Whether is the right handle the one which is selected.
- bool mUpdateHighlightBox : 1; ///< True if the text selection high light box must be updated.
- bool mScrollAfterUpdatePosition : 1; ///< Whether to scroll after the cursor position is updated.
- bool mScrollAfterDelete : 1; ///< Whether to scroll after delete characters.
- bool mAllTextSelected : 1; ///< True if the selection handles are selecting all the text.
- bool mUpdateInputStyle : 1; ///< Whether to update the input style after moving the cursor.
- bool mPasswordInput : 1; ///< True if password input is enabled.
- bool mCheckScrollAmount : 1; ///< Whether to check scrolled amount after updating the position
- bool mIsPlaceholderPixelSize : 1; ///< True if the placeholder font size is set as pixel size.
- bool mIsPlaceholderElideEnabled : 1; ///< True if the placeholder text's elide is enabled.
- bool mPlaceholderEllipsisFlag : 1; ///< True if the text controller sets the placeholder ellipsis.
- bool mShiftSelectionFlag : 1; ///< True if the text selection using Shift key is enabled.
- bool mUpdateAlignment : 1; ///< True if the whole text needs to be full aligned..
- bool mEditingEnabled : 1; ///< True if the editing is enabled, false otherwise.
-};
-
-struct ModifyEvent
-{
- enum Type
- {
- TEXT_REPLACED, ///< The entire text was replaced
- TEXT_INSERTED, ///< Insert characters at the current cursor position
- TEXT_DELETED ///< Characters were deleted
- };
-
- Type type;
-};
-
-struct FontDefaults
-{
- FontDefaults()
- : mFontDescription(),
- mDefaultPointSize(0.f),
- mFitPointSize(0.f),
- mFontId(0u),
- familyDefined(false),
- weightDefined(false),
- widthDefined(false),
- slantDefined(false),
- sizeDefined(false)
- {
- // Initially use the default platform font
- TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
- fontClient.GetDefaultPlatformFontDescription(mFontDescription);
- }
-
- FontId GetFontId(TextAbstraction::FontClient& fontClient, float fontPointSize)
- {
- if(!mFontId)
- {
- const PointSize26Dot6 pointSize = static_cast<PointSize26Dot6>(fontPointSize * 64.f);
- mFontId = fontClient.GetFontId(mFontDescription, pointSize);
- }
-
- return mFontId;
- }
-
- TextAbstraction::FontDescription mFontDescription; ///< The default font's description.
- float mDefaultPointSize; ///< The default font's point size.
- float mFitPointSize; ///< The fit font's point size.
- FontId mFontId; ///< The font's id of the default font.
- bool familyDefined : 1; ///< Whether the default font's family name is defined.
- bool weightDefined : 1; ///< Whether the default font's weight is defined.
- bool widthDefined : 1; ///< Whether the default font's width is defined.
- bool slantDefined : 1; ///< Whether the default font's slant is defined.
- bool sizeDefined : 1; ///< Whether the default font's point size is defined.
-};
-
-/**
- * @brief Stores indices used to update the text.
- * Stores the character index where the text is updated and the number of characters removed and added.
- * Stores as well indices to the first and the last paragraphs to be updated.
- */
-struct TextUpdateInfo
-{
- TextUpdateInfo()
- : mCharacterIndex(0u),
- mNumberOfCharactersToRemove(0u),
- mNumberOfCharactersToAdd(0u),
- mPreviousNumberOfCharacters(0u),
- mParagraphCharacterIndex(0u),
- mRequestedNumberOfCharacters(0u),
- mStartGlyphIndex(0u),
- mStartLineIndex(0u),
- mEstimatedNumberOfLines(0u),
- mClearAll(true),
- mFullRelayoutNeeded(true),
- mIsLastCharacterNewParagraph(false)
- {
- }
-
- ~TextUpdateInfo()
- {
- }
-
- CharacterIndex mCharacterIndex; ///< Index to the first character to be updated.
- Length mNumberOfCharactersToRemove; ///< The number of characters to be removed.
- Length mNumberOfCharactersToAdd; ///< The number of characters to be added.
- Length mPreviousNumberOfCharacters; ///< The number of characters before the text update.
-
- CharacterIndex mParagraphCharacterIndex; ///< Index of the first character of the first paragraph to be updated.
- Length mRequestedNumberOfCharacters; ///< The requested number of characters.
- GlyphIndex mStartGlyphIndex;
- LineIndex mStartLineIndex;
- Length mEstimatedNumberOfLines; ///< The estimated number of lines. Used to avoid reallocations when layouting.
-
- bool mClearAll : 1; ///< Whether the whole text is cleared. i.e. when the text is reset.
- bool mFullRelayoutNeeded : 1; ///< Whether a full re-layout is needed. i.e. when a new size is set to the text control.
- bool mIsLastCharacterNewParagraph : 1; ///< Whether the last character is a new paragraph character.
-
- void Clear()
- {
- // Clear all info except the mPreviousNumberOfCharacters member.
- mCharacterIndex = static_cast<CharacterIndex>(-1);
- mNumberOfCharactersToRemove = 0u;
- mNumberOfCharactersToAdd = 0u;
- mParagraphCharacterIndex = 0u;
- mRequestedNumberOfCharacters = 0u;
- mStartGlyphIndex = 0u;
- mStartLineIndex = 0u;
- mEstimatedNumberOfLines = 0u;
- mClearAll = false;
- mFullRelayoutNeeded = false;
- mIsLastCharacterNewParagraph = false;
- }
-};
-
-struct UnderlineDefaults
-{
- std::string properties;
- // TODO: complete with underline parameters.
-};
-
-struct ShadowDefaults
-{
- std::string properties;
- // TODO: complete with shadow parameters.
-};
-
-struct EmbossDefaults
-{
- std::string properties;
- // TODO: complete with emboss parameters.
-};
-
-struct OutlineDefaults
-{
- std::string properties;
- // TODO: complete with outline parameters.
-};
-
-struct Controller::Impl
-{
- Impl(ControlInterface* controlInterface,
- EditableControlInterface* editableControlInterface,
- SelectableControlInterface* selectableControlInterface,
- AnchorControlInterface* anchorControlInterface)
- : mControlInterface(controlInterface),
- mEditableControlInterface(editableControlInterface),
- mSelectableControlInterface(selectableControlInterface),
- mAnchorControlInterface(anchorControlInterface),
- mModel(),
- mFontDefaults(NULL),
- mUnderlineDefaults(NULL),
- mShadowDefaults(NULL),
- mEmbossDefaults(NULL),
- mOutlineDefaults(NULL),
- mEventData(NULL),
- mFontClient(),
- mClipboard(),
- mView(),
- mMetrics(),
- mModifyEvents(),
- mTextColor(Color::BLACK),
- mTextUpdateInfo(),
- mOperationsPending(NO_OPERATION),
- mMaximumNumberOfCharacters(50u),
- mHiddenInput(NULL),
- mInputFilter(nullptr),
- mRecalculateNaturalSize(true),
- mMarkupProcessorEnabled(false),
- mClipboardHideEnabled(true),
- mIsAutoScrollEnabled(false),
- mIsAutoScrollMaxTextureExceeded(false),
- mUpdateTextDirection(true),
- mIsTextDirectionRTL(false),
- mUnderlineSetByString(false),
- mShadowSetByString(false),
- mOutlineSetByString(false),
- mFontStyleSetByString(false),
- mStrikethroughSetByString(false),
- mShouldClearFocusOnEscape(true),
- mLayoutDirection(LayoutDirection::LEFT_TO_RIGHT),
- mTextFitMinSize(DEFAULT_TEXTFIT_MIN),
- mTextFitMaxSize(DEFAULT_TEXTFIT_MAX),
- mTextFitStepSize(DEFAULT_TEXTFIT_STEP),
- mFontSizeScale(DEFAULT_FONT_SIZE_SCALE),
- mDisabledColorOpacity(DEFAULT_DISABLED_COLOR_OPACITY),
- mFontSizeScaleEnabled(true),
- mTextFitEnabled(false),
- mTextFitChanged(false),
- mIsLayoutDirectionChanged(false),
- mIsUserInteractionEnabled(true)
- {
- mModel = Model::New();
-
- mFontClient = TextAbstraction::FontClient::Get();
- mClipboard = Clipboard::Get();
-
- mView.SetVisualModel(mModel->mVisualModel);
- mView.SetLogicalModel(mModel->mLogicalModel);
-
- // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
- mMetrics = Metrics::New(mFontClient);
- mLayoutEngine.SetMetrics(mMetrics);
-
- // Set the text properties to default
- mModel->mVisualModel->SetUnderlineEnabled(false);
- mModel->mVisualModel->SetUnderlineHeight(0.0f);
-
- Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
- if(styleManager)
- {
- const Property::Map& config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
- const auto clearFocusOnEscapeValue = config.Find("clearFocusOnEscape", Property::Type::BOOLEAN);
-
- // Default is true. If config don't have "clearFocusOnEscape" property, make it true.
- mShouldClearFocusOnEscape = (!clearFocusOnEscapeValue || clearFocusOnEscapeValue->Get<bool>());
- }
- }
-
- ~Impl()
- {
- delete mHiddenInput;
- delete mFontDefaults;
- delete mUnderlineDefaults;
- delete mShadowDefaults;
- delete mEmbossDefaults;
- delete mOutlineDefaults;
- delete mEventData;
- }
-
- // Text Controller Implementation.
-
- /**
- * @copydoc Text::Controller::RequestRelayout()
- */
- void RequestRelayout();
-
- /**
- * @brief Request a relayout using the ControlInterface.
- */
- void QueueModifyEvent(ModifyEvent::Type type)
- {
- if(ModifyEvent::TEXT_REPLACED == type)
- {
- // Cancel previously queued inserts etc.
- mModifyEvents.Clear();
- }
-
- ModifyEvent event;
- event.type = type;
- mModifyEvents.PushBack(event);
-
- // The event will be processed during relayout
- RequestRelayout();
- }
-
- /**
- * @brief Helper to move the cursor, grab handle etc.
- */
- bool ProcessInputEvents();
-
- /**
- * @brief Helper to check whether any place-holder text is available.
- */
- bool IsPlaceholderAvailable() const
- {
- return (mEventData &&
- (!mEventData->mPlaceholderTextInactive.empty() ||
- !mEventData->mPlaceholderTextActive.empty()));
- }
-
- bool IsShowingPlaceholderText() const
- {
- return (mEventData && mEventData->mIsShowingPlaceholderText);
- }
-
- /**
- * @brief Helper to check whether active place-holder text is available.
- */
- bool IsFocusedPlaceholderAvailable() const
- {
- return (mEventData && !mEventData->mPlaceholderTextActive.empty());
- }
-
- bool IsShowingRealText() const
- {
- return (!IsShowingPlaceholderText() &&
- 0u != mModel->mLogicalModel->mText.Count());
- }
-
- /**
- * @brief Called when placeholder-text is hidden
- */
- void PlaceholderCleared()
- {
- if(mEventData)
- {
- mEventData->mIsShowingPlaceholderText = false;
-
- // Remove mPlaceholderTextColor
- mModel->mVisualModel->SetTextColor(mTextColor);
- }
- }
-
- void ClearPreEditFlag()
- {
- if(mEventData)
- {
- mEventData->mPreEditFlag = false;
- mEventData->mPreEditStartPosition = 0;
- mEventData->mPreEditLength = 0;
- }
- }
-
- void ResetInputMethodContext()
- {
- if(mEventData)
- {
- // Reset incase we are in a pre-edit state.
- if(mEventData->mInputMethodContext)
- {
- mEventData->mInputMethodContext.Reset(); // Will trigger a message ( commit, get surrounding )
- }
-
- ClearPreEditFlag();
- }
- }
-
- float GetFontSizeScale()
- {
- return mFontSizeScaleEnabled ? mFontSizeScale : 1.0f;
- }
-
- /**
- * @brief Helper to notify InputMethodContext with surrounding text & cursor changes.
- */
- void NotifyInputMethodContext();
-
- /**
- * @brief Helper to notify InputMethodContext with multi line status.
- */
- void NotifyInputMethodContextMultiLineStatus();
-
- /**
- * @brief Retrieve the current cursor position.
- *
- * @return The cursor position.
- */
- CharacterIndex GetLogicalCursorPosition() const;
-
- /**
- * @brief Retrieves the number of consecutive white spaces starting from the given @p index.
- *
- * @param[in] index The character index from where to count the number of consecutive white spaces.
- *
- * @return The number of consecutive white spaces.
- */
- Length GetNumberOfWhiteSpaces(CharacterIndex index) const;
-
- /**
- * @brief Retrieve any text previously set.
- *
- * @param[out] text A string of UTF-8 characters.
- */
- void GetText(std::string& text) const;
-
- /**
- * @brief Retrieve any text previously set starting from the given @p index.
- *
- * @param[in] index The character index from where to retrieve the text.
- * @param[out] text A string of UTF-8 characters.
- *
- * @see Dali::Toolkit::Text::Controller::GetText()
- */
- void GetText(CharacterIndex index, std::string& text) const;
-
- bool IsClipboardEmpty()
- {
- bool result(mClipboard && mClipboard.NumberOfItems());
- return !result; // If NumberOfItems greater than 0, return false
- }
-
- bool IsClipboardVisible()
- {
- bool result(mClipboard && mClipboard.IsVisible());
- return result;
- }
-
- /**
- * @copydoc Controller::GetLayoutDirection()
- */
- Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
-
- /**
- * @brief Checks text direction.
- * @return The text direction.
- */
- Toolkit::DevelText::TextDirection::Type GetTextDirection();
-
- /**
- * @brief Calculates the start character index of the first paragraph to be updated and
- * the end character index of the last paragraph to be updated.
- *
- * @param[out] numberOfCharacters The number of characters to be updated.
- */
- void CalculateTextUpdateIndices(Length& numberOfCharacters);
-
- /**
- * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
- *
- * @note It never clears the text stored in utf32.
- *
- * @param[in] startIndex Index to the first character to be cleared.
- * @param[in] endIndex Index to the last character to be cleared.
- * @param[in] operations The operations required.
- */
- void ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations);
-
- /**
- * @brief Updates the logical and visual models. Updates the style runs in the visual model when the text's styles changes.
- *
- * When text or style changes the model is set with some operations pending.
- * When i.e. the text's size or a relayout is required this method is called
- * with a given @p operationsRequired parameter. The operations required are
- * matched with the operations pending to perform the minimum number of operations.
- *
- * @param[in] operationsRequired The operations required.
- *
- * @return @e true if the model has been modified.
- */
- bool UpdateModel(OperationsMask operationsRequired);
-
- /**
- * @brief Retreieves the default style.
- *
- * @param[out] inputStyle The default style.
- */
- void RetrieveDefaultInputStyle(InputStyle& inputStyle);
-
- /**
- * @brief Retrieve the line height of the default font.
- */
- float GetDefaultFontLineHeight();
-
- /**
- * @copydoc Controller::SetDefaultLineSpacing
- */
- bool SetDefaultLineSpacing(float lineSpacing);
-
- /**
- * @copydoc Controller::SetDefaultLineSize
- */
- bool SetDefaultLineSize(float lineSize);
-
- /**
- * @copydoc Controller::SetRelativeLineSize
- */
- bool SetRelativeLineSize(float relativeLineSize);
-
- /**
- * @copydoc Controller::GetRelativeLineSize
- */
- float GetRelativeLineSize();
-
- /**
- * @copydoc Text::Controller::GetPrimaryCursorPosition()
- */
- CharacterIndex GetPrimaryCursorPosition() const;
-
- /**
- * @copydoc Text::Controller::SetPrimaryCursorPosition()
- */
- bool SetPrimaryCursorPosition(CharacterIndex index, bool focused);
-
- /**
- * @copydoc Text::SelectableControlInterface::GetSelectedText()
- */
- string GetSelectedText();
-
- /**
- * @copydoc Text::EditableControlInterface::CopyText()
- */
- string CopyText();
-
- /**
- * @copydoc Text::EditableControlInterface::CutText()
- */
- string CutText();
-
- /**
- * @copydoc Text::SelectableControlInterface::SetTextSelectionRange()
- */
- void SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEndf);
-
- /**
- * @copydoc Text::SelectableControlInterface::GetTextSelectionRange()
- */
- Uint32Pair GetTextSelectionRange() const;
-
- /**
- * @copydoc Text::EditableControlInterface::IsEditable()
- */
- bool IsEditable() const;
-
- /**
- * @copydoc Text::EditableControlInterface::SetEditable()
- */
- void SetEditable(bool editable);
-
- /**
- * @copydoc Controller::UpdateAfterFontChange
- */
- void UpdateAfterFontChange(const std::string& newDefaultFont);
-
- /**
- * @brief Retrieves the selected text. It removes the text if the @p deleteAfterRetrieval parameter is @e true.
- *
- * @param[out] selectedText The selected text encoded in utf8.
- * @param[in] deleteAfterRetrieval Whether the text should be deleted after retrieval.
- */
- void RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval);
-
- void SetSelection(int start, int end);
-
- std::pair<int, int> GetSelectionIndexes() const;
-
- void ShowClipboard();
-
- void HideClipboard();
-
- void SetClipboardHideEnable(bool enable);
-
- bool CopyStringToClipboard(const std::string& source);
-
- void SendSelectionToClipboard(bool deleteAfterSending);
-
- void RequestGetTextFromClipboard();
-
- void RepositionSelectionHandles();
- void RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action);
-
- void SetPopupButtons();
-
- void ChangeState(EventData::State newState);
-
- /**
- * @brief Calculates the cursor's position for a given character index in the logical order.
- *
- * It retrieves as well the line's height and the cursor's height and
- * if there is a valid alternative cursor, its position and height.
- *
- * @param[in] logical The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
- * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
- */
- void GetCursorPosition(CharacterIndex logical,
- CursorInfo& cursorInfo);
-
- /**
- * @brief Calculates the new cursor index.
- *
- * It takes into account that in some scripts multiple characters can form a glyph and all of them
- * need to be jumped with one key event.
- *
- * @param[in] index The initial new index.
- *
- * @return The new cursor index.
- */
- CharacterIndex CalculateNewCursorIndex(CharacterIndex index) const;
-
- /**
- * @brief Updates the cursor position.
- *
- * Sets the cursor's position into the decorator. It transforms the cursor's position into decorator's coords.
- * It sets the position of the secondary cursor if it's a valid one.
- * Sets which cursors are active.
- *
- * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
- *
- */
- void UpdateCursorPosition(const CursorInfo& cursorInfo);
-
- /**
- * @brief Updates the position of the given selection handle. It transforms the handle's position into decorator's coords.
- *
- * @param[in] handleType One of the selection handles.
- * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
- */
- void UpdateSelectionHandle(HandleType handleType,
- const CursorInfo& cursorInfo);
-
- /**
- * @biref Clamps the horizontal scrolling to get the control always filled with text.
- *
- * @param[in] layoutSize The size of the laid out text.
- */
- void ClampHorizontalScroll(const Vector2& layoutSize);
-
- /**
- * @biref Clamps the vertical scrolling to get the control always filled with text.
- *
- * @param[in] layoutSize The size of the laid out text.
- */
- void ClampVerticalScroll(const Vector2& layoutSize);
-
- /**
- * @brief Scrolls the text to make a position visible.
- *
- * @pre mEventData must not be NULL. (there is a text-input or selection capabilities).
- *
- * @param[in] position A position in text coords.
- * @param[in] lineHeight The line height for the given position.
- *
- * This method is called after inserting text, moving the cursor with the grab handle or the keypad,
- * or moving the selection handles.
- */
- void ScrollToMakePositionVisible(const Vector2& position, float lineHeight);
-
- /**
- * @brief Scrolls the text to make the cursor visible.
- *
- * This method is called after deleting text.
- */
- void ScrollTextToMatchCursor(const CursorInfo& cursorInfo);
-
- /**
- * @brief Scrolls the text to make primary cursor visible.
- */
- void ScrollTextToMatchCursor();
-
- /**
- * @brief Create an actor that renders the text background color
- *
- * @return the created actor or an empty handle if no background color needs to be rendered.
- */
- Actor CreateBackgroundActor();
-
- /**
- * @brief fill needed relayout parameters whenever a property is changed and a re-layout is needed for the entire text.
- */
- void RelayoutAllCharacters();
-
- /**
- * @copydoc Controller::IsInputStyleChangedSignalsQueueEmpty
- */
- bool IsInputStyleChangedSignalsQueueEmpty();
-
- /**
- * @copydoc Controller::ProcessInputStyleChangedSignals
- */
- void ProcessInputStyleChangedSignals();
-
- /**
- * @copydoc Controller::ScrollBy()
- */
- void ScrollBy(Vector2 scroll);
-
- /**
- * @copydoc Controller::IsScrollable()
- */
- bool IsScrollable(const Vector2& displacement);
-
- /**
- * @copydoc Controller::GetHorizontalScrollPosition()
- */
- float GetHorizontalScrollPosition();
-
- /**
- * @copydoc Controller::GetVerticalScrollPosition()
- */
- float GetVerticalScrollPosition();
-
- /**
- * @copydoc Controller::SetAutoScrollEnabled()
- */
- void SetAutoScrollEnabled(bool enable);
-
- /**
- * @copydoc Controller::SetEnableCursorBlink()
- */
- void SetEnableCursorBlink(bool enable);
-
- /**
- * @copydoc Controller::SetMultiLineEnabled()
- */
- void SetMultiLineEnabled(bool enable);
-
- /**
- * @copydoc Controller::SetHorizontalAlignment()
- */
- void SetHorizontalAlignment(HorizontalAlignment::Type alignment);
-
- /**
- * @copydoc Controller::SetVerticalAlignment()
- */
- void SetVerticalAlignment(VerticalAlignment::Type alignment);
-
- /**
- * @copydoc Controller::SetLineWrapMode()
- */
- void SetLineWrapMode(Text::LineWrap::Mode textWarpMode);
-
- /**
- * @copydoc Controller::SetDefaultColor()
- */
- void SetDefaultColor(const Vector4& color);
-
- /**
- * @copydoc Controller::SetUserInteractionEnabled()
- */
- void SetUserInteractionEnabled(bool enabled);
-
- /**
- * @brief Helper to clear font-specific data (only).
- */
- void ClearFontData();
-
- /**
- * @brief Helper to clear text's style data.
- */
- void ClearStyleData();
-
- /**
- * @brief Used to reset the scroll position after setting a new text.
- */
- void ResetScrollPosition();
-
- /**
- * @brief Resets a provided vector with actors that marks the position of anchors in markup enabled text
- *
- * @param[out] anchorActors the vector of actor (empty collection if no anchors available).
- */
- void GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors);
-
- /**
- * @brief Return an index of first anchor in the anchor vector whose boundaries includes given character offset
- *
- * @param[in] characterOffset A position in text coords.
- *
- * @return the 0-based index in anchor vector (-1 if an anchor not found)
- */
- int32_t GetAnchorIndex(size_t characterOffset) const;
-
- /**
- * @brief Return the geometrical position of an anchor relative to the parent origin point.
- *
- * @param[in] anchor An anchor.
- *
- * @return The x, y, z coordinates of an anchor.
- */
- Vector3 GetAnchorPosition(Anchor anchor) const;
-
- /**
- * @brief Return the size of an anchor expresed as a vector containing anchor's width and height.
- *
- * @param[in] anchor An anchor.
- *
- * @return The width and height of an anchor.
- */
- Vector2 GetAnchorSize(Anchor anchor) const;
-
- /**
- * @brief Return the actor representing an anchor.
- *
- * @param[in] anchor An anchor.
- *
- * @return The actor representing an anchor.
- */
- Toolkit::TextAnchor CreateAnchorActor(Anchor anchor);
-
-public:
- /**
- * @brief Gets implementation from the controller handle.
- * @param controller The text controller
- * @return The implementation of the Controller
- */
- static Impl& GetImplementation(Text::Controller& controller)
- {
- return *controller.mImpl;
- }
-
-private:
- // Declared private and left undefined to avoid copies.
- Impl(const Impl&);
- // Declared private and left undefined to avoid copies.
- Impl& operator=(const Impl&);
-
- /**
- * @brief Copy Underlined-Character-Runs from Logical-Model to Underlined-Glyph-Runs in Visual-Model
- *
- * @param shouldClearPreUnderlineRuns Whether should clear the existing Underlined-Glyph-Runs in Visual-Model
- */
- void CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns);
-
- /**
- * @brief Copy strikethrough-Character-Runs from Logical-Model to strikethrough-Glyph-Runs in Visual-Model
- *
- */
- void CopyStrikethroughFromLogicalToVisualModels();
-
- /**
- * @brief Copy CharacterSpacing-Character-Runs from Logical-Model to CharacterSpacing-Glyph-Runs in Visual-Model
- *
- */
- void CopyCharacterSpacingFromLogicalToVisualModels();
-
-public:
- ControlInterface* mControlInterface; ///< Reference to the text controller.
- EditableControlInterface* mEditableControlInterface; ///< Reference to the editable text controller.
- SelectableControlInterface* mSelectableControlInterface; ///< Reference to the selectable text controller.
- AnchorControlInterface* mAnchorControlInterface; ///< Reference to the anchor controller.
- ModelPtr mModel; ///< Pointer to the text's model.
- FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
- UnderlineDefaults* mUnderlineDefaults; ///< Avoid allocating this when the user does not specify underline parameters.
- ShadowDefaults* mShadowDefaults; ///< Avoid allocating this when the user does not specify shadow parameters.
- EmbossDefaults* mEmbossDefaults; ///< Avoid allocating this when the user does not specify emboss parameters.
- OutlineDefaults* mOutlineDefaults; ///< Avoid allocating this when the user does not specify outline parameters.
- EventData* mEventData; ///< Avoid allocating everything for text input until EnableTextInput().
- TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
- Clipboard mClipboard; ///< Handle to the system clipboard
- View mView; ///< The view interface to the rendering back-end.
- MetricsPtr mMetrics; ///< A wrapper around FontClient used to get metrics & potentially down-scaled Emoji metrics.
- Layout::Engine mLayoutEngine; ///< The layout engine.
- Vector<ModifyEvent> mModifyEvents; ///< Temporary stores the text set until the next relayout.
- Vector4 mTextColor; ///< The regular text color
- TextUpdateInfo mTextUpdateInfo; ///< Info of the characters updated.
- OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
- Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
- HiddenText* mHiddenInput; ///< Avoid allocating this when the user does not specify hidden input mode.
- std::unique_ptr<InputFilter> mInputFilter; ///< Avoid allocating this when the user does not specify input filter mode.
- Vector2 mTextFitContentSize; ///< Size of Text fit content
-
- bool mRecalculateNaturalSize : 1; ///< Whether the natural size needs to be recalculated.
- bool mMarkupProcessorEnabled : 1; ///< Whether the mark-up procesor is enabled.
- bool mClipboardHideEnabled : 1; ///< Whether the ClipboardHide function work or not
- bool mIsAutoScrollEnabled : 1; ///< Whether auto text scrolling is enabled.
- bool mIsAutoScrollMaxTextureExceeded : 1; ///< Whether auto text scrolling is exceed max texture size.
- bool mUpdateTextDirection : 1; ///< Whether the text direction needs to be updated.
- CharacterDirection mIsTextDirectionRTL : 1; ///< Whether the text direction is right to left or not
-
- bool mUnderlineSetByString : 1; ///< Set when underline is set by string (legacy) instead of map
- bool mShadowSetByString : 1; ///< Set when shadow is set by string (legacy) instead of map
- bool mOutlineSetByString : 1; ///< Set when outline is set by string (legacy) instead of map
- bool mFontStyleSetByString : 1; ///< Set when font style is set by string (legacy) instead of map
- bool mStrikethroughSetByString : 1; ///< Set when strikethrough is set by string (legacy) instead of map
- bool mShouldClearFocusOnEscape : 1; ///< Whether text control should clear key input focus
- LayoutDirection::Type mLayoutDirection; ///< Current system language direction
-
- Shader mShaderBackground; ///< The shader for text background.
-
- float mTextFitMinSize; ///< Minimum Font Size for text fit. Default 10
- float mTextFitMaxSize; ///< Maximum Font Size for text fit. Default 100
- float mTextFitStepSize; ///< Step Size for font intervalse. Default 1
- float mFontSizeScale; ///< Scale value for Font Size. Default 1.0
- float mDisabledColorOpacity; ///< Color opacity when disabled.
- bool mFontSizeScaleEnabled : 1; ///< Whether the font size scale is enabled.
- bool mTextFitEnabled : 1; ///< Whether the text's fit is enabled.
- bool mTextFitChanged : 1; ///< Whether the text fit property has changed.
- bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
- bool mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled.
-
-private:
- friend ControllerImplEventHandler;
- friend ControllerImplModelUpdater;
- friend SelectionHandleController;
-};
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
-
-// EXTERNAL INCLUDES
-#include <memory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-namespace
-{
-/**
- * @brief Adds a new font description run for the selected text.
- *
- * The new font parameters are added after the call to this method.
- *
- * @param[in] eventData The event data pointer.
- * @param[in] logicalModel The logical model where to add the new font description run.
- * @param[out] startOfSelectedText Index to the first selected character.
- * @param[out] lengthOfSelectedText Number of selected characters.
- */
-FontDescriptionRun& UpdateSelectionFontStyleRun(EventData* eventData,
- LogicalModelPtr logicalModel,
- CharacterIndex& startOfSelectedText,
- Length& lengthOfSelectedText)
-{
- const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
-
- // Get start and end position of selection
- startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
- lengthOfSelectedText = (handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition) - startOfSelectedText;
-
- // Add the font run.
- const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
- logicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
-
- FontDescriptionRun& fontDescriptionRun = *(logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
-
- fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
- fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
-
- // Recalculate the selection highlight as the metrics may have changed.
- eventData->mUpdateLeftSelectionPosition = true;
- eventData->mUpdateRightSelectionPosition = true;
- eventData->mUpdateHighlightBox = true;
-
- return fontDescriptionRun;
-}
-
-} // unnamed namespace
-
-void Controller::InputFontHandler::SetInputFontFamily(Controller& controller, const std::string& fontFamily)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.familyName = fontFamily;
- controller.mImpl->mEventData->mInputStyle.isFamilyDefined = true;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- CharacterIndex startOfSelectedText = 0u;
- Length lengthOfSelectedText = 0u;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- // Update a font description run for the selecting state.
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
- controller.mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText);
-
- fontDescriptionRun.familyLength = fontFamily.size();
- fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
- memcpy(fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength);
- fontDescriptionRun.familyDefined = true;
-
- // The memory allocated for the font family name is freed when the font description is removed from the logical model.
-
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
- }
- else
- {
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
- }
-
- // Request to relayout.
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
- VALIDATE_FONTS |
- SHAPE_TEXT |
- GET_GLYPH_METRICS |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER |
- ALIGN);
- controller.mImpl->mRecalculateNaturalSize = true;
- controller.mImpl->RequestRelayout();
-
- // As the font changes, recalculate the handle positions is needed.
- controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateHighlightBox = true;
- controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
- }
- }
-}
-
-const std::string& Controller::InputFontHandler::GetInputFontFamily(const Controller& controller)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- return controller.mImpl->mEventData->mInputStyle.familyName;
- }
-
- // Return the default font's family if there is no EventData.
- return controller.GetDefaultFontFamily();
-}
-
-void Controller::InputFontHandler::SetInputFontWeight(const Controller& controller, FontWeight weight)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.weight = weight;
- controller.mImpl->mEventData->mInputStyle.isWeightDefined = true;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- CharacterIndex startOfSelectedText = 0u;
- Length lengthOfSelectedText = 0u;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- // Update a font description run for the selecting state.
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
- controller.mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText);
-
- fontDescriptionRun.weight = weight;
- fontDescriptionRun.weightDefined = true;
-
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
- }
- else
- {
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
- }
-
- // Request to relayout.
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
- VALIDATE_FONTS |
- SHAPE_TEXT |
- GET_GLYPH_METRICS |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER |
- ALIGN);
- controller.mImpl->mRecalculateNaturalSize = true;
- controller.mImpl->RequestRelayout();
-
- // As the font might change, recalculate the handle positions is needed.
- controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateHighlightBox = true;
- controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
- }
- }
-}
-
-bool Controller::InputFontHandler::IsInputFontWeightDefined(const Controller& controller)
-{
- bool defined = false;
-
- if(NULL != controller.mImpl->mEventData)
- {
- defined = controller.mImpl->mEventData->mInputStyle.isWeightDefined;
- }
-
- return defined;
-}
-
-FontWeight Controller::InputFontHandler::GetInputFontWeight(const Controller& controller)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- return controller.mImpl->mEventData->mInputStyle.weight;
- }
-
- return controller.GetDefaultFontWeight();
-}
-
-void Controller::InputFontHandler::SetInputFontWidth(Controller& controller, FontWidth width)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.width = width;
- controller.mImpl->mEventData->mInputStyle.isWidthDefined = true;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- CharacterIndex startOfSelectedText = 0u;
- Length lengthOfSelectedText = 0u;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- // Update a font description run for the selecting state.
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
- controller.mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText);
-
- fontDescriptionRun.width = width;
- fontDescriptionRun.widthDefined = true;
-
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
- }
- else
- {
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
- }
-
- // Request to relayout.
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
- VALIDATE_FONTS |
- SHAPE_TEXT |
- GET_GLYPH_METRICS |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER |
- ALIGN);
- controller.mImpl->mRecalculateNaturalSize = true;
- controller.mImpl->RequestRelayout();
-
- // As the font might change, recalculate the handle positions is needed.
- controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateHighlightBox = true;
- controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
- }
- }
-}
-
-bool Controller::InputFontHandler::IsInputFontWidthDefined(const Controller& controller)
-{
- bool defined = false;
-
- if(NULL != controller.mImpl->mEventData)
- {
- defined = controller.mImpl->mEventData->mInputStyle.isWidthDefined;
- }
-
- return defined;
-}
-
-FontWidth Controller::InputFontHandler::GetInputFontWidth(const Controller& controller)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- return controller.mImpl->mEventData->mInputStyle.width;
- }
-
- return controller.GetDefaultFontWidth();
-}
-
-void Controller::InputFontHandler::SetInputFontSlant(Controller& controller, FontSlant slant)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.slant = slant;
- controller.mImpl->mEventData->mInputStyle.isSlantDefined = true;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- CharacterIndex startOfSelectedText = 0u;
- Length lengthOfSelectedText = 0u;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- // Update a font description run for the selecting state.
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
- controller.mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText);
-
- fontDescriptionRun.slant = slant;
- fontDescriptionRun.slantDefined = true;
-
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
- }
- else
- {
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
- }
-
- // Request to relayout.
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
- VALIDATE_FONTS |
- SHAPE_TEXT |
- GET_GLYPH_METRICS |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER |
- ALIGN);
- controller.mImpl->mRecalculateNaturalSize = true;
- controller.mImpl->RequestRelayout();
-
- // As the font might change, recalculate the handle positions is needed.
- controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateHighlightBox = true;
- controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
- }
- }
-}
-
-bool Controller::InputFontHandler::IsInputFontSlantDefined(const Controller& controller)
-{
- bool defined = false;
-
- if(NULL != controller.mImpl->mEventData)
- {
- defined = controller.mImpl->mEventData->mInputStyle.isSlantDefined;
- }
-
- return defined;
-}
-
-FontSlant Controller::InputFontHandler::GetInputFontSlant(const Controller& controller)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- return controller.mImpl->mEventData->mInputStyle.slant;
- }
-
- return controller.GetDefaultFontSlant();
-}
-
-void Controller::InputFontHandler::SetInputFontPointSize(Controller& controller, float size)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.size = size;
- controller.mImpl->mEventData->mInputStyle.isSizeDefined = true;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- CharacterIndex startOfSelectedText = 0u;
- Length lengthOfSelectedText = 0u;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- // Update a font description run for the selecting state.
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun(controller.mImpl->mEventData,
- controller.mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText);
-
- fontDescriptionRun.size = static_cast<PointSize26Dot6>(size * controller.mImpl->GetFontSizeScale() * 64.f);
- fontDescriptionRun.sizeDefined = true;
-
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
- }
- else
- {
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
- }
-
- // Request to relayout.
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending |
- VALIDATE_FONTS |
- SHAPE_TEXT |
- GET_GLYPH_METRICS |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER |
- ALIGN);
- controller.mImpl->mRecalculateNaturalSize = true;
- controller.mImpl->RequestRelayout();
-
- // As the font might change, recalculate the handle positions is needed.
- controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
- controller.mImpl->mEventData->mUpdateHighlightBox = true;
- controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
- }
- }
-}
-
-float Controller::InputFontHandler::GetInputFontPointSize(const Controller& controller)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- return controller.mImpl->mEventData->mInputStyle.size;
- }
-
- // Return the default font's point size if there is no EventData.
- return controller.GetDefaultFontSize(Text::Controller::POINT_SIZE);
-}
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
-#include <dali-toolkit/internal/text/text-definitions.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Controller::InputFontHandler
-{
- static void SetInputFontFamily(Controller& controller, const std::string& fontFamily);
- static const std::string& GetInputFontFamily(const Controller& controller);
- static void SetInputFontWeight(const Controller& controller, FontWeight weight);
- static bool IsInputFontWeightDefined(const Controller& controller);
- static FontWeight GetInputFontWeight(const Controller& controller);
- static void SetInputFontWidth(Controller& controller, FontWidth width);
- static bool IsInputFontWidthDefined(const Controller& controller);
- static FontWidth GetInputFontWidth(const Controller& controller);
- static void SetInputFontSlant(Controller& controller, FontSlant slant);
- static bool IsInputFontSlantDefined(const Controller& controller);
- static FontSlant GetInputFontSlant(const Controller& controller);
- static void SetInputFontPointSize(Controller& controller, float size);
- static float GetInputFontPointSize(const Controller& controller);
-};
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-input-properties.h>
-
-// EXTERNAL INCLUDES
-//#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
-//#include <dali/devel-api/adaptor-framework/window-devel.h>
-//#include <dali/integration-api/debug.h>
-#include <memory.h>
-#include <cmath>
-#include <limits>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
-#include <dali-toolkit/internal/text/text-controller-event-handler.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
-#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
-#include <dali-toolkit/internal/text/text-controller-relayouter.h>
-#include <dali-toolkit/internal/text/text-controller-text-updater.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-
-namespace
-{
-const std::string EMPTY_STRING("");
-}
-
-namespace Dali::Toolkit::Text
-{
-
-void Controller::InputProperties::SetInputColor(Controller& controller, const Vector4& color)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.textColor = color;
- controller.mImpl->mEventData->mInputStyle.isDefaultColor = false;
-
- if(EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState)
- {
- if(EventData::SELECTING == controller.mImpl->mEventData->mState)
- {
- const bool handlesCrossed = controller.mImpl->mEventData->mLeftSelectionPosition > controller.mImpl->mEventData->mRightSelectionPosition;
-
- // Get start and end position of selection
- const CharacterIndex startOfSelectedText = handlesCrossed ? controller.mImpl->mEventData->mRightSelectionPosition : controller.mImpl->mEventData->mLeftSelectionPosition;
- const Length lengthOfSelectedText = (handlesCrossed ? controller.mImpl->mEventData->mLeftSelectionPosition : controller.mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
-
- // Add the color run.
- const VectorBase::SizeType numberOfRuns = controller.mImpl->mModel->mLogicalModel->mColorRuns.Count();
- controller.mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
-
- ColorRun& colorRun = *(controller.mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
- colorRun.color = color;
- colorRun.characterRun.characterIndex = startOfSelectedText;
- colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
-
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
- }
- else
- {
- controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
- controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
- }
-
- // Request to relayout.
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending | COLOR);
- controller.mImpl->RequestRelayout();
- }
- }
-}
-
-const Vector4& Controller::InputProperties::GetInputColor(const Controller& controller)
-{
- // Return event text input color if we have it, otherwise just return the default text's color
- return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.textColor : controller.mImpl->mTextColor;
-}
-
-void Controller::InputProperties::SetInputLineSpacing(Controller& controller, float lineSpacing)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
- controller.mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
- }
-}
-
-float Controller::InputProperties::GetInputLineSpacing(const Controller& controller)
-{
- return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.lineSpacing : 0.0f;
-}
-
-void Controller::InputProperties::SetInputShadowProperties(Controller& controller, const std::string& shadowProperties)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
- }
-}
-
-const std::string& Controller::InputProperties::GetInputShadowProperties(const Controller& controller)
-{
- return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.shadowProperties : EMPTY_STRING;
-}
-
-void Controller::InputProperties::SetInputUnderlineProperties(Controller& controller, const std::string& underlineProperties)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
- }
-}
-
-const std::string& Controller::InputProperties::GetInputUnderlineProperties(const Controller& controller)
-{
- return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.underlineProperties : EMPTY_STRING;
-}
-
-void Controller::InputProperties::SetInputEmbossProperties(Controller& controller, const std::string& embossProperties)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
- }
-}
-
-const std::string& Controller::InputProperties::GetInputEmbossProperties(const Controller& controller)
-{
- return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.embossProperties : controller.GetDefaultEmbossProperties();
-}
-
-void Controller::InputProperties::SetInputOutlineProperties(Controller& controller, const std::string& outlineProperties)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
- }
-}
-
-const std::string& Controller::InputProperties::GetInputOutlineProperties(const Controller& controller)
-{
- return controller.mImpl->mEventData ? controller.mImpl->mEventData->mInputStyle.outlineProperties : controller.GetDefaultOutlineProperties();
-}
-
-void Controller::InputProperties::SetInputModePassword(Controller& controller, bool passwordInput)
-{
- if(controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mPasswordInput = passwordInput;
- }
-}
-
-bool Controller::InputProperties::IsInputModePassword(Controller& controller)
-{
- return controller.mImpl->mEventData && controller.mImpl->mEventData->mPasswordInput;
-}
-
-} // namespace Dali::Toolkit::Text
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_PROPERTIES_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_PROPERTIES_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/input-method-context.h>
-#include <dali/public-api/events/gesture.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
-//#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
-//#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
-//#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
-//#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-//#include <dali-toolkit/internal/text/hidden-text.h>
-//#include <dali-toolkit/internal/text/input-filter.h>
-//#include <dali-toolkit/internal/text/layouts/layout-engine.h>
-//#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
-//#include <dali-toolkit/internal/text/text-model-interface.h>
-//#include <dali-toolkit/internal/text/text-selectable-control-interface.h>
-//#include <dali-toolkit/public-api/text/text-enumerations.h>
-
-namespace Dali::Toolkit::Text
-{
-struct Controller::InputProperties
-{
- static void SetInputColor(Controller& controller, const Vector4& color);
-
- static const Vector4& GetInputColor(const Controller& controller);
-
- static void SetInputLineSpacing(Controller& controller, float lineSpacing);
-
- static float GetInputLineSpacing(const Controller& controller);
-
- static void SetInputShadowProperties(Controller& controller, const std::string& shadowProperties);
-
- static const std::string& GetInputShadowProperties(const Controller& controller);
-
- static void SetInputUnderlineProperties(Controller& controller, const std::string& underlineProperties);
-
- static const std::string& GetInputUnderlineProperties(const Controller& controller);
-
- static void SetInputEmbossProperties(Controller& controller, const std::string& embossProperties);
-
- static const std::string& GetInputEmbossProperties(const Controller& controller);
-
- static void SetInputOutlineProperties(Controller& controller, const std::string& outlineProperties);
-
- static const std::string& GetInputOutlineProperties(const Controller& controller);
-
- static void SetInputModePassword(Controller& controller, bool passwordInput);
-
- static bool IsInputModePassword(Controller& controller);
-};
-
-
-} // namespace Dali::Toolkit::Text
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_PROPERTIES_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-font-style.h>
-#include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-const std::string EMPTY_STRING("");
-
-const char* const PLACEHOLDER_TEXT = "text";
-const char* const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
-const char* const PLACEHOLDER_COLOR = "color";
-const char* const PLACEHOLDER_FONT_FAMILY = "fontFamily";
-const char* const PLACEHOLDER_FONT_STYLE = "fontStyle";
-const char* const PLACEHOLDER_POINT_SIZE = "pointSize";
-const char* const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
-const char* const PLACEHOLDER_ELLIPSIS = "ellipsis";
-
-} // namespace
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled)
-{
- controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
- controller.mImpl->mEventData->mPlaceholderEllipsisFlag = true;
-
- // Update placeholder if there is no text
- if(controller.mImpl->IsShowingPlaceholderText() ||
- (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
- {
- ShowPlaceholderText(*controller.mImpl);
- }
-}
-
-bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller)
-{
- return controller.mImpl->mEventData->mIsPlaceholderElideEnabled;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- if(PLACEHOLDER_TYPE_INACTIVE == type)
- {
- controller.mImpl->mEventData->mPlaceholderTextInactive = text;
- }
- else
- {
- controller.mImpl->mEventData->mPlaceholderTextActive = text;
- }
-
- // Update placeholder if there is no text
- if(controller.mImpl->IsShowingPlaceholderText() ||
- (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
- {
- ShowPlaceholderText(*controller.mImpl);
- }
- }
-}
-
-void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- if(PLACEHOLDER_TYPE_INACTIVE == type)
- {
- text = controller.mImpl->mEventData->mPlaceholderTextInactive;
- }
- else
- {
- text = controller.mImpl->mEventData->mPlaceholderTextActive;
- }
- }
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- // if mPlaceholderFont is null, create an instance.
- CreatePlaceholderFont(controller);
-
- controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
- controller.mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
- }
-
- return EMPTY_STRING;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- // if mPlaceholderFont is null, create an instance.
- CreatePlaceholderFont(controller);
-
- controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
- controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true;
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->weightDefined;
- }
- return false;
-}
-
-FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
- }
-
- return TextAbstraction::FontWeight::NORMAL;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- // if mPlaceholderFont is null, create an instance.
- CreatePlaceholderFont(controller);
-
- controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
- controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true;
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->widthDefined;
- }
- return false;
-}
-
-FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
- }
-
- return TextAbstraction::FontWidth::NORMAL;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- // if mPlaceholderFont is null, create an instance.
- CreatePlaceholderFont(controller);
-
- controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
- controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true;
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->slantDefined;
- }
- return false;
-}
-
-FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller)
-{
- if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
- {
- return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
- }
-
- return TextAbstraction::FontSlant::NORMAL;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- // if mPlaceholderFont is null, create an instance.
- CreatePlaceholderFont(controller);
-
- switch(type)
- {
- case POINT_SIZE:
- {
- controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
- controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
- controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
- break;
- }
- case PIXEL_SIZE:
- {
- // Point size = Pixel size * 72.f / DPI
- unsigned int horizontalDpi = 0u;
- unsigned int verticalDpi = 0u;
- TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
- fontClient.GetDpi(horizontalDpi, verticalDpi);
-
- controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
- controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
- controller.mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
- break;
- }
- }
-
- controller.mImpl->RequestRelayout();
- }
-}
-
-float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type)
-{
- float value = 0.0f;
- if(NULL != controller.mImpl->mEventData)
- {
- switch(type)
- {
- case POINT_SIZE:
- {
- if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
- {
- value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
- }
- else
- {
- // If the placeholder text font size is not set, then return the default font size.
- value = controller.GetDefaultFontSize(POINT_SIZE);
- }
- break;
- }
- case PIXEL_SIZE:
- {
- if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
- {
- // Pixel size = Point size * DPI / 72.f
- unsigned int horizontalDpi = 0u;
- unsigned int verticalDpi = 0u;
- TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
- fontClient.GetDpi(horizontalDpi, verticalDpi);
-
- value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
- }
- else
- {
- // If the placeholder text font size is not set, then return the default font size.
- value = controller.GetDefaultFontSize(PIXEL_SIZE);
- }
- break;
- }
- }
- return value;
- }
-
- return value;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- controller.mImpl->mEventData->mPlaceholderTextColor = textColor;
- }
-
- if(controller.mImpl->IsShowingPlaceholderText())
- {
- controller.mImpl->mModel->mVisualModel->SetTextColor(textColor);
- controller.mImpl->mModel->mLogicalModel->mColorRuns.Clear();
- controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending | COLOR);
- controller.mImpl->RequestRelayout();
- }
-}
-
-const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- return controller.mImpl->mEventData->mPlaceholderTextColor;
- }
-
- return Color::BLACK;
-}
-
-void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map)
-{
- const Property::Map::SizeType count = map.Count();
-
- for(Property::Map::SizeType position = 0; position < count; ++position)
- {
- KeyValuePair keyValue = map.GetKeyValue(position);
- Property::Key& key = keyValue.first;
- Property::Value& value = keyValue.second;
-
- if(key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT)
- {
- std::string text = "";
- value.Get(text);
- SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text);
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED)
- {
- std::string text = "";
- value.Get(text);
- SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text);
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR)
- {
- Vector4 textColor;
- value.Get(textColor);
- if(GetPlaceholderTextColor(controller) != textColor)
- {
- SetPlaceholderTextColor(controller, textColor);
- }
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY)
- {
- std::string fontFamily = "";
- value.Get(fontFamily);
- SetPlaceholderFontFamily(controller, fontFamily);
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE)
- {
- SetFontStyleProperty(&controller, value, Text::FontStyle::PLACEHOLDER);
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE)
- {
- float pointSize;
- value.Get(pointSize);
- if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize))
- {
- SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE);
- }
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE)
- {
- float pixelSize;
- value.Get(pixelSize);
- if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize))
- {
- SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE);
- }
- }
- else if(key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS)
- {
- bool ellipsis;
- value.Get(ellipsis);
- SetPlaceholderTextElideEnabled(controller, ellipsis);
- }
- }
-}
-
-void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map)
-{
- if(NULL != controller.mImpl->mEventData)
- {
- if(!controller.mImpl->mEventData->mPlaceholderTextActive.empty())
- {
- map[Text::PlaceHolder::Property::TEXT_FOCUSED] = controller.mImpl->mEventData->mPlaceholderTextActive;
- }
- if(!controller.mImpl->mEventData->mPlaceholderTextInactive.empty())
- {
- map[Text::PlaceHolder::Property::TEXT] = controller.mImpl->mEventData->mPlaceholderTextInactive;
- }
-
- map[Text::PlaceHolder::Property::COLOR] = controller.mImpl->mEventData->mPlaceholderTextColor;
- map[Text::PlaceHolder::Property::FONT_FAMILY] = GetPlaceholderFontFamily(controller);
-
- Property::Value fontStyleMapGet;
- GetFontStyleProperty(&controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER);
- map[Text::PlaceHolder::Property::FONT_STYLE] = fontStyleMapGet;
-
- // Choose font size : POINT_SIZE or PIXEL_SIZE
- if(!controller.mImpl->mEventData->mIsPlaceholderPixelSize)
- {
- map[Text::PlaceHolder::Property::POINT_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE);
- }
- else
- {
- map[Text::PlaceHolder::Property::PIXEL_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE);
- }
-
- if(controller.mImpl->mEventData->mPlaceholderEllipsisFlag)
- {
- map[Text::PlaceHolder::Property::ELLIPSIS] = IsPlaceholderTextElideEnabled(controller);
- }
- }
-}
-
-void Controller::PlaceholderHandler::ShowPlaceholderText(Controller::Impl& impl)
-{
- if(impl.IsPlaceholderAvailable())
- {
- EventData*& eventData = impl.mEventData;
- DALI_ASSERT_DEBUG(eventData && "No placeholder text available");
-
- if(NULL == eventData)
- {
- return;
- }
-
- eventData->mIsShowingPlaceholderText = true;
-
- // Disable handles when showing place-holder text
- DecoratorPtr& decorator = eventData->mDecorator;
- decorator->SetHandleActive(GRAB_HANDLE, false);
- decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
- decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-
- const char* text(NULL);
- size_t size(0);
-
- // TODO - Switch Placeholder text when changing state
- std::string& placeholderTextActive = eventData->mPlaceholderTextActive;
- if((EventData::INACTIVE != eventData->mState) &&
- (0u != placeholderTextActive.c_str()))
- {
- text = placeholderTextActive.c_str();
- size = placeholderTextActive.size();
- }
- else
- {
- std::string& placeholderTextInactive = eventData->mPlaceholderTextInactive;
- text = placeholderTextInactive.c_str();
- size = placeholderTextInactive.size();
- }
-
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
- textUpdateInfo.mCharacterIndex = 0u;
- textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
-
- // Reset model for showing placeholder.
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
- logicalModel->mText.Clear();
- model->mVisualModel->SetTextColor(eventData->mPlaceholderTextColor);
-
- // Convert text into UTF-32
- Vector<Character>& utf32Characters = logicalModel->mText;
- utf32Characters.Resize(size);
-
- // This is a bit horrible but std::string returns a (signed) char*
- const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
-
- // Transform a text array encoded in utf8 into an array encoded in utf32.
- // It returns the actual number of characters.
- const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
- utf32Characters.Resize(characterCount);
-
- // The characters to be added.
- textUpdateInfo.mNumberOfCharactersToAdd = characterCount;
-
- // Reset the cursor position
- eventData->mPrimaryCursorPosition = 0;
-
- // The natural size needs to be re-calculated.
- impl.mRecalculateNaturalSize = true;
-
- // The text direction needs to be updated.
- impl.mUpdateTextDirection = true;
-
- // Apply modifications to the model
- impl.mOperationsPending = ALL_OPERATIONS;
-
- // Update the rest of the model during size negotiation
- impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
- }
-}
-
-void Controller::PlaceholderHandler::CreatePlaceholderFont(Controller& controller)
-{
- if(nullptr == controller.mImpl->mEventData->mPlaceholderFont)
- {
- controller.mImpl->mEventData->mPlaceholderFont = std::unique_ptr<FontDefaults>(new FontDefaults());
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/math/vector4.h>
-#include <dali/public-api/object/property-map.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
-#include <dali-toolkit/internal/text/text-definitions.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-struct Controller::PlaceholderHandler
-{
- static void SetPlaceholderTextElideEnabled(Controller& controller, bool enabled);
- static bool IsPlaceholderTextElideEnabled(const Controller& controller);
- static void SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text);
- static void GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text);
- static void SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily);
- static const std::string& GetPlaceholderFontFamily(const Controller& controller);
- static void SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight);
- static bool IsPlaceholderTextFontWeightDefined(const Controller& controller);
- static FontWeight GetPlaceholderTextFontWeight(const Controller& controller);
- static void SetPlaceholderTextFontWidth(Controller& controller, FontWidth width);
- static bool IsPlaceholderTextFontWidthDefined(const Controller& controller);
- static FontWidth GetPlaceholderTextFontWidth(const Controller& controller);
- static void SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant);
- static bool IsPlaceholderTextFontSlantDefined(const Controller& controller);
- static FontSlant GetPlaceholderTextFontSlant(const Controller& controller);
- static void SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type);
- static float GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type);
- static void SetPlaceholderTextColor(Controller& controller, const Vector4& textColor);
- static const Vector4& GetPlaceholderTextColor(const Controller& controller);
- static void SetPlaceholderProperty(Controller& controller, const Property::Map& map);
- static void GetPlaceholderProperty(Controller& controller, Property::Map& map);
- static void ShowPlaceholderText(Controller::Impl& impl);
- static void CreatePlaceholderFont(Controller& controller);
-};
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-relayouter.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <limits>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
-#include <dali-toolkit/internal/text/text-controller-event-handler.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
-
-float ConvertToEven(float value)
-{
- int intValue(static_cast<int>(value));
- return static_cast<float>(intValue + (intValue & 1));
-}
-
-} // namespace
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->CalculateLayoutSizeOnRequiredControllerSize\n");
- Size calculatedLayoutSize;
-
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
-
- // Operations that can be done only once until the text changes.
- const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
- GET_SCRIPTS |
- VALIDATE_FONTS |
- GET_LINE_BREAKS |
- BIDI_INFO |
- SHAPE_TEXT |
- GET_GLYPH_METRICS);
-
- const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT | ALIGN | REORDER);
-
- // Set the update info to relayout the whole text.
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
- if((0 == textUpdateInfo.mNumberOfCharactersToAdd) &&
- (0 == textUpdateInfo.mPreviousNumberOfCharacters) &&
- ((visualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (visualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
- {
- textUpdateInfo.mNumberOfCharactersToAdd = model->mLogicalModel->mText.Count();
- }
- textUpdateInfo.mParagraphCharacterIndex = 0u;
- textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
-
- // Get a reference to the pending operations member
- OperationsMask& operationsPending = impl.mOperationsPending;
-
- // Store the actual control's size to restore later.
- const Size actualControlSize = visualModel->mControlSize;
-
- // Whether the text control is editable
- const bool isEditable = NULL != impl.mEventData;
-
- if(!isEditable)
- {
- impl.UpdateModel(onlyOnceOperations);
-
- // Layout the text for the new width.
- operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask);
-
- DoRelayout(impl,
- requestedControllerSize,
- static_cast<OperationsMask>(onlyOnceOperations | requestedOperationsMask),
- calculatedLayoutSize);
-
- textUpdateInfo.Clear();
- textUpdateInfo.mClearAll = true;
-
- // Do not do again the only once operations.
- operationsPending = static_cast<OperationsMask>(operationsPending & ~onlyOnceOperations);
- }
- else
- {
- // This is to keep Index to the first character to be updated.
- // Then restore it after calling Clear method.
- auto updateInfoCharIndexBackup = textUpdateInfo.mCharacterIndex;
-
- // Layout the text for the new width.
- // Apply the pending operations, requested operations and the only once operations.
- // Then remove onlyOnceOperations
- operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask | onlyOnceOperations);
-
- // Make sure the model is up-to-date before layouting
- impl.UpdateModel(static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE));
-
- DoRelayout(impl,
- requestedControllerSize,
- static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE),
- calculatedLayoutSize);
-
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
-
- //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel,
- //TODO: then calculate GlyphPositions. Lines, Size, Layout for Natural-Size
- //TODO: and utilize the values in OperationsPending and TextUpdateInfo without changing the original one.
- //TODO: Also it will improve performance because there is no need todo FullRelyout on the next need for layouting.
-
- // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
- // By this no need to take backup and restore it.
- textUpdateInfo.mFullRelayoutNeeded = true;
-
- // Restore mCharacterIndex. Because "Clear" set it to the maximum integer.
- // The "CalculateTextUpdateIndices" does not work proprely because the mCharacterIndex will be greater than mPreviousNumberOfCharacters.
- // Which apply an assumption to update only the last paragraph. That could cause many of out of index crashes.
- textUpdateInfo.mCharacterIndex = updateInfoCharIndexBackup;
- }
-
- // Do the size related operations again.
- operationsPending = static_cast<OperationsMask>(operationsPending | sizeOperations);
-
- // Restore the actual control's size.
- visualModel->mControlSize = actualControlSize;
-
- return calculatedLayoutSize;
-}
-
-Vector3 Controller::Relayouter::GetNaturalSize(Controller& controller)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
- Vector3 naturalSizeVec3;
-
- // Make sure the model is up-to-date before layouting
- EventHandler::ProcessModifyEvents(controller);
-
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
-
- if(impl.mRecalculateNaturalSize)
- {
- Size naturalSize;
-
- // Layout the text for the new width.
- OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT | REORDER);
- Size sizeMaxWidthAndMaxHeight = Size(MAX_FLOAT, MAX_FLOAT);
-
- naturalSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeMaxWidthAndMaxHeight, requestedOperationsMask);
-
- // Stores the natural size to avoid recalculate it again
- // unless the text/style changes.
- visualModel->SetNaturalSize(naturalSize);
- naturalSizeVec3 = naturalSize;
-
- impl.mRecalculateNaturalSize = false;
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSizeVec3.x, naturalSizeVec3.y, naturalSizeVec3.z);
- }
- else
- {
- naturalSizeVec3 = visualModel->GetNaturalSize();
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSizeVec3.x, naturalSizeVec3.y, naturalSizeVec3.z);
- }
-
- naturalSizeVec3.x = ConvertToEven(naturalSizeVec3.x);
- naturalSizeVec3.y = ConvertToEven(naturalSizeVec3.y);
-
- return naturalSizeVec3;
-}
-
-bool Controller::Relayouter::CheckForTextFit(Controller& controller, float pointSize, const Size& layoutSize)
-{
- Size textSize;
- Controller::Impl& impl = *controller.mImpl;
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
- impl.mFontDefaults->mFitPointSize = pointSize;
- impl.mFontDefaults->sizeDefined = true;
- impl.ClearFontData();
-
- // Operations that can be done only once until the text changes.
- const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
- GET_SCRIPTS |
- VALIDATE_FONTS |
- GET_LINE_BREAKS |
- BIDI_INFO |
- SHAPE_TEXT |
- GET_GLYPH_METRICS);
-
- textUpdateInfo.mParagraphCharacterIndex = 0u;
- textUpdateInfo.mRequestedNumberOfCharacters = impl.mModel->mLogicalModel->mText.Count();
-
- // Make sure the model is up-to-date before layouting
- impl.UpdateModel(onlyOnceOperations);
-
- DoRelayout(impl,
- Size(layoutSize.width, MAX_FLOAT),
- static_cast<OperationsMask>(onlyOnceOperations | LAYOUT),
- textSize);
-
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
- textUpdateInfo.mClearAll = true;
-
- if(textSize.width > layoutSize.width || textSize.height > layoutSize.height)
- {
- return false;
- }
- return true;
-}
-
-void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const Size& layoutSize)
-{
- Controller::Impl& impl = *controller.mImpl;
-
- const OperationsMask operations = impl.mOperationsPending;
- if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || impl.mTextFitContentSize != layoutSize)
- {
- ModelPtr& model = impl.mModel;
-
- bool actualellipsis = model->mElideEnabled;
- float minPointSize = impl.mTextFitMinSize;
- float maxPointSize = impl.mTextFitMaxSize;
- float pointInterval = impl.mTextFitStepSize;
- float currentFitPointSize = impl.mFontDefaults->mFitPointSize;
-
- model->mElideEnabled = false;
- Vector<float> pointSizeArray;
-
- // check zero value
- if(pointInterval < 1.f)
- {
- impl.mTextFitStepSize = pointInterval = 1.0f;
- }
-
- pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
-
- for(float i = minPointSize; i < maxPointSize; i += pointInterval)
- {
- pointSizeArray.PushBack(i);
- }
-
- pointSizeArray.PushBack(maxPointSize);
-
- int bestSizeIndex = 0;
- int min = bestSizeIndex + 1;
- int max = pointSizeArray.Size() - 1;
- while(min <= max)
- {
- int destI = (min + max) / 2;
-
- if(CheckForTextFit(controller, pointSizeArray[destI], layoutSize))
- {
- bestSizeIndex = min;
- min = destI + 1;
- }
- else
- {
- max = destI - 1;
- bestSizeIndex = max;
- }
- }
-
- model->mElideEnabled = actualellipsis;
- if(currentFitPointSize != pointSizeArray[bestSizeIndex])
- {
- impl.mTextFitChanged = true;
- }
- impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
- impl.mFontDefaults->sizeDefined = true;
- impl.ClearFontData();
- }
-}
-
-float Controller::Relayouter::GetHeightForWidth(Controller& controller, float width)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", &controller, width);
-
- // Make sure the model is up-to-date before layouting
- EventHandler::ProcessModifyEvents(controller);
-
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
-
- Size layoutSize;
-
- if(fabsf(width - visualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
- textUpdateInfo.mFullRelayoutNeeded ||
- textUpdateInfo.mClearAll)
- {
- // Layout the text for the new width.
- OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT);
- Size sizeRequestedWidthAndMaxHeight = Size(width, MAX_FLOAT);
-
- layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask);
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
- }
- else
- {
- layoutSize = visualModel->GetLayoutSize();
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height);
- }
-
- return layoutSize.height;
-}
-
-Controller::UpdateTextType Controller::Relayouter::Relayout(Controller& controller, const Size& size, Dali::LayoutDirection::Type layoutDirection)
-{
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", &controller, size.width, size.height, impl.mIsAutoScrollEnabled ? "true" : "false");
-
- UpdateTextType updateTextType = NONE_UPDATED;
-
- if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
- {
- if(0u != visualModel->mGlyphPositions.Count())
- {
- visualModel->mGlyphPositions.Clear();
- updateTextType = MODEL_UPDATED;
- }
-
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
-
- // Not worth to relayout if width or height is equal to zero.
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n");
-
- return updateTextType;
- }
-
- // Whether a new size has been set.
- const bool newSize = (size != visualModel->mControlSize);
-
- // Get a reference to the pending operations member
- OperationsMask& operationsPending = impl.mOperationsPending;
-
- if(newSize)
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", visualModel->mControlSize.width, visualModel->mControlSize.height);
-
- if((0 == textUpdateInfo.mNumberOfCharactersToAdd) &&
- (0 == textUpdateInfo.mPreviousNumberOfCharacters) &&
- ((visualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (visualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
- {
- textUpdateInfo.mNumberOfCharactersToAdd = model->mLogicalModel->mText.Count();
- }
-
- // Layout operations that need to be done if the size changes.
- operationsPending = static_cast<OperationsMask>(operationsPending |
- LAYOUT |
- ALIGN |
- UPDATE_LAYOUT_SIZE |
- REORDER);
- // Set the update info to relayout the whole text.
- textUpdateInfo.mFullRelayoutNeeded = true;
- textUpdateInfo.mCharacterIndex = 0u;
-
- // Store the size used to layout the text.
- visualModel->mControlSize = size;
- }
-
- // Whether there are modify events.
- if(0u != impl.mModifyEvents.Count())
- {
- // Style operations that need to be done if the text is modified.
- operationsPending = static_cast<OperationsMask>(operationsPending | COLOR);
- }
-
- // Set the update info to elide the text.
- if(model->mElideEnabled ||
- ((NULL != impl.mEventData) && impl.mEventData->mIsPlaceholderElideEnabled))
- {
- // Update Text layout for applying elided
- operationsPending = static_cast<OperationsMask>(operationsPending |
- ALIGN |
- LAYOUT |
- UPDATE_LAYOUT_SIZE |
- REORDER);
- textUpdateInfo.mFullRelayoutNeeded = true;
- textUpdateInfo.mCharacterIndex = 0u;
- }
-
- bool layoutDirectionChanged = false;
- if(impl.mLayoutDirection != layoutDirection)
- {
- // Flag to indicate that the layout direction has changed.
- layoutDirectionChanged = true;
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.mClearAll = true;
- // Apply modifications to the model
- // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
- operationsPending = static_cast<OperationsMask>(operationsPending |
- GET_GLYPH_METRICS |
- SHAPE_TEXT |
- UPDATE_DIRECTION |
- ALIGN |
- LAYOUT |
- BIDI_INFO |
- REORDER);
- impl.mLayoutDirection = layoutDirection;
- }
-
- // Make sure the model is up-to-date before layouting.
- EventHandler::ProcessModifyEvents(controller);
- bool updated = impl.UpdateModel(operationsPending);
-
- // Layout the text.
- Size layoutSize;
- updated = DoRelayout(impl, size, operationsPending, layoutSize) || updated;
-
- if(updated)
- {
- updateTextType = MODEL_UPDATED;
- }
-
- // Do not re-do any operation until something changes.
- operationsPending = NO_OPERATION;
- model->mScrollPositionLast = model->mScrollPosition;
-
- // Whether the text control is editable
- const bool isEditable = NULL != impl.mEventData;
-
- // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
- Vector2 offset;
- if(newSize && isEditable)
- {
- offset = model->mScrollPosition;
- }
-
- if(!isEditable || !controller.IsMultiLineEnabled())
- {
- // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
- CalculateVerticalOffset(impl, size);
- }
- else // TextEditor
- {
- // If layoutSize is bigger than size, vertical align has no meaning.
- if(layoutSize.y < size.y)
- {
- CalculateVerticalOffset(impl, size);
- if(impl.mEventData)
- {
- impl.mEventData->mScrollAfterDelete = false;
- }
- }
- }
-
- if(isEditable)
- {
- if(newSize || layoutDirectionChanged)
- {
- // If there is a new size or layout direction is changed, the scroll position needs to be clamped.
- impl.ClampHorizontalScroll(layoutSize);
-
- // Update the decorator's positions is needed if there is a new size.
- impl.mEventData->mDecorator->UpdatePositions(model->mScrollPosition - offset);
-
- // All decorator elements need to be updated.
- if(EventData::IsEditingState(impl.mEventData->mState))
- {
- impl.mEventData->mScrollAfterUpdatePosition = true;
- impl.mEventData->mUpdateCursorPosition = true;
- impl.mEventData->mUpdateGrabHandlePosition = true;
- }
- else if(impl.mEventData->mState == EventData::SELECTING)
- {
- impl.mEventData->mUpdateHighlightBox = true;
- }
- }
-
- // Move the cursor, grab handle etc.
- if(impl.ProcessInputEvents())
- {
- updateTextType = static_cast<UpdateTextType>(updateTextType | DECORATOR_UPDATED);
- }
- }
-
- // Clear the update info. This info will be set the next time the text is updated.
- textUpdateInfo.Clear();
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout\n");
-
- return updateTextType;
-}
-
-bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size, OperationsMask operationsRequired, Size& layoutSize)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayouter::DoRelayout %p size %f,%f\n", &impl, size.width, size.height);
- bool viewUpdated(false);
-
- // Calculate the operations to be done.
- const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
-
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
- const CharacterIndex startIndex = textUpdateInfo.mParagraphCharacterIndex;
- const Length requestedNumberOfCharacters = textUpdateInfo.mRequestedNumberOfCharacters;
-
- // Get the current layout size.
- VisualModelPtr& visualModel = impl.mModel->mVisualModel;
- layoutSize = visualModel->GetLayoutSize();
-
- if(NO_OPERATION != (LAYOUT & operations))
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
-
- // Some vectors with data needed to layout and reorder may be void
- // after the first time the text has been laid out.
- // Fill the vectors again.
-
- // Calculate the number of glyphs to layout.
- const Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
- const Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
- const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
- const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
-
- const CharacterIndex lastIndex = startIndex + ((requestedNumberOfCharacters > 0u) ? requestedNumberOfCharacters - 1u : 0u);
- const GlyphIndex startGlyphIndex = textUpdateInfo.mStartGlyphIndex;
-
- // Make sure the index is not out of bound
- if(charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
- requestedNumberOfCharacters > charactersToGlyph.Count() ||
- (lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u))
- {
- std::string currentText;
- impl.GetText(currentText);
-
- DALI_LOG_ERROR("Controller::DoRelayout: Attempting to access invalid buffer\n");
- DALI_LOG_ERROR("Current text is: %s\n", currentText.c_str());
- DALI_LOG_ERROR("startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
-
- return false;
- }
-
- const Length numberOfGlyphs = (requestedNumberOfCharacters > 0u) ? *(charactersToGlyphBuffer + lastIndex) + *(glyphsPerCharacterBuffer + lastIndex) - startGlyphIndex : 0u;
- const Length totalNumberOfGlyphs = visualModel->mGlyphs.Count();
-
- if(0u == totalNumberOfGlyphs)
- {
- if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
- {
- visualModel->SetLayoutSize(Size::ZERO);
- }
-
- // Nothing else to do if there is no glyphs.
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n");
- return true;
- }
-
- // Set the layout parameters.
- Layout::Parameters layoutParameters(size, impl.mModel);
-
- // Resize the vector of positions to have the same size than the vector of glyphs.
- Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
- glyphPositions.Resize(totalNumberOfGlyphs);
-
- // Whether the last character is a new paragraph character.
- const Character* const textBuffer = impl.mModel->mLogicalModel->mText.Begin();
- textUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph(*(textBuffer + (impl.mModel->mLogicalModel->mText.Count() - 1u)));
- layoutParameters.isLastNewParagraph = textUpdateInfo.mIsLastCharacterNewParagraph;
-
- // The initial glyph and the number of glyphs to layout.
- layoutParameters.startGlyphIndex = startGlyphIndex;
- layoutParameters.numberOfGlyphs = numberOfGlyphs;
- layoutParameters.startLineIndex = textUpdateInfo.mStartLineIndex;
- layoutParameters.estimatedNumberOfLines = textUpdateInfo.mEstimatedNumberOfLines;
-
- // Update the ellipsis
- bool elideTextEnabled = impl.mModel->mElideEnabled;
- auto ellipsisPosition = impl.mModel->mEllipsisPosition;
-
- if(NULL != impl.mEventData)
- {
- if(impl.mEventData->mPlaceholderEllipsisFlag && impl.IsShowingPlaceholderText())
- {
- elideTextEnabled = impl.mEventData->mIsPlaceholderElideEnabled;
- }
- else if(EventData::INACTIVE != impl.mEventData->mState)
- {
- // Disable ellipsis when editing
- elideTextEnabled = false;
- }
-
- // Reset the scroll position in inactive state
- if(elideTextEnabled && (impl.mEventData->mState == EventData::INACTIVE))
- {
- impl.ResetScrollPosition();
- }
- }
-
- // Update the visual model.
- bool isAutoScrollEnabled = impl.mIsAutoScrollEnabled;
- bool isAutoScrollMaxTextureExceeded = impl.mIsAutoScrollMaxTextureExceeded;
-
- Size newLayoutSize;
- viewUpdated = impl.mLayoutEngine.LayoutText(layoutParameters,
- newLayoutSize,
- elideTextEnabled,
- isAutoScrollEnabled,
- isAutoScrollMaxTextureExceeded,
- ellipsisPosition);
- impl.mIsAutoScrollEnabled = isAutoScrollEnabled;
-
- viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
-
- if(viewUpdated)
- {
- layoutSize = newLayoutSize;
-
- if(NO_OPERATION != (UPDATE_DIRECTION & operations))
- {
- impl.mIsTextDirectionRTL = false;
- }
-
- if((NO_OPERATION != (UPDATE_DIRECTION & operations)) && !visualModel->mLines.Empty())
- {
- impl.mIsTextDirectionRTL = visualModel->mLines[0u].direction;
- }
-
- // Sets the layout size.
- if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
- {
- visualModel->SetLayoutSize(layoutSize);
- }
- } // view updated
- }
-
- if(NO_OPERATION != (ALIGN & operations))
- {
- 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;
-
- // The laid-out lines.
- Vector<LineRun>& lines = visualModel->mLines;
-
- 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,
- alignStartIndex,
- alignRequestedNumberOfCharacters,
- impl.mModel->mHorizontalAlignment,
- lines,
- impl.mModel->mAlignmentOffset,
- impl.mLayoutDirection,
- (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS));
- }
- else
- {
- //Override the controller horizontal-alignment by horizontal-alignment of bounded paragraph.
- const Length& numberOfBoundedParagraphRuns = impl.mModel->GetNumberOfBoundedParagraphRuns();
- const Vector<BoundedParagraphRun>& boundedParagraphRuns = impl.mModel->GetBoundedParagraphRuns();
- const CharacterIndex alignEndIndex = alignStartIndex + alignRequestedNumberOfCharacters - 1u;
-
- 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));
- }
- }
-}
-
-void Controller::Relayouter::CalculateVerticalOffset(Controller::Impl& impl, const Size& controlSize)
-{
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
- Size layoutSize = model->mVisualModel->GetLayoutSize();
- Size oldLayoutSize = layoutSize;
- float offsetY = 0.f;
- bool needRecalc = false;
- float defaultFontLineHeight = impl.GetDefaultFontLineHeight();
-
- if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
- {
- // Get the line height of the default font.
- layoutSize.height = defaultFontLineHeight;
- }
-
- // Whether the text control is editable
- const bool isEditable = NULL != impl.mEventData;
- if(isEditable && layoutSize.height != defaultFontLineHeight && impl.IsShowingPlaceholderText())
- {
- // This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
- // This situation occurs when the size of placeholder text is different from the default text.
- layoutSize.height = defaultFontLineHeight;
- needRecalc = true;
- }
-
- switch(model->mVerticalAlignment)
- {
- case VerticalAlignment::TOP:
- {
- model->mScrollPosition.y = 0.f;
- offsetY = 0.f;
- break;
- }
- case VerticalAlignment::CENTER:
- {
- model->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
- if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
- break;
- }
- case VerticalAlignment::BOTTOM:
- {
- model->mScrollPosition.y = controlSize.height - layoutSize.height;
- if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
- break;
- }
- }
-
- if(needRecalc)
- {
- // Update glyphPositions according to recalculation.
- const Length positionCount = visualModel->mGlyphPositions.Count();
- Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
- for(Length index = 0u; index < positionCount; index++)
- {
- glyphPositions[index].y += offsetY;
- }
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_RELAYOUTER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_RELAYOUTER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/actors/actor-enumerations.h>
-#include <dali/public-api/math/vector2.h>
-#include <dali/public-api/math/vector3.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-/**
- * Contains all the relayouting related methods for Text::Controller
- */
-struct Controller::Relayouter
-{
- /**
- * @brief Called by the Controller to retrieve the natural size.
- *
- * @param[in] controller A reference to the controller class
- * @return
- */
- static Vector3 GetNaturalSize(Controller& controller);
-
- /**
- * @brief Called by the Controller to check if the text fits.
- *
- * @param[in] controller A reference to the controller class
- * @param[in] pointSize The point size
- * @param[in] layoutSize The layout size
- * @return
- */
- static bool CheckForTextFit(Controller& controller, float pointSize, const Size& layoutSize);
-
- /**
- * @brief Calculates the point size for text for given layout()
- *
- * @param[in] controller A reference to the controller class
- * @param[in] layoutSize The layout size
- */
- static void FitPointSizeforLayout(Controller& controller, const Size& layoutSize);
-
- /**
- * @brief Called by the Controller to get the height for a particular width.
- *
- * @param[in] controller A reference to the controller class
- * @param[in] width The width we want the height for
- * @return
- */
- static float GetHeightForWidth(Controller& controller, float width);
-
- /**
- * @brief Called by the Controller to do the relayout itself.
- *
- * @param[in] controller A reference to the controller class
- * @param[in] size The size to set
- * @param[in] layoutDirection The layout direction
- * @return
- */
- static Controller::UpdateTextType Relayout(Controller& controller, const Size& size, Dali::LayoutDirection::Type layoutDirection);
-
- /**
- * @brief Called by the Controller to do certain operations when relayouting.
- *
- * @param[in] impl A reference to the controller impl class
- * @param[in] size The size to set
- * @param[in] operationsRequired The operations we need to do
- * @param[in/out] layoutSize The Layout size which can be updated depending on the result of the performed operations
- * @return
- */
-
- static bool DoRelayout(Controller::Impl& impl, const Size& size, OperationsMask operationsRequired, Size& layoutSize);
-
- /**
- * @brief Called by the Controller to calculate the veritcal offset give the control size.
- *
- * @param[in] impl A reference to the controller impl class
- * @param[in] controlSize The control size
- */
- static void CalculateVerticalOffset(Controller::Impl& impl, const Size& controlSize);
-
- /**
- * @brief Calculates the layout size of control according to @p requestedControllerSize and @p requestedOperationsMask
- *
- * GetNaturalSize() and GetHeightForWidth() calls this method.
- *
- * @param[in] controller The controller to calcualte size on it.
- * @param[in] requestedControllerSize The requested size of controller to calcualte layout size on it.
- * @param[in] requestedOperationsMask The requested operations-mask to calcualte layout size according to it.
- *
- * @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
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_RELAYOUTER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller-text-updater.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <memory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/characters-helper-functions.h>
-#include <dali-toolkit/internal/text/emoji-helper.h>
-#include <dali-toolkit/internal/text/markup-processor.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-} // namespace
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-void Controller::TextUpdater::SetText(Controller& controller, const std::string& text)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText\n");
-
- Controller::Impl& impl = *controller.mImpl;
-
- // Reset keyboard as text changed
- impl.ResetInputMethodContext();
-
- // Remove the previously set text and style.
- ResetText(controller);
-
- // Remove the style.
- impl.ClearStyleData();
-
- CharacterIndex lastCursorIndex = 0u;
-
- EventData*& eventData = impl.mEventData;
-
- if(nullptr != eventData)
- {
- // If popup shown then hide it by switching to Editing state
- if((EventData::SELECTING == eventData->mState) ||
- (EventData::EDITING_WITH_POPUP == eventData->mState) ||
- (EventData::EDITING_WITH_GRAB_HANDLE == eventData->mState) ||
- (EventData::EDITING_WITH_PASTE_POPUP == eventData->mState))
- {
- if((impl.mSelectableControlInterface != nullptr) && (EventData::SELECTING == eventData->mState))
- {
- impl.mSelectableControlInterface->SelectionChanged(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition, eventData->mPrimaryCursorPosition, eventData->mPrimaryCursorPosition);
- }
-
- impl.ChangeState(EventData::EDITING);
- }
- }
-
- if(!text.empty())
- {
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
- model->mVisualModel->SetTextColor(impl.mTextColor);
-
- MarkupProcessData markupProcessData(logicalModel->mColorRuns,
- logicalModel->mFontDescriptionRuns,
- logicalModel->mEmbeddedItems,
- logicalModel->mAnchors,
- logicalModel->mUnderlinedCharacterRuns,
- logicalModel->mBackgroundColorRuns,
- logicalModel->mStrikethroughCharacterRuns,
- logicalModel->mBoundedParagraphRuns,
- logicalModel->mCharacterSpacingCharacterRuns);
-
- Length textSize = 0u;
- const uint8_t* utf8 = NULL;
- if(impl.mMarkupProcessorEnabled)
- {
- ProcessMarkupString(text, markupProcessData);
- textSize = markupProcessData.markupProcessedText.size();
-
- // This is a bit horrible but std::string returns a (signed) char*
- utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
- }
- else
- {
- textSize = text.size();
-
- // This is a bit horrible but std::string returns a (signed) char*
- utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
- }
-
- // Convert text into UTF-32
- Vector<Character>& utf32Characters = logicalModel->mText;
- utf32Characters.Resize(textSize);
-
- // Transform a text array encoded in utf8 into an array encoded in utf32.
- // It returns the actual number of characters.
- Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
- utf32Characters.Resize(characterCount);
-
- DALI_ASSERT_DEBUG(textSize >= characterCount && "Invalid UTF32 conversion length");
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", &controller, textSize, logicalModel->mText.Count());
-
- // The characters to be added.
- impl.mTextUpdateInfo.mNumberOfCharactersToAdd = logicalModel->mText.Count();
-
- // To reset the cursor position
- lastCursorIndex = characterCount;
-
- // Update the rest of the model during size negotiation
- impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
-
- // The natural size needs to be re-calculated.
- impl.mRecalculateNaturalSize = true;
-
- // The text direction needs to be updated.
- impl.mUpdateTextDirection = true;
-
- // Apply modifications to the model
- impl.mOperationsPending = ALL_OPERATIONS;
- }
- else
- {
- PlaceholderHandler::ShowPlaceholderText(impl);
- }
-
- unsigned int oldCursorPos = (nullptr != eventData ? eventData->mPrimaryCursorPosition : 0);
-
- // Resets the cursor position.
- controller.ResetCursorPosition(lastCursorIndex);
-
- // Scrolls the text to make the cursor visible.
- impl.ResetScrollPosition();
-
- impl.RequestRelayout();
-
- if(nullptr != eventData)
- {
- // Cancel previously queued events
- eventData->mEventQueue.clear();
- }
-
- // Do this last since it provides callbacks into application code.
- if(NULL != impl.mEditableControlInterface)
- {
- impl.mEditableControlInterface->CursorPositionChanged(oldCursorPos, lastCursorIndex);
- impl.mEditableControlInterface->TextChanged(true);
- }
-}
-
-void Controller::TextUpdater::InsertText(Controller& controller, const std::string& text, Controller::InsertType type)
-{
- Controller::Impl& impl = *controller.mImpl;
- EventData*& eventData = impl.mEventData;
-
- DALI_ASSERT_DEBUG(nullptr != eventData && "Unexpected InsertText")
-
- if(NULL == eventData)
- {
- return;
- }
-
- bool removedPrevious = false;
- bool removedSelected = false;
- bool maxLengthReached = false;
- unsigned int oldCursorPos = eventData->mPrimaryCursorPosition;
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n", &controller, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"), eventData->mPrimaryCursorPosition, eventData->mPreEditFlag, eventData->mPreEditStartPosition, eventData->mPreEditLength);
-
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
-
- // TODO: At the moment the underline runs are only for pre-edit.
- model->mVisualModel->mUnderlineRuns.Clear();
-
- // Remove the previous InputMethodContext pre-edit.
- if(eventData->mPreEditFlag && (0u != eventData->mPreEditLength))
- {
- removedPrevious = RemoveText(controller,
- -static_cast<int>(eventData->mPrimaryCursorPosition - eventData->mPreEditStartPosition),
- eventData->mPreEditLength,
- DONT_UPDATE_INPUT_STYLE);
-
- eventData->mPrimaryCursorPosition = eventData->mPreEditStartPosition;
- eventData->mPreEditLength = 0u;
- }
- else
- {
- // Remove the previous Selection.
- removedSelected = RemoveSelectedText(controller);
- }
-
- Vector<Character> utf32Characters;
- Length characterCount = 0u;
-
- if(!text.empty())
- {
- // Convert text into UTF-32
- utf32Characters.Resize(text.size());
-
- // This is a bit horrible but std::string returns a (signed) char*
- const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
-
- // Transform a text array encoded in utf8 into an array encoded in utf32.
- // It returns the actual number of characters.
- characterCount = Utf8ToUtf32(utf8, text.size(), utf32Characters.Begin());
- utf32Characters.Resize(characterCount);
-
- DALI_ASSERT_DEBUG(text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count());
- }
-
- if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
- {
- // The placeholder text is no longer needed
- if(impl.IsShowingPlaceholderText())
- {
- ResetText(controller);
- }
-
- impl.ChangeState(EventData::EDITING);
-
- // Handle the InputMethodContext (predicitive text) state changes
- if(COMMIT == type)
- {
- // InputMethodContext is no longer handling key-events
- impl.ClearPreEditFlag();
- }
- else // PRE_EDIT
- {
- if(!eventData->mPreEditFlag)
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
-
- // Record the start of the pre-edit text
- eventData->mPreEditStartPosition = eventData->mPrimaryCursorPosition;
- }
-
- eventData->mPreEditLength = utf32Characters.Count();
- eventData->mPreEditFlag = true;
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", eventData->mPreEditStartPosition, eventData->mPreEditLength);
- }
-
- const Length numberOfCharactersInModel = logicalModel->mText.Count();
-
- // Restrict new text to fit within Maximum characters setting.
- Length temp_length = (impl.mMaximumNumberOfCharacters > numberOfCharactersInModel ? impl.mMaximumNumberOfCharacters - numberOfCharactersInModel : 0);
- Length maxSizeOfNewText = std::min(temp_length, characterCount);
- maxLengthReached = (characterCount > maxSizeOfNewText);
-
- // The cursor position.
- CharacterIndex& cursorIndex = eventData->mPrimaryCursorPosition;
-
- // Update the text's style.
-
- // Updates the text style runs by adding characters.
- logicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
-
- // Get the character index from the cursor index.
- const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
-
- // Retrieve the text's style for the given index.
- InputStyle style;
- impl.RetrieveDefaultInputStyle(style);
- logicalModel->RetrieveStyle(styleIndex, style);
-
- InputStyle& inputStyle = eventData->mInputStyle;
-
- // Whether to add a new text color run.
- const bool addColorRun = (style.textColor != inputStyle.textColor) && !inputStyle.isDefaultColor;
-
- // Whether to add a new font run.
- const bool addFontNameRun = (style.familyName != inputStyle.familyName) && inputStyle.isFamilyDefined;
- const bool addFontWeightRun = (style.weight != inputStyle.weight) && inputStyle.isWeightDefined;
- const bool addFontWidthRun = (style.width != inputStyle.width) && inputStyle.isWidthDefined;
- const bool addFontSlantRun = (style.slant != inputStyle.slant) && inputStyle.isSlantDefined;
- const bool addFontSizeRun = (style.size != inputStyle.size) && inputStyle.isSizeDefined;
-
- // Add style runs.
- if(addColorRun)
- {
- const VectorBase::SizeType numberOfRuns = logicalModel->mColorRuns.Count();
- logicalModel->mColorRuns.Resize(numberOfRuns + 1u);
-
- ColorRun& colorRun = *(logicalModel->mColorRuns.Begin() + numberOfRuns);
- colorRun.color = inputStyle.textColor;
- colorRun.characterRun.characterIndex = cursorIndex;
- colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
- }
-
- if(addFontNameRun ||
- addFontWeightRun ||
- addFontWidthRun ||
- addFontSlantRun ||
- addFontSizeRun)
- {
- const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
- logicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
-
- FontDescriptionRun& fontDescriptionRun = *(logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
-
- if(addFontNameRun)
- {
- fontDescriptionRun.familyLength = inputStyle.familyName.size();
- fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
- memcpy(fontDescriptionRun.familyName, inputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
- fontDescriptionRun.familyDefined = true;
-
- // The memory allocated for the font family name is freed when the font description is removed from the logical model.
- }
-
- if(addFontWeightRun)
- {
- fontDescriptionRun.weight = inputStyle.weight;
- fontDescriptionRun.weightDefined = true;
- }
-
- if(addFontWidthRun)
- {
- fontDescriptionRun.width = inputStyle.width;
- fontDescriptionRun.widthDefined = true;
- }
-
- if(addFontSlantRun)
- {
- fontDescriptionRun.slant = inputStyle.slant;
- fontDescriptionRun.slantDefined = true;
- }
-
- if(addFontSizeRun)
- {
- fontDescriptionRun.size = static_cast<PointSize26Dot6>(inputStyle.size * impl.GetFontSizeScale() * 64.f);
- fontDescriptionRun.sizeDefined = true;
- }
-
- fontDescriptionRun.characterRun.characterIndex = cursorIndex;
- fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
- }
-
- // Insert at current cursor position.
- Vector<Character>& modifyText = logicalModel->mText;
-
- auto pos = modifyText.End();
- if(cursorIndex < numberOfCharactersInModel)
- {
- pos = modifyText.Begin() + cursorIndex;
- }
- unsigned int realPos = pos - modifyText.Begin();
- modifyText.Insert(pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
-
- if(NULL != impl.mEditableControlInterface)
- {
- impl.mEditableControlInterface->TextInserted(realPos, maxSizeOfNewText, text);
- }
-
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
-
- // Mark the first paragraph to be updated.
- if(Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout())
- {
- textUpdateInfo.mCharacterIndex = 0;
- textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
- textUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
- textUpdateInfo.mClearAll = true;
- }
- else
- {
- textUpdateInfo.mCharacterIndex = std::min(cursorIndex, textUpdateInfo.mCharacterIndex);
- textUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
- }
-
- if(impl.mMarkupProcessorEnabled)
- {
- InsertTextAnchor(controller, maxSizeOfNewText, cursorIndex);
- }
-
- // Update the cursor index.
- cursorIndex += maxSizeOfNewText;
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition);
- }
-
- if((0u == logicalModel->mText.Count()) &&
- impl.IsPlaceholderAvailable())
- {
- // Show place-holder if empty after removing the pre-edit text
- PlaceholderHandler::ShowPlaceholderText(impl);
- eventData->mUpdateCursorPosition = true;
- impl.ClearPreEditFlag();
- }
- else if(removedPrevious ||
- removedSelected ||
- (0 != utf32Characters.Count()))
- {
- // Queue an inserted event
- impl.QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
-
- eventData->mUpdateCursorPosition = true;
- if(removedSelected)
- {
- eventData->mScrollAfterDelete = true;
- }
- else
- {
- eventData->mScrollAfterUpdatePosition = true;
- }
- }
-
- if(nullptr != impl.mEditableControlInterface)
- {
- impl.mEditableControlInterface->CursorPositionChanged(oldCursorPos, eventData->mPrimaryCursorPosition);
- }
-
- if(maxLengthReached)
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", logicalModel->mText.Count());
-
- impl.ResetInputMethodContext();
-
- if(NULL != impl.mEditableControlInterface)
- {
- // Do this last since it provides callbacks into application code
- impl.mEditableControlInterface->MaxLengthReached();
- }
- }
-}
-
-void Controller::TextUpdater::PasteText(Controller& controller, const std::string& stringToPaste)
-{
- InsertText(controller, stringToPaste, Text::Controller::COMMIT);
- Controller::Impl& impl = *controller.mImpl;
- impl.ChangeState(EventData::EDITING);
- impl.RequestRelayout();
-
- if(NULL != impl.mEditableControlInterface)
- {
- // Do this last since it provides callbacks into application code
- impl.mEditableControlInterface->TextChanged(true);
- }
-}
-
-bool Controller::TextUpdater::RemoveText(
- Controller& controller,
- int cursorOffset,
- int numberOfCharacters,
- UpdateInputStyleType type)
-{
- bool removed = false;
- bool removeAll = false;
-
- Controller::Impl& impl = *controller.mImpl;
- EventData*& eventData = impl.mEventData;
-
- if(nullptr == eventData)
- {
- return removed;
- }
-
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
- VisualModelPtr& visualModel = model->mVisualModel;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", &controller, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters);
-
- if(!impl.IsShowingPlaceholderText())
- {
- // Delete at current cursor position
- Vector<Character>& currentText = logicalModel->mText;
- CharacterIndex& previousCursorIndex = eventData->mPrimaryCursorPosition;
-
- CharacterIndex cursorIndex = 0;
-
- // Validate the cursor position & number of characters
- if((static_cast<int>(eventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
- {
- cursorIndex = eventData->mPrimaryCursorPosition + cursorOffset;
- }
-
- //Handle Emoji clustering for cursor handling
- // Deletion case: this is handling the deletion cases when the cursor is before or after Emoji
- // - Before: when use delete key and cursor is before Emoji (cursorOffset = -1)
- // - After: when use backspace key and cursor is after Emoji (cursorOffset = 0)
-
- const Script script = logicalModel->GetScript(cursorIndex);
- if((numberOfCharacters == 1u) &&
- (IsOneOfEmojiScripts(script)))
- {
- //TODO: Use this clustering for Emoji cases only. This needs more testing to generalize to all scripts.
- CharacterRun emojiClusteredCharacters = RetrieveClusteredCharactersOfCharacterIndex(visualModel, logicalModel, cursorIndex);
- Length actualNumberOfCharacters = emojiClusteredCharacters.numberOfCharacters;
-
- //Set cursorIndex at the first characterIndex of clustred Emoji
- cursorIndex = emojiClusteredCharacters.characterIndex;
-
- numberOfCharacters = actualNumberOfCharacters;
- }
-
- if((cursorIndex + numberOfCharacters) > currentText.Count())
- {
- numberOfCharacters = currentText.Count() - cursorIndex;
- }
-
- if((cursorIndex == 0) && (currentText.Count() - numberOfCharacters == 0))
- {
- removeAll = true;
- }
-
- TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
-
- if(eventData->mPreEditFlag || removeAll || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
- ((cursorIndex + numberOfCharacters) <= textUpdateInfo.mPreviousNumberOfCharacters))
- {
- // Mark the paragraphs to be updated.
- if(Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout())
- {
- textUpdateInfo.mCharacterIndex = 0;
- textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
- textUpdateInfo.mNumberOfCharactersToAdd = textUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
- textUpdateInfo.mClearAll = true;
- }
- else
- {
- textUpdateInfo.mCharacterIndex = std::min(cursorIndex, textUpdateInfo.mCharacterIndex);
- textUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
- }
-
- // Update the input style and remove the text's style before removing the text.
-
- if(UPDATE_INPUT_STYLE == type)
- {
- InputStyle& eventDataInputStyle = eventData->mInputStyle;
-
- // Keep a copy of the current input style.
- InputStyle currentInputStyle;
- currentInputStyle.Copy(eventDataInputStyle);
-
- // Set first the default input style.
- impl.RetrieveDefaultInputStyle(eventDataInputStyle);
-
- // Update the input style.
- logicalModel->RetrieveStyle(cursorIndex, eventDataInputStyle);
-
- // Compare if the input style has changed.
- const bool hasInputStyleChanged = !currentInputStyle.Equal(eventDataInputStyle);
-
- if(hasInputStyleChanged)
- {
- const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(eventDataInputStyle);
- // Queue the input style changed signal.
- eventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
- }
- }
-
- // If the number of current text and the number of characters to be deleted are same,
- // it means all texts should be removed and all Preedit variables should be initialized.
- if(removeAll)
- {
- impl.ClearPreEditFlag();
- textUpdateInfo.mNumberOfCharactersToAdd = 0;
- }
-
- // Updates the text style runs by removing characters. Runs with no characters are removed.
- logicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
-
- // Remove the characters.
- Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
- Vector<Character>::Iterator last = first + numberOfCharacters;
-
- if(NULL != impl.mEditableControlInterface)
- {
- std::string utf8;
- Utf32ToUtf8(first, numberOfCharacters, utf8);
- impl.mEditableControlInterface->TextDeleted(cursorIndex, numberOfCharacters, utf8);
- }
-
- currentText.Erase(first, last);
-
- if(impl.mMarkupProcessorEnabled)
- {
- RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
- }
-
- if(nullptr != impl.mEditableControlInterface)
- {
- impl.mEditableControlInterface->CursorPositionChanged(previousCursorIndex, cursorIndex);
- }
-
- // Cursor position retreat
- previousCursorIndex = cursorIndex;
-
- eventData->mScrollAfterDelete = true;
-
- if(EventData::INACTIVE == eventData->mState)
- {
- impl.ChangeState(EventData::EDITING);
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", &controller, numberOfCharacters);
- removeAll = false;
- removed = true;
- }
- }
-
- return removed;
-}
-
-bool Controller::TextUpdater::RemoveSelectedText(Controller& controller)
-{
- bool textRemoved(false);
-
- Controller::Impl& impl = *controller.mImpl;
-
- if(EventData::SELECTING == impl.mEventData->mState)
- {
- std::string removedString;
- uint32_t oldSelStart = impl.mEventData->mLeftSelectionPosition;
- uint32_t oldSelEnd = impl.mEventData->mRightSelectionPosition;
-
- impl.RetrieveSelection(removedString, true);
-
- if(!removedString.empty())
- {
- textRemoved = true;
- impl.ChangeState(EventData::EDITING);
-
- if(impl.mMarkupProcessorEnabled)
- {
- int cursorOffset = -1;
- int numberOfCharacters = removedString.length();
- CharacterIndex& cursorIndex = impl.mEventData->mPrimaryCursorPosition;
- CharacterIndex previousCursorIndex = cursorIndex + numberOfCharacters;
-
- RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
- }
-
- if(impl.mSelectableControlInterface != nullptr)
- {
- impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, impl.mEventData->mPrimaryCursorPosition, impl.mEventData->mPrimaryCursorPosition);
- }
- }
- }
-
- return textRemoved;
-}
-
-void Controller::TextUpdater::ResetText(Controller& controller)
-{
- Controller::Impl& impl = *controller.mImpl;
- LogicalModelPtr& logicalModel = impl.mModel->mLogicalModel;
-
- // Reset buffers.
- logicalModel->mText.Clear();
-
- // Reset the embedded images buffer.
- logicalModel->ClearEmbeddedImages();
-
- // Reset the anchors buffer.
- logicalModel->ClearAnchors();
-
- // We have cleared everything including the placeholder-text
- impl.PlaceholderCleared();
-
- impl.mTextUpdateInfo.mCharacterIndex = 0u;
- impl.mTextUpdateInfo.mNumberOfCharactersToRemove = impl.mTextUpdateInfo.mPreviousNumberOfCharacters;
- impl.mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
-
- // Clear any previous text.
- impl.mTextUpdateInfo.mClearAll = true;
-
- // The natural size needs to be re-calculated.
- impl.mRecalculateNaturalSize = true;
-
- // The text direction needs to be updated.
- impl.mUpdateTextDirection = true;
-
- // Apply modifications to the model
- impl.mOperationsPending = ALL_OPERATIONS;
-}
-
-void Controller::TextUpdater::InsertTextAnchor(Controller& controller, int numberOfCharacters, CharacterIndex previousCursorIndex)
-{
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
-
- for(auto& anchor : logicalModel->mAnchors)
- {
- if(anchor.endIndex < previousCursorIndex) // [anchor] CUR
- {
- continue;
- }
- if(anchor.startIndex < previousCursorIndex) // [anCURr]
- {
- anchor.endIndex += numberOfCharacters;
- }
- else // CUR [anchor]
- {
- anchor.startIndex += numberOfCharacters;
- anchor.endIndex += numberOfCharacters;
- }
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::InsertTextAnchor[%p] Anchor[%s] start[%d] end[%d]\n", &controller, anchor.href, anchor.startIndex, anchor.endIndex);
- }
-}
-
-void Controller::TextUpdater::RemoveTextAnchor(Controller& controller, int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex)
-{
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- LogicalModelPtr& logicalModel = model->mLogicalModel;
- Vector<Anchor>::Iterator it = logicalModel->mAnchors.Begin();
-
- while(it != logicalModel->mAnchors.End())
- {
- Anchor& anchor = *it;
-
- if(anchor.endIndex <= previousCursorIndex && cursorOffset == 0) // [anchor] CUR >>
- {
- // Nothing happens.
- }
- else if(anchor.endIndex <= previousCursorIndex && cursorOffset == -1) // [anchor] << CUR
- {
- int endIndex = anchor.endIndex;
- int offset = previousCursorIndex - endIndex;
- int index = endIndex - (numberOfCharacters - offset);
-
- if(index < endIndex)
- {
- endIndex = index;
- }
-
- if((int)anchor.startIndex >= endIndex)
- {
- if(anchor.href)
- {
- delete[] anchor.href;
- }
- it = logicalModel->mAnchors.Erase(it);
- continue;
- }
- else
- {
- anchor.endIndex = endIndex;
- }
- }
- else if(anchor.startIndex >= previousCursorIndex && cursorOffset == -1) // << CUR [anchor]
- {
- anchor.startIndex -= numberOfCharacters;
- anchor.endIndex -= numberOfCharacters;
- }
- else if(anchor.startIndex >= previousCursorIndex && cursorOffset == 0) // CUR >> [anchor]
- {
- int startIndex = anchor.startIndex;
- int endIndex = anchor.endIndex;
- int index = previousCursorIndex + numberOfCharacters - 1;
-
- if(startIndex > index)
- {
- anchor.startIndex -= numberOfCharacters;
- anchor.endIndex -= numberOfCharacters;
- }
- else if(endIndex > index + 1)
- {
- anchor.endIndex -= numberOfCharacters;
- }
- else
- {
- if(anchor.href)
- {
- delete[] anchor.href;
- }
- it = logicalModel->mAnchors.Erase(it);
- continue;
- }
- }
- else if(cursorOffset == -1) // [<< CUR]
- {
- int startIndex = anchor.startIndex;
- int index = previousCursorIndex - numberOfCharacters;
-
- if(startIndex >= index)
- {
- anchor.startIndex = index;
- }
- anchor.endIndex -= numberOfCharacters;
- }
- else if(cursorOffset == 0) // [CUR >>]
- {
- anchor.endIndex -= numberOfCharacters;
- }
- else
- {
- // When this condition is reached, someting is wrong.
- DALI_LOG_ERROR("Controller::RemoveTextAnchor[%p] Invaild state cursorOffset[%d]\n", &controller, cursorOffset);
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveTextAnchor[%p] Anchor[%s] start[%d] end[%d]\n", &controller, anchor.href, anchor.startIndex, anchor.endIndex);
-
- it++;
- }
-}
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_UPDATER_H
-#define DALI_TOOLKIT_TEXT_UPDATER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
-{
-/**
- * @brief Methods that update the text
- */
-struct Controller::TextUpdater
-{
- /// @copydoc Text::Contoller::SetText
- /// @param[in] controller The controller
- static void SetText(Controller& controller, const std::string& text);
-
- /**
- * @brief Called by editable UI controls when key events are received.
- *
- * @param[in] controller The controller
- * @param[in] text The text to insert.
- * @param[in] type Used to distinguish between regular key events and InputMethodContext events.
- */
- static void InsertText(Controller& controller, const std::string& text, Controller::InsertType type);
-
- /// @copydoc Text::EditableControlInterface::PasteText()
- /// @param[in] controller The controller
- static void PasteText(Controller& controller, const std::string& stringToPaste);
-
- /**
- * @brief Remove a given number of characters
- *
- * When predictve text is used the pre-edit text is removed and inserted again with the new characters.
- * The UpdateInputStyleType @type parameter if set to DONT_UPDATE_INPUT_STYLE avoids to update the input
- * style when pre-edit text is removed.
- *
- * @param[in] controller The controller
- * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
- * @param[in] numberOfCharacters The number of characters to delete from the cursorOffset.
- * @param[in] type Whether to update the input style.
- * @return True if the remove was successful.
- */
- static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type);
-
- /**
- * @brief Checks if text is selected and if so removes it.
- * @param[in] controller The controller
- * @return true if text was removed
- */
- static bool RemoveSelectedText(Controller& controller);
-
- /**
- * @brief Used to remove the text included the placeholder text.
- * @param[in] controller The controller
- */
- static void ResetText(Controller& controller);
-
- /**
- * @brief Update anchor position from given number of inserted characters.
- *
- * @param[in] controller The controller
- * @param[in] numberOfCharacters The number of inserted characters.
- * @param[in] previousCursorIndex A cursor position before event occurs.
- */
- static void InsertTextAnchor(Controller& controller, int numberOfCharacters, CharacterIndex previousCursorIndex);
-
- /**
- * @brief Update anchor position from given number of removed characters.
- *
- * @param[in] controller The controller
- * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
- * @param[in] numberOfCharacters The number of removed characters.
- * @param[in] previousCursorIndex A cursor position before event occurs.
- */
- static void RemoveTextAnchor(Controller& controller, int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex);
-};
-
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_UPDATER_H
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/text/text-controller.h>
-
-// EXTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
-#include <dali/devel-api/adaptor-framework/window-devel.h>
-#include <dali/integration-api/debug.h>
-#include <memory.h>
-#include <cmath>
-#include <limits>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
-#include <dali-toolkit/internal/text/text-controller-background-actor.h>
-#include <dali-toolkit/internal/text/text-controller-event-handler.h>
-#include <dali-toolkit/internal/text/text-controller-impl.h>
-#include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
-#include <dali-toolkit/internal/text/text-controller-input-properties.h>
-#include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
-#include <dali-toolkit/internal/text/text-controller-relayouter.h>
-#include <dali-toolkit/internal/text/text-controller-text-updater.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
-#include <dali-toolkit/internal/text/text-geometry.h>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
-#endif
-
-const std::string EMPTY_STRING("");
-
-template<typename Type>
-void EnsureCreated(Type*& object)
-{
- if(!object)
- {
- object = new Type();
- }
-}
-
-template<typename Type>
-void EnsureCreated(std::unique_ptr<Type>& object)
-{
- if(!object)
- {
- object = std::unique_ptr<Type>(new Type());
- }
-}
-
-template<typename Type, typename Arg1>
-void EnsureCreated(Type*& object, Arg1 arg1)
-{
- if(!object)
- {
- object = new Type(arg1);
- }
-}
-
-template<typename Type, typename Arg1, typename Arg2>
-void EnsureCreated(Type*& object, Arg1 arg1, Arg2 arg2)
-{
- if(!object)
- {
- object = new Type(arg1, arg2);
- }
-}
-
-float GetDpi()
-{
- unsigned int horizontalDpi = 0u;
- unsigned int verticalDpi = 0u;
- Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
- fontClient.GetDpi(horizontalDpi, verticalDpi);
- return static_cast<float>(horizontalDpi);
-}
-
-float ConvertPixelToPoint(float pixel)
-{
- return pixel * 72.0f / GetDpi();
-}
-
-float ConvertPointToPixel(float point)
-{
- // Pixel size = Point size * DPI / 72.f
- return point * GetDpi() / 72.0f;
-}
-
-void UpdateCursorPosition(Dali::Toolkit::Text::EventData* eventData)
-{
- if(eventData && Dali::Toolkit::Text::EventData::IsEditingState(eventData->mState))
- {
- // Update the cursor position if it's in editing mode
- eventData->mDecoratorUpdated = true;
- eventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
- }
-}
-
-} // namespace
-
-namespace Dali::Toolkit::Text
-{
-void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
-{
- if(!decorator)
- {
- delete mImpl->mEventData;
- mImpl->mEventData = NULL;
-
- // Nothing else to do.
- return;
- }
-
- EnsureCreated(mImpl->mEventData, decorator, inputMethodContext);
-}
-
-void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
-{
- // Metrics for bitmap & vector based glyphs are different
- mImpl->mMetrics->SetGlyphType(glyphType);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-void Controller::SetMarkupProcessorEnabled(bool enable)
-{
- if(enable != mImpl->mMarkupProcessorEnabled)
- {
- //If Text was already set, call the SetText again for enabling or disabling markup
- mImpl->mMarkupProcessorEnabled = enable;
- std::string text;
- GetText(text);
- SetText(text);
- }
-
- mImpl->mModel->mVisualModel->SetMarkupProcessorEnabled(enable);
-}
-
-bool Controller::IsMarkupProcessorEnabled() const
-{
- return mImpl->mMarkupProcessorEnabled;
-}
-
-bool Controller::HasAnchors() const
-{
- return (mImpl->mMarkupProcessorEnabled && mImpl->mModel->mLogicalModel->mAnchors.Count() && mImpl->IsShowingRealText());
-}
-
-void Controller::SetAutoScrollEnabled(bool enable)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable) ? "true" : "false", (mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) ? "true" : "false", this);
- mImpl->SetAutoScrollEnabled(enable);
-}
-
-void Controller::SetAutoScrollMaxTextureExceeded(bool exceed)
-{
- mImpl->mIsAutoScrollMaxTextureExceeded = exceed;
-}
-
-bool Controller::IsAutoScrollEnabled() const
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
- return mImpl->mIsAutoScrollEnabled;
-}
-
-CharacterDirection Controller::GetAutoScrollDirection() const
-{
- return mImpl->mIsTextDirectionRTL;
-}
-
-float Controller::GetAutoScrollLineAlignment() const
-{
- float offset = 0.f;
- if(mImpl->mModel->mVisualModel && (0u != mImpl->mModel->mVisualModel->mLines.Count()))
- {
- offset = (*mImpl->mModel->mVisualModel->mLines.Begin()).alignmentOffset;
- }
- return offset;
-}
-
-void Controller::SetHorizontalScrollEnabled(bool enable)
-{
- if(mImpl->mEventData && mImpl->mEventData->mDecorator)
- {
- mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled(enable);
- }
-}
-
-bool Controller::IsHorizontalScrollEnabled() const
-{
- return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
-}
-
-void Controller::SetVerticalScrollEnabled(bool enable)
-{
- if(mImpl->mEventData && mImpl->mEventData->mDecorator)
- {
- mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
- }
-}
-
-bool Controller::IsVerticalScrollEnabled() const
-{
- return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
-}
-
-void Controller::SetSmoothHandlePanEnabled(bool enable)
-{
- if(mImpl->mEventData && mImpl->mEventData->mDecorator)
- {
- mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled(enable);
- }
-}
-
-bool Controller::IsSmoothHandlePanEnabled() const
-{
- return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
-}
-
-void Controller::SetMaximumNumberOfCharacters(Length maxCharacters)
-{
- mImpl->mMaximumNumberOfCharacters = maxCharacters;
-}
-
-int Controller::GetMaximumNumberOfCharacters()
-{
- return mImpl->mMaximumNumberOfCharacters;
-}
-
-void Controller::SetEnableCursorBlink(bool enable)
-{
- mImpl->SetEnableCursorBlink(enable);
-}
-
-bool Controller::GetEnableCursorBlink() const
-{
- return mImpl->mEventData && mImpl->mEventData->mCursorBlinkEnabled;
-}
-
-void Controller::SetMultiLineEnabled(bool enable)
-{
- mImpl->SetMultiLineEnabled(enable);
-}
-
-bool Controller::IsMultiLineEnabled() const
-{
- return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
-}
-
-void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
-{
- mImpl->SetHorizontalAlignment(alignment);
-}
-
-Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
-{
- return mImpl->mModel->mHorizontalAlignment;
-}
-
-void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
-{
- mImpl->SetVerticalAlignment(alignment);
-}
-
-VerticalAlignment::Type Controller::GetVerticalAlignment() const
-{
- return mImpl->mModel->mVerticalAlignment;
-}
-
-bool Controller::IsIgnoreSpacesAfterText() const
-{
- return mImpl->mModel->mIgnoreSpacesAfterText;
-}
-
-void Controller::SetIgnoreSpacesAfterText(bool ignore)
-{
- mImpl->mModel->mIgnoreSpacesAfterText = ignore;
-}
-
-void Controller::ChangedLayoutDirection()
-{
- mImpl->mIsLayoutDirectionChanged = true;
-}
-
-void Controller::SetMatchLayoutDirection(DevelText::MatchLayoutDirection type)
-{
- mImpl->mModel->mMatchLayoutDirection = type;
-}
-
-DevelText::MatchLayoutDirection Controller::GetMatchLayoutDirection() const
-{
- return mImpl->mModel->mMatchLayoutDirection;
-}
-
-void Controller::SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection)
-{
- mImpl->mLayoutDirection = layoutDirection;
-}
-
-Dali::LayoutDirection::Type Controller::GetLayoutDirection(Dali::Actor& actor) const
-{
- return mImpl->GetLayoutDirection(actor);
-}
-
-bool Controller::IsShowingRealText() const
-{
- return mImpl->IsShowingRealText();
-}
-
-void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
-{
- mImpl->SetLineWrapMode(lineWrapMode);
-}
-
-Text::LineWrap::Mode Controller::GetLineWrapMode() const
-{
- return mImpl->mModel->mLineWrapMode;
-}
-
-void Controller::SetTextElideEnabled(bool enabled)
-{
- mImpl->mModel->mElideEnabled = enabled;
- mImpl->mModel->mVisualModel->SetTextElideEnabled(enabled);
-}
-
-bool Controller::IsTextElideEnabled() const
-{
- return mImpl->mModel->mElideEnabled;
-}
-
-void Controller::SetTextFitEnabled(bool enabled)
-{
- mImpl->mTextFitEnabled = enabled;
-}
-
-bool Controller::IsTextFitEnabled() const
-{
- return mImpl->mTextFitEnabled;
-}
-
-void Controller::SetTextFitChanged(bool changed)
-{
- mImpl->mTextFitChanged = changed;
-}
-
-bool Controller::IsTextFitChanged() const
-{
- return mImpl->mTextFitChanged;
-}
-
-void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
-{
- mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize);
-}
-
-float Controller::GetTextFitMinSize() const
-{
- return mImpl->mTextFitMinSize;
-}
-
-void Controller::SetTextFitMaxSize(float maxSize, FontSizeType type)
-{
- mImpl->mTextFitMaxSize = (type == POINT_SIZE) ? maxSize : ConvertPixelToPoint(maxSize);
-}
-
-float Controller::GetTextFitMaxSize() const
-{
- return mImpl->mTextFitMaxSize;
-}
-
-void Controller::SetTextFitStepSize(float step, FontSizeType type)
-{
- mImpl->mTextFitStepSize = (type == POINT_SIZE) ? step : ConvertPixelToPoint(step);
-}
-
-float Controller::GetTextFitStepSize() const
-{
- return mImpl->mTextFitStepSize;
-}
-
-void Controller::SetTextFitContentSize(Vector2 size)
-{
- mImpl->mTextFitContentSize = size;
-}
-
-Vector2 Controller::GetTextFitContentSize() const
-{
- return mImpl->mTextFitContentSize;
-}
-
-float Controller::GetTextFitPointSize() const
-{
- return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFitPointSize : 0.0f;
-}
-
-void Controller::SetPlaceholderTextElideEnabled(bool enabled)
-{
- PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
-}
-
-bool Controller::IsPlaceholderTextElideEnabled() const
-{
- return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
-}
-
-void Controller::SetSelectionEnabled(bool enabled)
-{
- mImpl->mEventData->mSelectionEnabled = enabled;
-}
-
-bool Controller::IsSelectionEnabled() const
-{
- return mImpl->mEventData->mSelectionEnabled;
-}
-
-void Controller::SetShiftSelectionEnabled(bool enabled)
-{
- mImpl->mEventData->mShiftSelectionFlag = enabled;
-}
-
-bool Controller::IsShiftSelectionEnabled() const
-{
- return mImpl->mEventData->mShiftSelectionFlag;
-}
-
-void Controller::SetGrabHandleEnabled(bool enabled)
-{
- mImpl->mEventData->mGrabHandleEnabled = enabled;
-}
-
-bool Controller::IsGrabHandleEnabled() const
-{
- return mImpl->mEventData->mGrabHandleEnabled;
-}
-
-void Controller::SetGrabHandlePopupEnabled(bool enabled)
-{
- mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
-}
-
-bool Controller::IsGrabHandlePopupEnabled() const
-{
- return mImpl->mEventData->mGrabHandlePopupEnabled;
-}
-
-void Controller::SetText(const std::string& text)
-{
- TextUpdater::SetText(*this, text);
-}
-
-void Controller::GetText(std::string& text) const
-{
- mImpl->GetText(text);
-}
-
-void Controller::SetPlaceholderText(PlaceholderType type, const std::string& text)
-{
- PlaceholderHandler::SetPlaceholderText(*this, type, text);
-}
-
-void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) const
-{
- PlaceholderHandler::GetPlaceholderText(*this, type, text);
-}
-
-void Controller::UpdateAfterFontChange(const std::string& newDefaultFont)
-{
- mImpl->UpdateAfterFontChange(newDefaultFont);
-}
-
-void Controller::RetrieveSelection(std::string& selectedText) const
-{
- mImpl->RetrieveSelection(selectedText, false);
-}
-
-void Controller::SetSelection(int start, int end)
-{
- mImpl->SetSelection(start, end);
-}
-
-std::pair<int, int> Controller::GetSelectionIndexes() const
-{
- return mImpl->GetSelectionIndexes();
-}
-
-void Controller::CopyStringToClipboard(const std::string& source)
-{
- mImpl->CopyStringToClipboard(source);
-}
-
-void Controller::SendSelectionToClipboard(bool deleteAfterSending)
-{
- mImpl->SendSelectionToClipboard(deleteAfterSending);
-}
-
-void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
-{
- EnsureCreated(mImpl->mFontDefaults);
-
- mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
- DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
- mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-const std::string& Controller::GetDefaultFontFamily() const
-{
- return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.family : EMPTY_STRING;
-}
-
-void Controller::SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily)
-{
- PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
-}
-
-const std::string& Controller::GetPlaceholderFontFamily() const
-{
- return PlaceholderHandler::GetPlaceholderFontFamily(*this);
-}
-
-void Controller::SetDefaultFontWeight(FontWeight weight)
-{
- EnsureCreated(mImpl->mFontDefaults);
-
- mImpl->mFontDefaults->mFontDescription.weight = weight;
- mImpl->mFontDefaults->weightDefined = true;
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsDefaultFontWeightDefined() const
-{
- return mImpl->mFontDefaults && mImpl->mFontDefaults->weightDefined;
-}
-
-FontWeight Controller::GetDefaultFontWeight() const
-{
- return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.weight : TextAbstraction::FontWeight::NORMAL;
-}
-
-void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
-{
- PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
-}
-
-bool Controller::IsPlaceholderTextFontWeightDefined() const
-{
- return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);
-}
-
-FontWeight Controller::GetPlaceholderTextFontWeight() const
-{
- return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
-}
-
-void Controller::SetDefaultFontWidth(FontWidth width)
-{
- EnsureCreated(mImpl->mFontDefaults);
-
- mImpl->mFontDefaults->mFontDescription.width = width;
- mImpl->mFontDefaults->widthDefined = true;
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsDefaultFontWidthDefined() const
-{
- return mImpl->mFontDefaults && mImpl->mFontDefaults->widthDefined;
-}
-
-FontWidth Controller::GetDefaultFontWidth() const
-{
- return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.width : TextAbstraction::FontWidth::NORMAL;
-}
-
-void Controller::SetPlaceholderTextFontWidth(FontWidth width)
-{
- PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
-}
-
-bool Controller::IsPlaceholderTextFontWidthDefined() const
-{
- return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
-}
-
-FontWidth Controller::GetPlaceholderTextFontWidth() const
-{
- return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
-}
-
-void Controller::SetDefaultFontSlant(FontSlant slant)
-{
- EnsureCreated(mImpl->mFontDefaults);
-
- mImpl->mFontDefaults->mFontDescription.slant = slant;
- mImpl->mFontDefaults->slantDefined = true;
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsDefaultFontSlantDefined() const
-{
- return mImpl->mFontDefaults && mImpl->mFontDefaults->slantDefined;
-}
-
-FontSlant Controller::GetDefaultFontSlant() const
-{
- return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.slant : TextAbstraction::FontSlant::NORMAL;
-}
-
-void Controller::SetPlaceholderTextFontSlant(FontSlant slant)
-{
- PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
-}
-
-bool Controller::IsPlaceholderTextFontSlantDefined() const
-{
- return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
-}
-
-FontSlant Controller::GetPlaceholderTextFontSlant() const
-{
- return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
-}
-
-void Controller::SetFontSizeScale(float scale)
-{
- mImpl->mFontSizeScale = scale;
-
- // No relayout is required
- if(!mImpl->mFontSizeScaleEnabled) return;
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-float Controller::GetFontSizeScale() const
-{
- return mImpl->mFontDefaults ? mImpl->mFontSizeScale : 1.0f;
-}
-
-void Controller::SetFontSizeScaleEnabled(bool enabled)
-{
- mImpl->mFontSizeScaleEnabled = enabled;
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsFontSizeScaleEnabled() const
-{
- return mImpl->mFontSizeScaleEnabled;
-}
-
-void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
-{
- EnsureCreated(mImpl->mFontDefaults);
-
- mImpl->mFontDefaults->mDefaultPointSize = (type == POINT_SIZE) ? fontSize : ConvertPixelToPoint(fontSize);
- mImpl->mFontDefaults->sizeDefined = true;
-
- // Update the cursor position if it's in editing mode
- UpdateCursorPosition(mImpl->mEventData);
-
- // Clear the font-specific data
- mImpl->ClearFontData();
-
- mImpl->RequestRelayout();
-}
-
-float Controller::GetDefaultFontSize(FontSizeType type) const
-{
- if(mImpl->mFontDefaults)
- {
- return (type == POINT_SIZE) ? mImpl->mFontDefaults->mDefaultPointSize : ConvertPointToPixel(mImpl->mFontDefaults->mDefaultPointSize);
- }
- return 0.0f;
-}
-
-void Controller::SetPlaceholderTextFontSize(float fontSize, FontSizeType type)
-{
- PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
-}
-
-float Controller::GetPlaceholderTextFontSize(FontSizeType type) const
-{
- return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
-}
-
-void Controller::SetDefaultColor(const Vector4& color)
-{
- mImpl->SetDefaultColor(color);
-}
-
-const Vector4& Controller::GetDefaultColor() const
-{
- return mImpl->mTextColor;
-}
-
-void Controller::SetDisabledColorOpacity(float opacity)
-{
- mImpl->mDisabledColorOpacity = opacity;
-}
-
-float Controller::GetDisabledColorOpacity() const
-{
- return mImpl->mDisabledColorOpacity;
-}
-
-void Controller::SetUserInteractionEnabled(bool enabled)
-{
- mImpl->SetUserInteractionEnabled(enabled);
-}
-
-bool Controller::IsUserInteractionEnabled() const
-{
- return mImpl->mIsUserInteractionEnabled;
-}
-
-void Controller::SetPlaceholderTextColor(const Vector4& textColor)
-{
- PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
-}
-
-const Vector4& Controller::GetPlaceholderTextColor() const
-{
- return PlaceholderHandler::GetPlaceholderTextColor(*this);
-}
-
-void Controller::SetShadowOffset(const Vector2& shadowOffset)
-{
- mImpl->mModel->mVisualModel->SetShadowOffset(shadowOffset);
- mImpl->RequestRelayout();
-}
-
-const Vector2& Controller::GetShadowOffset() const
-{
- return mImpl->mModel->mVisualModel->GetShadowOffset();
-}
-
-void Controller::SetShadowColor(const Vector4& shadowColor)
-{
- mImpl->mModel->mVisualModel->SetShadowColor(shadowColor);
- mImpl->RequestRelayout();
-}
-
-const Vector4& Controller::GetShadowColor() const
-{
- return mImpl->mModel->mVisualModel->GetShadowColor();
-}
-
-void Controller::SetShadowBlurRadius(const float& shadowBlurRadius)
-{
- if(fabsf(GetShadowBlurRadius() - shadowBlurRadius) > Math::MACHINE_EPSILON_1)
- {
- mImpl->mModel->mVisualModel->SetShadowBlurRadius(shadowBlurRadius);
- mImpl->RequestRelayout();
- }
-}
-
-const float& Controller::GetShadowBlurRadius() const
-{
- return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
-}
-
-void Controller::SetUnderlineColor(const Vector4& color)
-{
- mImpl->mModel->mVisualModel->SetUnderlineColor(color);
- mImpl->RequestRelayout();
-}
-
-const Vector4& Controller::GetUnderlineColor() const
-{
- return mImpl->mModel->mVisualModel->GetUnderlineColor();
-}
-
-void Controller::SetUnderlineEnabled(bool enabled)
-{
- mImpl->mModel->mVisualModel->SetUnderlineEnabled(enabled);
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsUnderlineEnabled() const
-{
- return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
-}
-
-void Controller::SetUnderlineHeight(float height)
-{
- mImpl->mModel->mVisualModel->SetUnderlineHeight(height);
- mImpl->RequestRelayout();
-}
-
-float Controller::GetUnderlineHeight() const
-{
- return mImpl->mModel->mVisualModel->GetUnderlineHeight();
-}
-
-void Controller::SetUnderlineType(Text::Underline::Type type)
-{
- mImpl->mModel->mVisualModel->SetUnderlineType(type);
-
- mImpl->RequestRelayout();
-}
-
-Text::Underline::Type Controller::GetUnderlineType() const
-{
- return mImpl->mModel->mVisualModel->GetUnderlineType();
-}
-
-void Controller::SetDashedUnderlineWidth(float width)
-{
- mImpl->mModel->mVisualModel->SetDashedUnderlineWidth(width);
-
- mImpl->RequestRelayout();
-}
-
-float Controller::GetDashedUnderlineWidth() const
-{
- return mImpl->mModel->mVisualModel->GetDashedUnderlineWidth();
-}
-
-void Controller::SetDashedUnderlineGap(float gap)
-{
- mImpl->mModel->mVisualModel->SetDashedUnderlineGap(gap);
-
- mImpl->RequestRelayout();
-}
-
-float Controller::GetDashedUnderlineGap() const
-{
- return mImpl->mModel->mVisualModel->GetDashedUnderlineGap();
-}
-
-void Controller::SetOutlineColor(const Vector4& color)
-{
- mImpl->mModel->mVisualModel->SetOutlineColor(color);
- mImpl->RequestRelayout();
-}
-
-const Vector4& Controller::GetOutlineColor() const
-{
- return mImpl->mModel->mVisualModel->GetOutlineColor();
-}
-
-void Controller::SetOutlineWidth(uint16_t width)
-{
- mImpl->mModel->mVisualModel->SetOutlineWidth(width);
- mImpl->RequestRelayout();
-}
-
-uint16_t Controller::GetOutlineWidth() const
-{
- return mImpl->mModel->mVisualModel->GetOutlineWidth();
-}
-
-void Controller::SetBackgroundColor(const Vector4& color)
-{
- mImpl->mModel->mVisualModel->SetBackgroundColor(color);
- mImpl->RequestRelayout();
-}
-
-const Vector4& Controller::GetBackgroundColor() const
-{
- return mImpl->mModel->mVisualModel->GetBackgroundColor();
-}
-
-void Controller::SetBackgroundEnabled(bool enabled)
-{
- mImpl->mModel->mVisualModel->SetBackgroundEnabled(enabled);
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsBackgroundEnabled() const
-{
- return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
-}
-
-void Controller::SetDefaultEmbossProperties(const std::string& embossProperties)
-{
- EnsureCreated(mImpl->mEmbossDefaults);
- mImpl->mEmbossDefaults->properties = embossProperties;
-}
-
-const std::string& Controller::GetDefaultEmbossProperties() const
-{
- return mImpl->mEmbossDefaults ? mImpl->mEmbossDefaults->properties : EMPTY_STRING;
-}
-
-void Controller::SetDefaultOutlineProperties(const std::string& outlineProperties)
-{
- EnsureCreated(mImpl->mOutlineDefaults);
- mImpl->mOutlineDefaults->properties = outlineProperties;
-}
-
-const std::string& Controller::GetDefaultOutlineProperties() const
-{
- return mImpl->mOutlineDefaults ? mImpl->mOutlineDefaults->properties : EMPTY_STRING;
-}
-
-bool Controller::SetDefaultLineSpacing(float lineSpacing)
-{
- return mImpl->SetDefaultLineSpacing(lineSpacing);
-}
-
-float Controller::GetDefaultLineSpacing() const
-{
- return mImpl->mLayoutEngine.GetDefaultLineSpacing();
-}
-
-bool Controller::SetDefaultLineSize(float lineSize)
-{
- return mImpl->SetDefaultLineSize(lineSize);
-}
-
-float Controller::GetDefaultLineSize() const
-{
- return mImpl->mLayoutEngine.GetDefaultLineSize();
-}
-
-bool Controller::SetRelativeLineSize(float relativeLineSize)
-{
- return mImpl->SetRelativeLineSize(relativeLineSize);
-}
-
-float Controller::GetRelativeLineSize() const
-{
- return mImpl->GetRelativeLineSize();
-}
-
-void Controller::SetInputColor(const Vector4& color)
-{
- InputProperties::SetInputColor(*this, color);
-}
-
-const Vector4& Controller::GetInputColor() const
-{
- return InputProperties::GetInputColor(*this);
-}
-
-void Controller::SetInputFontFamily(const std::string& fontFamily)
-{
- InputFontHandler::SetInputFontFamily(*this, fontFamily);
-}
-
-const std::string& Controller::GetInputFontFamily() const
-{
- return InputFontHandler::GetInputFontFamily(*this);
-}
-
-void Controller::SetInputFontWeight(FontWeight weight)
-{
- InputFontHandler::SetInputFontWeight(*this, weight);
-}
-
-bool Controller::IsInputFontWeightDefined() const
-{
- return InputFontHandler::IsInputFontWeightDefined(*this);
-}
-
-FontWeight Controller::GetInputFontWeight() const
-{
- return InputFontHandler::GetInputFontWeight(*this);
-}
-
-void Controller::SetInputFontWidth(FontWidth width)
-{
- InputFontHandler::SetInputFontWidth(*this, width);
-}
-
-bool Controller::IsInputFontWidthDefined() const
-{
- return InputFontHandler::IsInputFontWidthDefined(*this);
-}
-
-FontWidth Controller::GetInputFontWidth() const
-{
- return InputFontHandler::GetInputFontWidth(*this);
-}
-
-void Controller::SetInputFontSlant(FontSlant slant)
-{
- InputFontHandler::SetInputFontSlant(*this, slant);
-}
-
-bool Controller::IsInputFontSlantDefined() const
-{
- return InputFontHandler::IsInputFontSlantDefined(*this);
-}
-
-FontSlant Controller::GetInputFontSlant() const
-{
- return InputFontHandler::GetInputFontSlant(*this);
-}
-
-void Controller::SetInputFontPointSize(float size)
-{
- InputFontHandler::SetInputFontPointSize(*this, size);
-}
-
-float Controller::GetInputFontPointSize() const
-{
- return InputFontHandler::GetInputFontPointSize(*this);
-}
-
-void Controller::SetInputLineSpacing(float lineSpacing)
-{
- InputProperties::SetInputLineSpacing(*this, lineSpacing);
-}
-
-float Controller::GetInputLineSpacing() const
-{
- return InputProperties::GetInputLineSpacing(*this);
-}
-
-void Controller::SetInputShadowProperties(const std::string& shadowProperties)
-{
- InputProperties::SetInputShadowProperties(*this, shadowProperties);
-}
-
-const std::string& Controller::GetInputShadowProperties() const
-{
- return InputProperties::GetInputShadowProperties(*this);
-}
-
-void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
-{
- InputProperties::SetInputUnderlineProperties(*this, underlineProperties);
-}
-
-const std::string& Controller::GetInputUnderlineProperties() const
-{
- return InputProperties::GetInputUnderlineProperties(*this);
-}
-
-void Controller::SetInputEmbossProperties(const std::string& embossProperties)
-{
- InputProperties::SetInputEmbossProperties(*this, embossProperties);
-}
-
-const std::string& Controller::GetInputEmbossProperties() const
-{
- return InputProperties::GetInputEmbossProperties(*this);
-}
-
-void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
-{
- InputProperties::SetInputOutlineProperties(*this, outlineProperties);
-}
-
-const std::string& Controller::GetInputOutlineProperties() const
-{
- return InputProperties::GetInputOutlineProperties(*this);
-}
-
-void Controller::SetInputModePassword(bool passwordInput)
-{
- InputProperties::SetInputModePassword(*this, passwordInput);
-}
-
-bool Controller::IsInputModePassword()
-{
- return InputProperties::IsInputModePassword(*this);
-}
-
-void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
-{
- if(mImpl->mEventData)
- {
- mImpl->mEventData->mDoubleTapAction = action;
- }
-}
-
-Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
-{
- return mImpl->mEventData ? mImpl->mEventData->mDoubleTapAction : NoTextTap::NO_ACTION;
-}
-
-void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
-{
- if(mImpl->mEventData)
- {
- mImpl->mEventData->mLongPressAction = action;
- }
-}
-
-Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
-{
- return mImpl->mEventData ? mImpl->mEventData->mLongPressAction : NoTextTap::NO_ACTION;
-}
-
-bool Controller::IsUnderlineSetByString()
-{
- return mImpl->mUnderlineSetByString;
-}
-
-void Controller::UnderlineSetByString(bool setByString)
-{
- mImpl->mUnderlineSetByString = setByString;
-}
-
-bool Controller::IsShadowSetByString()
-{
- return mImpl->mShadowSetByString;
-}
-
-void Controller::ShadowSetByString(bool setByString)
-{
- mImpl->mShadowSetByString = setByString;
-}
-
-bool Controller::IsOutlineSetByString()
-{
- return mImpl->mOutlineSetByString;
-}
-
-void Controller::OutlineSetByString(bool setByString)
-{
- mImpl->mOutlineSetByString = setByString;
-}
-
-bool Controller::IsFontStyleSetByString()
-{
- return mImpl->mFontStyleSetByString;
-}
-
-void Controller::FontStyleSetByString(bool setByString)
-{
- mImpl->mFontStyleSetByString = setByString;
-}
-
-void Controller::SetStrikethroughHeight(float height)
-{
- mImpl->mModel->mVisualModel->SetStrikethroughHeight(height);
-
- mImpl->RequestRelayout();
-}
-
-float Controller::GetStrikethroughHeight() const
-{
- return mImpl->mModel->mVisualModel->GetStrikethroughHeight();
-}
-
-void Controller::SetStrikethroughColor(const Vector4& color)
-{
- mImpl->mModel->mVisualModel->SetStrikethroughColor(color);
-
- mImpl->RequestRelayout();
-}
-
-const Vector4& Controller::GetStrikethroughColor() const
-{
- return mImpl->mModel->mVisualModel->GetStrikethroughColor();
-}
-
-void Controller::SetStrikethroughEnabled(bool enabled)
-{
- mImpl->mModel->mVisualModel->SetStrikethroughEnabled(enabled);
-
- mImpl->RequestRelayout();
-}
-
-bool Controller::IsStrikethroughEnabled() const
-{
- return mImpl->mModel->mVisualModel->IsStrikethroughEnabled();
-}
-
-void Controller::SetInputStrikethroughProperties(const std::string& strikethroughProperties)
-{
- if(NULL != mImpl->mEventData)
- {
- mImpl->mEventData->mInputStyle.strikethroughProperties = strikethroughProperties;
- }
-}
-
-const std::string& Controller::GetInputStrikethroughProperties() const
-{
- return (NULL != mImpl->mEventData) ? mImpl->mEventData->mInputStyle.strikethroughProperties : EMPTY_STRING;
-}
-
-bool Controller::IsStrikethroughSetByString()
-{
- return mImpl->mStrikethroughSetByString;
-}
-
-void Controller::StrikethroughSetByString(bool setByString)
-{
- mImpl->mStrikethroughSetByString = setByString;
-}
-
-Layout::Engine& Controller::GetLayoutEngine()
-{
- return mImpl->mLayoutEngine;
-}
-
-View& Controller::GetView()
-{
- return mImpl->mView;
-}
-
-Vector3 Controller::GetNaturalSize()
-{
- return Relayouter::GetNaturalSize(*this);
-}
-
-bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
-{
- return Relayouter::CheckForTextFit(*this, pointSize, layoutSize);
-}
-
-void Controller::FitPointSizeforLayout(Size layoutSize)
-{
- Relayouter::FitPointSizeforLayout(*this, layoutSize);
-}
-
-float Controller::GetHeightForWidth(float width)
-{
- return Relayouter::GetHeightForWidth(*this, width);
-}
-
-int Controller::GetLineCount(float width)
-{
- GetHeightForWidth(width);
- return mImpl->mModel->GetNumberOfLines();
-}
-
-const ModelInterface* const Controller::GetTextModel() const
-{
- return mImpl->mModel.Get();
-}
-
-float Controller::GetScrollAmountByUserInput()
-{
- float scrollAmount = 0.0f;
-
- if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
- {
- scrollAmount = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
- mImpl->mEventData->mCheckScrollAmount = false;
- }
- return scrollAmount;
-}
-
-bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
-{
- const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
- bool isScrolled;
-
- controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
- layoutHeight = layout.height;
- scrollPosition = mImpl->mModel->mScrollPosition.y;
- isScrolled = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
- return isScrolled;
-}
-
-void Controller::SetHiddenInputOption(const Property::Map& options)
-{
- EnsureCreated<HiddenText, Controller*>(mImpl->mHiddenInput, this);
- mImpl->mHiddenInput->SetProperties(options);
-}
-
-void Controller::GetHiddenInputOption(Property::Map& options)
-{
- if(mImpl->mHiddenInput)
- {
- mImpl->mHiddenInput->GetProperties(options);
- }
-}
-
-void Controller::SetInputFilterOption(const Property::Map& options)
-{
- EnsureCreated(mImpl->mInputFilter);
- mImpl->mInputFilter->SetProperties(options);
-}
-
-void Controller::GetInputFilterOption(Property::Map& options)
-{
- if(mImpl->mInputFilter)
- {
- mImpl->mInputFilter->GetProperties(options);
- }
-}
-
-void Controller::SetPlaceholderProperty(const Property::Map& map)
-{
- PlaceholderHandler::SetPlaceholderProperty(*this, map);
-}
-
-void Controller::GetPlaceholderProperty(Property::Map& map)
-{
- PlaceholderHandler::GetPlaceholderProperty(*this, map);
-}
-
-Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
-{
- // Make sure the model is up-to-date before layouting
- EventHandler::ProcessModifyEvents(*this);
-
- return mImpl->GetTextDirection();
-}
-
-Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
-{
- return mImpl->mModel->GetVerticalLineAlignment();
-}
-
-void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
-{
- mImpl->mModel->mVerticalLineAlignment = alignment;
-}
-
-Toolkit::DevelText::EllipsisPosition::Type Controller::GetEllipsisPosition() const
-{
- return mImpl->mModel->GetEllipsisPosition();
-}
-
-void Controller::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
-{
- mImpl->mModel->mEllipsisPosition = ellipsisPosition;
- mImpl->mModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
-}
-
-void Controller::SetCharacterSpacing(float characterSpacing)
-{
- mImpl->mModel->mVisualModel->SetCharacterSpacing(characterSpacing);
-
- mImpl->RelayoutAllCharacters();
- mImpl->RequestRelayout();
-}
-
-const float Controller::GetCharacterSpacing() const
-{
- return mImpl->mModel->mVisualModel->GetCharacterSpacing();
-}
-
-Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
-{
- return Relayouter::Relayout(*this, size, layoutDirection);
-}
-
-void Controller::RequestRelayout()
-{
- mImpl->RequestRelayout();
-}
-
-Vector<Vector2> Controller::GetTextSize(CharacterIndex startIndex, CharacterIndex endIndex)
-{
- Vector<Vector2> sizesList;
- Vector<Vector2> positionsList;
-
- GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizesList, positionsList);
- return sizesList;
-}
-
-Vector<Vector2> Controller::GetTextPosition(CharacterIndex startIndex, CharacterIndex endIndex)
-{
- Vector<Vector2> sizesList;
- Vector<Vector2> positionsList;
-
- GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizesList, positionsList);
- return positionsList;
-}
-
-Rect<> Controller::GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex)
-{
- Vector<Vector2> sizeList;
- Vector<Vector2> positionList;
-
- GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizeList, positionList);
-
- if(sizeList.Empty() || sizeList.Size() != positionList.Size())
- {
- return {0, 0, 0, 0};
- }
-
- auto minX = positionList[0].x;
- auto minY = positionList[0].y;
- auto maxRight = positionList[0].x + sizeList[0].x;
- auto maxBottom = positionList[0].y + sizeList[0].y;
-
- for(unsigned int i = 1; i < sizeList.Size(); i++)
- {
- minX = std::min(minX, positionList[i].x);
- minY = std::min(minY, positionList[i].y);
- maxRight = std::max(maxRight, positionList[i].x + sizeList[i].x);
- maxBottom = std::max(maxBottom, positionList[i].y + sizeList[i].y);
- }
-
- return {minX, minY, maxRight - minX, maxBottom - minY};
-}
-
-bool Controller::IsInputStyleChangedSignalsQueueEmpty()
-{
- return mImpl->IsInputStyleChangedSignalsQueueEmpty();
-}
-
-void Controller::ProcessInputStyleChangedSignals()
-{
- mImpl->ProcessInputStyleChangedSignals();
-}
-
-void Controller::KeyboardFocusGainEvent()
-{
- EventHandler::KeyboardFocusGainEvent(*this);
-}
-
-void Controller::KeyboardFocusLostEvent()
-{
- EventHandler::KeyboardFocusLostEvent(*this);
-}
-
-bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
-{
- return EventHandler::KeyEvent(*this, keyEvent);
-}
-
-void Controller::AnchorEvent(float x, float y)
-{
- EventHandler::AnchorEvent(*this, x, y);
-}
-
-void Controller::TapEvent(unsigned int tapCount, float x, float y)
-{
- EventHandler::TapEvent(*this, tapCount, x, y);
-}
-
-void Controller::PanEvent(GestureState state, const Vector2& displacement)
-{
- EventHandler::PanEvent(*this, state, displacement);
-}
-
-void Controller::LongPressEvent(GestureState state, float x, float y)
-{
- EventHandler::LongPressEvent(*this, state, x, y);
-}
-
-void Controller::SelectEvent(float x, float y, SelectionType selectType)
-{
- EventHandler::SelectEvent(*this, x, y, selectType);
-}
-
-void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
-{
- if(mImpl->mEventData)
- {
- mImpl->mEventData->mCheckScrollAmount = true;
- mImpl->mEventData->mIsLeftHandleSelected = true;
- mImpl->mEventData->mIsRightHandleSelected = true;
- mImpl->SetTextSelectionRange(start, end);
- mImpl->RequestRelayout();
- EventHandler::KeyboardFocusGainEvent(*this);
- }
-}
-
-Uint32Pair Controller::GetTextSelectionRange() const
-{
- return mImpl->GetTextSelectionRange();
-}
-
-CharacterIndex Controller::GetPrimaryCursorPosition() const
-{
- return mImpl->GetPrimaryCursorPosition();
-}
-
-bool Controller::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
-{
- if(mImpl->mEventData)
- {
- mImpl->mEventData->mCheckScrollAmount = true;
- mImpl->mEventData->mIsLeftHandleSelected = true;
- mImpl->mEventData->mIsRightHandleSelected = true;
- mImpl->mEventData->mCheckScrollAmount = true;
- if(mImpl->SetPrimaryCursorPosition(index, focused) && focused)
- {
- EventHandler::KeyboardFocusGainEvent(*this);
- return true;
- }
- }
- return false;
-}
-
-void Controller::SelectWholeText()
-{
- EventHandler::SelectEvent(*this, 0.f, 0.f, SelectionType::ALL);
-}
-
-void Controller::SelectNone()
-{
- EventHandler::SelectEvent(*this, 0.f, 0.f, SelectionType::NONE);
-}
-
-void Controller::SelectText(const uint32_t start, const uint32_t end)
-{
- EventHandler::SelectEvent(*this, start, end, SelectionType::RANGE);
-}
-
-string Controller::GetSelectedText() const
-{
- return mImpl->GetSelectedText();
-}
-
-string Controller::CopyText()
-{
- return mImpl->CopyText();
-}
-
-string Controller::CutText()
-{
- return mImpl->CutText();
-}
-
-void Controller::PasteText()
-{
- mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
-}
-
-InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
-{
- return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
-}
-
-void Controller::PasteClipboardItemEvent()
-{
- EventHandler::PasteClipboardItemEvent(*this);
-}
-
-void Controller::GetTargetSize(Vector2& targetSize)
-{
- targetSize = mImpl->mModel->mVisualModel->mControlSize;
-}
-
-void Controller::AddDecoration(Actor& actor, DecorationType type, bool needsClipping)
-{
- if(mImpl->mEditableControlInterface)
- {
- mImpl->mEditableControlInterface->AddDecoration(actor, type, needsClipping);
- }
-}
-
-bool Controller::IsEditable() const
-{
- return mImpl->IsEditable();
-}
-
-void Controller::SetEditable(bool editable)
-{
- mImpl->SetEditable(editable);
-}
-
-void Controller::ScrollBy(Vector2 scroll)
-{
- mImpl->ScrollBy(scroll);
-}
-
-bool Controller::IsScrollable(const Vector2& displacement)
-{
- return mImpl->IsScrollable(displacement);
-}
-
-float Controller::GetHorizontalScrollPosition()
-{
- return mImpl->GetHorizontalScrollPosition();
-}
-
-float Controller::GetVerticalScrollPosition()
-{
- return mImpl->GetVerticalScrollPosition();
-}
-
-void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
-{
- EventHandler::DecorationEvent(*this, handleType, state, x, y);
-}
-
-void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
-{
- EventHandler::TextPopupButtonTouched(*this, button);
-}
-
-void Controller::DisplayTimeExpired()
-{
- mImpl->mEventData->mUpdateCursorPosition = true;
- // Apply modifications to the model
- mImpl->mOperationsPending = ALL_OPERATIONS;
-
- mImpl->RequestRelayout();
-}
-
-void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
-{
- // Reset the cursor position
- if(NULL != mImpl->mEventData)
- {
- mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
-
- // Update the cursor if it's in editing mode.
- if(EventData::IsEditingState(mImpl->mEventData->mState))
- {
- mImpl->mEventData->mUpdateCursorPosition = true;
- }
- }
-}
-
-CharacterIndex Controller::GetCursorPosition()
-{
- return mImpl->mEventData ? mImpl->mEventData->mPrimaryCursorPosition : 0;
-}
-
-void Controller::SetControlInterface(ControlInterface* controlInterface)
-{
- mImpl->mControlInterface = controlInterface;
-}
-
-void Controller::SetAnchorControlInterface(AnchorControlInterface* anchorControlInterface)
-{
- mImpl->mAnchorControlInterface = anchorControlInterface;
-}
-
-bool Controller::ShouldClearFocusOnEscape() const
-{
- return mImpl->mShouldClearFocusOnEscape;
-}
-
-Actor Controller::CreateBackgroundActor()
-{
- return CreateControllerBackgroundActor(mImpl->mView, mImpl->mModel->mVisualModel, mImpl->mModel->mLogicalModel, mImpl->mShaderBackground);
-}
-
-void Controller::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
-{
- mImpl->GetAnchorActors(anchorActors);
-}
-
-int Controller::GetAnchorIndex(size_t characterOffset)
-{
- return mImpl->GetAnchorIndex(characterOffset);
-}
-
-Controller::Controller(ControlInterface* controlInterface,
- EditableControlInterface* editableControlInterface,
- SelectableControlInterface* selectableControlInterface,
- AnchorControlInterface* anchorControlInterface)
-: mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface, anchorControlInterface))
-{
-}
-
-Controller::~Controller()
-{
- delete mImpl;
-}
-
-} // namespace Dali::Toolkit::Text
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_H
-#define DALI_TOOLKIT_TEXT_CONTROLLER_H
-
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/input-method-context.h>
-#include <dali/public-api/events/gesture.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
-#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
-#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
-#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
-#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-#include <dali-toolkit/internal/text/hidden-text.h>
-#include <dali-toolkit/internal/text/input-filter.h>
-#include <dali-toolkit/internal/text/layouts/layout-engine.h>
-#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
-#include <dali-toolkit/internal/text/text-model-interface.h>
-#include <dali-toolkit/internal/text/text-selectable-control-interface.h>
-#include <dali-toolkit/public-api/text/text-enumerations.h>
-
-namespace Dali::Toolkit::Text
-{
-class Controller;
-class ControlInterface;
-class EditableControlInterface;
-class View;
-class RenderingController;
-
-/**
- * @brief Text selection operations .
- */
-enum SelectionType
-{
- INTERACTIVE = 0x0000, ///< Select the word where the cursor is located.
- ALL = 0x0001, ///< Select the whole text.
- NONE = 0x0002, ///< Unselect the whole text.
- RANGE = 0x0003 ///< Select the range text.
-};
-
-typedef IntrusivePtr<Controller> ControllerPtr;
-
-/**
- * @brief A Text Controller is used by UI Controls which display text.
- *
- * It manipulates the Logical & Visual text models on behalf of the UI Controls.
- * It provides a view of the text that can be used by rendering back-ends.
- *
- * For selectable/editable UI controls, the controller handles input events from the UI control
- * and decorations (grab handles etc) via the Decorator::ControllerInterface interface.
- *
- * The text selection popup button callbacks are as well handled via the TextSelectionPopupCallbackInterface interface.
- */
-class Controller : public RefObject, public Decorator::ControllerInterface, public TextSelectionPopupCallbackInterface, public HiddenText::Observer
-{
-public: // Enumerated types.
- /**
- * @brief Text related operations to be done in the relayout process.
- */
- enum OperationsMask
- {
- NO_OPERATION = 0x0000,
- CONVERT_TO_UTF32 = 0x0001,
- GET_SCRIPTS = 0x0002,
- VALIDATE_FONTS = 0x0004,
- GET_LINE_BREAKS = 0x0008,
- BIDI_INFO = 0x0010,
- SHAPE_TEXT = 0x0020,
- GET_GLYPH_METRICS = 0x0040,
- LAYOUT = 0x0080,
- UPDATE_LAYOUT_SIZE = 0x0100,
- REORDER = 0x0200,
- ALIGN = 0x0400,
- COLOR = 0x0800,
- UPDATE_DIRECTION = 0x1000,
- ALL_OPERATIONS = 0xFFFF
- };
-
- /**
- * @brief Used to distinguish between regular key events and InputMethodContext events
- */
- enum InsertType
- {
- COMMIT,
- PRE_EDIT
- };
-
- /**
- * @brief Used to specify whether to update the input style.
- */
- enum UpdateInputStyleType
- {
- UPDATE_INPUT_STYLE,
- DONT_UPDATE_INPUT_STYLE
- };
-
- /**
- * @brief Used to specify what has been updated after the Relayout() method has been called.
- */
- enum UpdateTextType
- {
- NONE_UPDATED = 0x0, ///< Nothing has been updated.
- MODEL_UPDATED = 0x1, ///< The text's model has been updated.
- DECORATOR_UPDATED = 0x2 ///< The decoration has been updated.
- };
-
- /**
- * @brief Different placeholder-text can be shown when the control is active/inactive.
- */
- enum PlaceholderType
- {
- PLACEHOLDER_TYPE_ACTIVE,
- PLACEHOLDER_TYPE_INACTIVE,
- };
-
- /**
- * @brief Enumeration for Font Size Type.
- */
- enum FontSizeType
- {
- POINT_SIZE, // The size of font in points.
- PIXEL_SIZE // The size of font in pixels.
- };
-
- struct NoTextTap
- {
- enum Action
- {
- NO_ACTION, ///< Does no action if there is a tap on top of an area with no text.
- HIGHLIGHT, ///< Highlights the nearest text (at the beginning or end of the text) and shows the text's selection popup.
- SHOW_SELECTION_POPUP ///< Shows the text's selection popup.
- };
- };
-
- struct TextFitInfo
- {
- enum Property
- {
- TEXT_FIT_ENABLE,
- TEXT_FIT_MIN_SIZE,
- TEXT_FIT_MAX_SIZE,
- TEXT_FIT_STEP_SIZE,
- TEXT_FIT_FONT_SIZE_TYPE
- };
- };
-
-public: // Constructor.
- /**
- * @brief Create a new instance of a Controller.
- *
- * @return A pointer to a new Controller.
- */
- static ControllerPtr New()
- {
- return ControllerPtr(new Controller());
- }
-
- /**
- * @brief Create a new instance of a Controller.
- *
- * @param[in] controlInterface The control's interface.
- *
- * @return A pointer to a new Controller.
- */
- static ControllerPtr New(ControlInterface* controlInterface)
- {
- return ControllerPtr(new Controller(controlInterface));
- }
-
- /**
- * @brief Create a new instance of a Controller.
- *
- * @param[in] controlInterface The control's interface.
- * @param[in] editableControlInterface The editable control's interface.
- * @param[in] selectableControlInterface The selectable control's interface.
- * @param[in] anchorControlInterface The anchor control's interface.
- *
- * @return A pointer to a new Controller.
- */
- static ControllerPtr New(ControlInterface* controlInterface,
- EditableControlInterface* editableControlInterface,
- SelectableControlInterface* selectableControlInterface,
- AnchorControlInterface* anchorControlInterface)
- {
- return ControllerPtr(new Controller(controlInterface,
- editableControlInterface,
- selectableControlInterface,
- anchorControlInterface));
- }
-
-public: // Configure the text controller.
- /**
- * @brief Called to enable text input.
- *
- * @note Selectable or editable controls should call this once after Controller::New().
- * @param[in] decorator Used to create cursor, selection handle decorations etc.
- * @param[in] inputMethodContext Used to manager ime.
- */
- void EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext);
-
- /**
- * @brief Used to switch between bitmap & vector based glyphs
- *
- * @param[in] glyphType The type of glyph; note that metrics for bitmap & vector based glyphs are different.
- */
- void SetGlyphType(TextAbstraction::GlyphType glyphType);
-
- /**
- * @brief Enables/disables the mark-up processor.
- *
- * By default is disabled.
- *
- * @param[in] enable Whether to enable the mark-up processor.
- */
- void SetMarkupProcessorEnabled(bool enable);
-
- /**
- * @brief Retrieves whether the mark-up processor is enabled.
- *
- * By default is disabled.
- *
- * @return @e true if the mark-up processor is enabled, otherwise returns @e false.
- */
- bool IsMarkupProcessorEnabled() const;
-
- /**
- * @brief Retrieves whether the current text contains anchors.
- *
- * @return @e true if the current text contains anchors. @e false.
- */
- bool HasAnchors() const;
-
- /**
- * @brief Enables/disables the auto text scrolling
- *
- * By default is disabled.
- *
- * @param[in] enable Whether to enable the auto scrolling
- */
- void SetAutoScrollEnabled(bool enable);
-
- /**
- * @brief Whether the auto scrolling texture exceed max texture.
- *
- * By default is false.
- *
- * @param[in] exceed Whether the auto scrolling texture exceed max texture.
- */
- void SetAutoScrollMaxTextureExceeded(bool exceed);
-
- /**
- * @brief Retrieves whether auto text scrolling is enabled.
- *
- * By default is disabled.
- *
- * @return @e true if auto scrolling is enabled, otherwise returns @e false.
- */
- bool IsAutoScrollEnabled() const;
-
- /**
- * @brief Get direction of the text from the first line of text,
- * @return bool rtl (right to left) is true
- */
- CharacterDirection GetAutoScrollDirection() const;
-
- /**
- * @brief Get the alignment offset of the first line of text.
- *
- * @return The alignment offset.
- */
- float GetAutoScrollLineAlignment() const;
-
- /**
- * @brief Enables the horizontal scrolling.
- *
- * @param[in] enable Whether to enable the horizontal scrolling.
- */
- void SetHorizontalScrollEnabled(bool enable);
-
- /**
- * @brief Retrieves whether the horizontal scrolling is enabled.
- *
- * @return @e true if the horizontal scrolling is enabled, otherwise it returns @e false.
- */
- bool IsHorizontalScrollEnabled() const;
-
- /**
- * @brief Enables the vertical scrolling.
- *
- * @param[in] enable Whether to enable the vertical scrolling.
- */
- void SetVerticalScrollEnabled(bool enable);
-
- /**
- * @brief Retrieves whether the verticall scrolling is enabled.
- *
- * @return @e true if the vertical scrolling is enabled, otherwise it returns @e false.
- */
- bool IsVerticalScrollEnabled() const;
-
- /**
- * @brief Enables the smooth handle panning.
- *
- * @param[in] enable Whether to enable the smooth handle panning.
- */
- void SetSmoothHandlePanEnabled(bool enable);
-
- /**
- * @brief Retrieves whether the smooth handle panning is enabled.
- *
- * @return @e true if the smooth handle panning is enabled.
- */
- bool IsSmoothHandlePanEnabled() const;
-
- /**
- * @brief Sets the maximum number of characters that can be inserted into the TextModel
- *
- * @param[in] maxCharacters maximum number of characters to be accepted
- */
- void SetMaximumNumberOfCharacters(Length maxCharacters);
-
- /**
- * @brief Sets the maximum number of characters that can be inserted into the TextModel
- *
- * @param[in] maxCharacters maximum number of characters to be accepted
- */
- int GetMaximumNumberOfCharacters();
-
- /**
- * @brief Called to enable/disable cursor blink.
- *
- * @note Only editable controls should calls this.
- * @param[in] enabled Whether the cursor should blink or not.
- */
- void SetEnableCursorBlink(bool enable);
-
- /**
- * @brief Query whether cursor blink is enabled.
- *
- * @return Whether the cursor should blink or not.
- */
- bool GetEnableCursorBlink() const;
-
- /**
- * @brief Whether to enable the multi-line layout.
- *
- * @param[in] enable \e true enables the multi-line (by default)
- */
- void SetMultiLineEnabled(bool enable);
-
- /**
- * @return Whether the multi-line layout is enabled.
- */
- bool IsMultiLineEnabled() const;
-
- /**
- * @brief Sets the text's horizontal alignment.
- *
- * @param[in] alignment The horizontal alignment.
- */
- void SetHorizontalAlignment(HorizontalAlignment::Type alignment);
-
- /**
- * @copydoc ModelInterface::GetHorizontalAlignment()
- */
- HorizontalAlignment::Type GetHorizontalAlignment() const;
-
- /**
- * @brief Sets the text's vertical alignment.
- *
- * @param[in] alignment The vertical alignment.
- */
- void SetVerticalAlignment(VerticalAlignment::Type alignment);
-
- /**
- * @copydoc ModelInterface::GetVerticalAlignment()
- */
- VerticalAlignment::Type GetVerticalAlignment() const;
-
- /**
- * @brief Sets the text's wrap mode
- * @param[in] text wrap mode The unit of wrapping
- */
- void SetLineWrapMode(Text::LineWrap::Mode textWarpMode);
-
- /**
- * @brief Retrieve text wrap mode previously set.
- * @return text wrap mode
- */
- Text::LineWrap::Mode GetLineWrapMode() const;
-
- /**
- * @brief Enable or disable the text elide.
- *
- * @param[in] enabled Whether to enable the text elide.
- */
- void SetTextElideEnabled(bool enabled);
-
- /**
- * @copydoc ModelInterface::IsTextElideEnabled()
- */
- bool IsTextElideEnabled() const;
-
- /**
- * @brief Enable or disable the text fit.
- *
- * @param[in] enabled Whether to enable the text fit.
- */
- void SetTextFitEnabled(bool enabled);
-
- /**
- * @brief Whether the text fit is enabled or not.
- *
- * @return True if the text fit is enabled
- */
- bool IsTextFitEnabled() const;
-
- /**
- * @brief Sets minimum size valid for text fit.
- *
- * @param[in] minimum size value.
- * @param[in] type The font size type is point size or pixel size
- */
- void SetTextFitMinSize(float pointSize, FontSizeType type);
-
- /**
- * @brief Retrieves the minimum point size valid for text fit.
- *
- * @return The minimum point size valid for text fit
- */
- float GetTextFitMinSize() const;
-
- /**
- * @brief Sets maximum size valid for text fit.
- *
- * @param[in] maximum size value.
- * @param[in] type The font size type is point size or pixel size
- */
- void SetTextFitMaxSize(float pointSize, FontSizeType type);
-
- /**
- * @brief Retrieves the maximum point size valid for text fit.
- *
- * @return The maximum point size valid for text fit
- */
- float GetTextFitMaxSize() const;
-
- /**
- * @brief Sets step size for font increase valid for text fit.
- *
- * @param[in] step size value.
- * @param[in] type The font size type is point size or pixel size
- */
- void SetTextFitStepSize(float step, FontSizeType type);
-
- /**
- * @brief Retrieves the step point size valid for text fit.
- *
- * @return The step point size valid for text fit
- */
- float GetTextFitStepSize() const;
-
- /**
- * @brief Sets content size valid for text fit.
- *
- * @param[in] Content size value.
- */
- void SetTextFitContentSize(Vector2 size);
-
- /**
- * @brief Retrieves the content size valid for text fit.
- *
- * @return The content size valid for text fit
- */
- Vector2 GetTextFitContentSize() const;
-
- /**
- * @brief Retrieve the fited point size.
- *
- * @return The fited point size.
- */
- float GetTextFitPointSize() const;
-
- /**
- * @brief Sets whether the text fit properties have changed.
- *
- * @param[in] changed Whether to changed the text fit.
- */
- void SetTextFitChanged(bool changed);
-
- /**
- * @brief Whether the text fit properties are changed or not.
- *
- * @return True if the text fit properties are changed
- */
- bool IsTextFitChanged() const;
-
- /**
- * @brief Sets disabled color opacity.
- *
- * @param[in] opacity The color opacity value in disabled state.
- */
- void SetDisabledColorOpacity(float opacity);
-
- /**
- * @brief Retrieves the disabled color opacity.
- *
- * @return The disabled color opacity value for disabled state.
- */
- float GetDisabledColorOpacity() const;
-
- /**
- * @brief Enable or disable the placeholder text elide.
- * @param enabled Whether to enable the placeholder text elide.
- */
- void SetPlaceholderTextElideEnabled(bool enabled);
-
- /**
- * @brief Whether the placeholder text elide property is enabled.
- * @return True if the placeholder text elide property is enabled, false otherwise.
- */
- bool IsPlaceholderTextElideEnabled() const;
-
- /**
- * @brief Enable or disable the text selection.
- * @param[in] enabled Whether to enable the text selection.
- */
- void SetSelectionEnabled(bool enabled);
-
- /**
- * @brief Whether the text selection is enabled or not.
- * @return True if the text selection is enabled
- */
- bool IsSelectionEnabled() const;
-
- /**
- * @brief Enable or disable the text selection using Shift key.
- * @param enabled Whether to enable the text selection using Shift key
- */
- void SetShiftSelectionEnabled(bool enabled);
-
- /**
- * @brief Whether the text selection using Shift key is enabled or not.
- * @return True if the text selection using Shift key is enabled
- */
- bool IsShiftSelectionEnabled() const;
-
- /**
- * @brief Enable or disable the grab handles for text selection.
- *
- * @param[in] enabled Whether to enable the grab handles
- */
- void SetGrabHandleEnabled(bool enabled);
-
- /**
- * @brief Returns whether the grab handles are enabled.
- *
- * @return True if the grab handles are enabled
- */
- bool IsGrabHandleEnabled() const;
-
- /**
- * @brief Enable or disable the grab handles for text selection.
- *
- * @param[in] enabled Whether to enable the grab handles
- */
- void SetGrabHandlePopupEnabled(bool enabled);
-
- /**
- * @brief Returns whether the grab handles are enabled.
- *
- * @return True if the grab handles are enabled
- */
- bool IsGrabHandlePopupEnabled() const;
-
- /**
- * @brief Sets input type to password
- *
- * @note The string is displayed hidden character
- *
- * @param[in] passwordInput True if password input is enabled.
- */
- void SetInputModePassword(bool passwordInput);
-
- /**
- * @brief Returns whether the input mode type is set as password.
- *
- * @return True if input mode type is password
- */
- bool IsInputModePassword();
-
- /**
- * @brief Sets the action when there is a double tap event on top of a text area with no text.
- *
- * @param[in] action The action to do.
- */
- void SetNoTextDoubleTapAction(NoTextTap::Action action);
-
- /**
- * @brief Retrieves the action when there is a double tap event on top of a text area with no text.
- *
- * @return The action to do.
- */
- NoTextTap::Action GetNoTextDoubleTapAction() const;
-
- /**
- * @briefSets the action when there is a long press event on top of a text area with no text.
- *
- * @param[in] action The action to do.
- */
- void SetNoTextLongPressAction(NoTextTap::Action action);
-
- /**
- * @brief Retrieves the action when there is a long press event on top of a text area with no text.
- *
- * @return The action to do.
- */
- NoTextTap::Action GetNoTextLongPressAction() const;
-
- /**
- * @brief Query if Underline settings were provided by string or map
- * @return bool true if set by string
- */
- bool IsUnderlineSetByString();
-
- /**
- * Set method underline setting were set by
- * @param[in] bool, true if set by string
- */
- void UnderlineSetByString(bool setByString);
-
- /**
- * @brief Query if shadow settings were provided by string or map
- * @return bool true if set by string
- */
- bool IsShadowSetByString();
-
- /**
- * Set method shadow setting were set by
- * @param[in] bool, true if set by string
- */
- void ShadowSetByString(bool setByString);
-
- /**
- * @brief Query if outline settings were provided by string or map
- * @return bool true if set by string
- */
- bool IsOutlineSetByString();
-
- /**
- * Set method outline setting were set by
- * @param[in] bool, true if set by string
- */
- void OutlineSetByString(bool setByString);
-
- /**
- * @brief Query if font style settings were provided by string or map
- * @return bool true if set by string
- */
- bool IsFontStyleSetByString();
-
- /**
- * Set method font style setting were set by
- * @param[in] bool, true if set by string
- */
- void FontStyleSetByString(bool setByString);
-
- /**
- * @brief Query if Strikethrough settings were provided by string or map
- * @return bool true if set by string
- */
- bool IsStrikethroughSetByString();
-
- /**
- * Set method Strikethrough setting were set by
- * @param[in] bool, true if set by string
- */
- void StrikethroughSetByString(bool setByString);
-
- /**
- * @brief Set the override used for strikethrough height, 0 indicates height will be supplied by font metrics
- *
- * @param[in] height The height in pixels of the strikethrough
- */
- void SetStrikethroughHeight(float height);
-
- /**
- * @brief Retrieves the override height of an strikethrough, 0 indicates height is supplied by font metrics
- *
- * @return The height of the strikethrough, or 0 if height is not overrided.
- */
- float GetStrikethroughHeight() const;
-
- /**
- * @brief Set the strikethrough color.
- *
- * @param[in] color color of strikethrough.
- */
- void SetStrikethroughColor(const Vector4& color);
-
- /**
- * @brief Retrieve the strikethrough color.
- *
- * @return The strikethrough color.
- */
- const Vector4& GetStrikethroughColor() const;
-
- /**
- * @brief Set the strikethrough enabled flag.
- *
- * @param[in] enabled The strikethrough enabled flag.
- */
- void SetStrikethroughEnabled(bool enabled);
-
- /**
- * @brief Returns whether the text has a strikethrough or not.
- *
- * @return The strikethrough state.
- */
- bool IsStrikethroughEnabled() const;
-
-public: // Update.
- /**
- * @brief Replaces any text previously set.
- *
- * @note This will be converted into UTF-32 when stored in the text model.
- * @param[in] text A string of UTF-8 characters.
- */
- void SetText(const std::string& text);
-
- /**
- * @brief Retrieve any text previously set.
- *
- * @param[out] text A string of UTF-8 characters.
- */
- void GetText(std::string& text) const;
-
- /**
- * @brief Replaces any placeholder text previously set.
- *
- * @param[in] type Different placeholder-text can be shown when the control is active/inactive.
- * @param[in] text A string of UTF-8 characters.
- */
- void SetPlaceholderText(PlaceholderType type, const std::string& text);
-
- /**
- * @brief Retrieve any placeholder text previously set.
- *
- * @param[in] type Different placeholder-text can be shown when the control is active/inactive.
- * @param[out] A string of UTF-8 characters.
- */
- void GetPlaceholderText(PlaceholderType type, std::string& text) const;
-
- /**
- * @ brief Update the text after a font change
- * @param[in] newDefaultFont The new font to change to
- */
- void UpdateAfterFontChange(const std::string& newDefaultFont);
-
- /**
- * @brief The method acquires currently selected text
- * @param selectedText variable to place selected text in
- */
- void RetrieveSelection(std::string& selectedText) const;
-
- /**
- * @brief The method sets selection in given range
- * @param start index of first character
- * @param end index of first character after selection
- */
- void SetSelection(int start, int end);
-
- /**
- * @brief This method retrieve indexes of current selection
- *
- * @return a pair, where first element is left index of selection and second is the right one
- */
- std::pair<int, int> GetSelectionIndexes() const;
-
- /**
- * Place string in system clipboard
- * @param source std::string
- */
- void CopyStringToClipboard(const std::string& source);
-
- /**
- * Place currently selected text in system clipboard
- * @param deleteAfterSending flag pointing if text should be deleted after sending to clipboard
- */
- void SendSelectionToClipboard(bool deleteAfterSending);
-
-public: // Default style & Input style
- /**
- * @brief Set the default font family.
- *
- * @param[in] defaultFontFamily The default font family.
- */
- void SetDefaultFontFamily(const std::string& defaultFontFamily);
-
- /**
- * @brief Retrieve the default font family.
- *
- * @return The default font family.
- */
- const std::string& GetDefaultFontFamily() const;
-
- /**
- * @brief Sets the placeholder text font family.
- * @param[in] placeholderTextFontFamily The placeholder text font family.
- */
- void SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily);
-
- /**
- * @brief Retrieves the placeholder text font family.
- *
- * @return The placeholder text font family
- */
- const std::string& GetPlaceholderFontFamily() const;
-
- /**
- * @brief Sets the default font weight.
- *
- * @param[in] weight The font weight.
- */
- void SetDefaultFontWeight(FontWeight weight);
-
- /**
- * @brief Whether the font's weight has been defined.
- */
- bool IsDefaultFontWeightDefined() const;
-
- /**
- * @brief Retrieves the default font weight.
- *
- * @return The default font weight.
- */
- FontWeight GetDefaultFontWeight() const;
-
- /**
- * @brief Sets the placeholder text font weight.
- *
- * @param[in] weight The font weight
- */
- void SetPlaceholderTextFontWeight(FontWeight weight);
-
- /**
- * @brief Whether the font's weight has been defined.
- *
- * @return True if the placeholder text font weight is defined
- */
- bool IsPlaceholderTextFontWeightDefined() const;
-
- /**
- * @brief Retrieves the placeholder text font weight.
- *
- * @return The placeholder text font weight
- */
- FontWeight GetPlaceholderTextFontWeight() const;
-
- /**
- * @brief Sets the default font width.
- *
- * @param[in] width The font width.
- */
- void SetDefaultFontWidth(FontWidth width);
-
- /**
- * @brief Whether the font's width has been defined.
- */
- bool IsDefaultFontWidthDefined() const;
-
- /**
- * @brief Retrieves the default font width.
- *
- * @return The default font width.
- */
- FontWidth GetDefaultFontWidth() const;
-
- /**
- * @brief Sets the placeholder text font width.
- *
- * @param[in] width The font width
- */
- void SetPlaceholderTextFontWidth(FontWidth width);
-
- /**
- * @brief Whether the font's width has been defined.
- *
- * @return True if the placeholder text font width is defined
- */
- bool IsPlaceholderTextFontWidthDefined() const;
-
- /**
- * @brief Retrieves the placeholder text font width.
- *
- * @return The placeholder text font width
- */
- FontWidth GetPlaceholderTextFontWidth() const;
-
- /**
- * @brief Sets the default font slant.
- *
- * @param[in] slant The font slant.
- */
- void SetDefaultFontSlant(FontSlant slant);
-
- /**
- * @brief Whether the font's slant has been defined.
- */
- bool IsDefaultFontSlantDefined() const;
-
- /**
- * @brief Retrieves the default font slant.
- *
- * @return The default font slant.
- */
- FontSlant GetDefaultFontSlant() const;
-
- /**
- * @brief Sets the placeholder text font slant.
- *
- * @param[in] slant The font slant
- */
- void SetPlaceholderTextFontSlant(FontSlant slant);
-
- /**
- * @brief Whether the font's slant has been defined.
- *
- * @return True if the placeholder text font slant is defined
- */
- bool IsPlaceholderTextFontSlantDefined() const;
-
- /**
- * @brief Retrieves the placeholder text font slant.
- *
- * @return The placeholder text font slant
- */
- FontSlant GetPlaceholderTextFontSlant() const;
-
- /**
- * @brief Set the default font size.
- *
- * @param[in] fontSize The default font size
- * @param[in] type The font size type is point size or pixel size
- */
- void SetDefaultFontSize(float fontSize, FontSizeType type);
-
- /**
- * @brief Retrieve the default point size.
- *
- * @param[in] type The font size type
- * @return The default point size.
- */
- float GetDefaultFontSize(FontSizeType type) const;
-
- /**
- * @brief Set the font size scale.
- *
- * @param[in] scale The font size scale
- */
- void SetFontSizeScale(float scale);
-
- /**
- * @brief Get the font size scale.
- *
- * @return The font size scale.
- */
- float GetFontSizeScale() const;
-
- /**
- * @brief Set the font size scale enabled flag.
- *
- * @param[in] enabled whether to enable the font size scale.
- */
- void SetFontSizeScaleEnabled(bool enabled);
-
- /**
- * @brief Returns whether the font size scale is enabled or not.
- *
- * @return @e true if the font size scale is enabled, otherwise returns @e false.
- */
- bool IsFontSizeScaleEnabled() const;
-
- /**
- * @brief Sets the Placeholder text font size.
- * @param[in] fontSize The placeholder text font size
- * @param[in] type The font size type is point size or pixel size
- */
- void SetPlaceholderTextFontSize(float fontSize, FontSizeType type);
-
- /**
- * @brief Retrieves the Placeholder text font size.
- * @param[in] type The font size type
- * @return The placeholder font size
- */
- float GetPlaceholderTextFontSize(FontSizeType type) const;
-
- /**
- * @brief Sets the text's default color.
- *
- * @param color The default color.
- */
- void SetDefaultColor(const Vector4& color);
-
- /**
- * @brief Retrieves the text's default color.
- *
- * @return The default color.
- */
- const Vector4& GetDefaultColor() const;
-
- /**
- * @brief Sets the user interaction enabled.
- *
- * @param enabled whether to enable the user interaction.
- */
- void SetUserInteractionEnabled(bool enabled);
-
- /**
- * @brief Whether the user interaction is enabled.
- *
- * @return true if the user interaction is enabled, false otherwise.
- */
- bool IsUserInteractionEnabled() const;
-
- /**
- * @brief Set the text color
- *
- * @param textColor The text color
- */
- void SetPlaceholderTextColor(const Vector4& textColor);
-
- /**
- * @brief Retrieve the text color
- *
- * @return The text color
- */
- const Vector4& GetPlaceholderTextColor() const;
-
- /**
- * @brief Set the shadow offset.
- *
- * @param[in] shadowOffset The shadow offset, 0,0 indicates no shadow.
- */
- void SetShadowOffset(const Vector2& shadowOffset);
-
- /**
- * @brief Retrieve the shadow offset.
- *
- * @return The shadow offset.
- */
- const Vector2& GetShadowOffset() const;
-
- /**
- * @brief Set the shadow color.
- *
- * @param[in] shadowColor The shadow color.
- */
- void SetShadowColor(const Vector4& shadowColor);
-
- /**
- * @brief Retrieve the shadow color.
- *
- * @return The shadow color.
- */
- const Vector4& GetShadowColor() const;
-
- /**
- * @brief Set the shadow blur radius.
- *
- * @param[in] shadowBlurRadius The shadow blur radius, 0,0 indicates no blur.
- */
- void SetShadowBlurRadius(const float& shadowBlurRadius);
-
- /**
- * @brief Retrieve the shadow blur radius.
- *
- * @return The shadow blur radius.
- */
- const float& GetShadowBlurRadius() const;
-
- /**
- * @brief Set the underline color.
- *
- * @param[in] color color of underline.
- */
- void SetUnderlineColor(const Vector4& color);
-
- /**
- * @brief Retrieve the underline color.
- *
- * @return The underline color.
- */
- const Vector4& GetUnderlineColor() const;
-
- /**
- * @brief Set the underline enabled flag.
- *
- * @param[in] enabled The underline enabled flag.
- */
- void SetUnderlineEnabled(bool enabled);
-
- /**
- * @brief Returns whether the text is underlined or not.
- *
- * @return The underline state.
- */
- bool IsUnderlineEnabled() const;
-
- /**
- * @brief Set the override used for underline height, 0 indicates height will be supplied by font metrics
- *
- * @param[in] height The height in pixels of the underline
- */
- void SetUnderlineHeight(float height);
-
- /**
- * @brief Retrieves the override height of an underline, 0 indicates height is supplied by font metrics
- *
- * @return The height of the underline, or 0 if height is not overrided.
- */
- float GetUnderlineHeight() const;
-
- /**
- * @brief Sets the underline type.
- * @param[in] type The underline type.
- */
- void SetUnderlineType(Text::Underline::Type type);
-
- /**
- * @brief Retrieve underline type.
- * @return The underline type.
- */
- Text::Underline::Type GetUnderlineType() const;
-
- /**
- * @brief Set the width of the dashes of the dashed underline.
- *
- * @param[in] width The width in pixels of the dashes of the dashed underline.
- */
- void SetDashedUnderlineWidth(float width);
-
- /**
- * @brief Retrieves the width of the dashes of the dashed underline.
- *
- * @return The width of the dashes of the dashed underline.
- */
- float GetDashedUnderlineWidth() const;
-
- /**
- * @brief Set the gap between the dashes of the dashed underline.
- *
- * @param[in] gap The gap between the dashes of the dashed underline.
- */
- void SetDashedUnderlineGap(float gap);
-
- /**
- * @brief Retrieves the gap between the dashes of the dashed underline.
- *
- * @return The The gap between the dashes of the dashed underline.
- */
- float GetDashedUnderlineGap() const;
-
- /**
- * @brief Set the outline color.
- *
- * @param[in] color color of outline.
- */
- void SetOutlineColor(const Vector4& color);
-
- /**
- * @brief Retrieve the outline color.
- *
- * @return The outline color.
- */
- const Vector4& GetOutlineColor() const;
-
- /**
- * @brief Set the outline width
- *
- * @param[in] width The width in pixels of the outline, 0 indicates no outline
- */
- void SetOutlineWidth(uint16_t width);
-
- /**
- * @brief Retrieves the width of an outline
- *
- * @return The width of the outline.
- */
- uint16_t GetOutlineWidth() const;
-
- /**
- * @brief Set the background color.
- *
- * @param[in] color color of background.
- */
- void SetBackgroundColor(const Vector4& color);
-
- /**
- * @brief Retrieve the background color.
- *
- * @return The background color.
- */
- const Vector4& GetBackgroundColor() const;
-
- /**
- * @brief Set the background enabled flag.
- *
- * @param[in] enabled The background enabled flag.
- */
- void SetBackgroundEnabled(bool enabled);
-
- /**
- * @brief Returns whether to enable text background or not.
- *
- * @return Whether text background is enabled.
- */
- bool IsBackgroundEnabled() const;
-
- /**
- * @brief Sets the emboss's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] embossProperties The emboss's properties string.
- */
- void SetDefaultEmbossProperties(const std::string& embossProperties);
-
- /**
- * @brief Retrieves the emboss's properties string.
- *
- * @return The emboss's properties string.
- */
- const std::string& GetDefaultEmbossProperties() const;
-
- /**
- * @brief Sets the outline's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] outlineProperties The outline's properties string.
- */
- void SetDefaultOutlineProperties(const std::string& outlineProperties);
-
- /**
- * @brief Retrieves the outline's properties string.
- *
- * @return The outline's properties string.
- */
- const std::string& GetDefaultOutlineProperties() const;
-
- /**
- * @brief Sets the default line spacing.
- *
- * @param[in] lineSpacing The line spacing.
- *
- * @return True if lineSpacing has been updated, false otherwise
- */
- bool SetDefaultLineSpacing(float lineSpacing);
-
- /**
- * @brief Retrieves the default line spacing.
- *
- * @return The line spacing.
- */
- float GetDefaultLineSpacing() const;
-
- /**
- * @brief Sets the default line size.
- *
- * @param[in] lineSize The line size.
- *
- * @return True if lineSize has been updated, false otherwise
- */
- bool SetDefaultLineSize(float lineSize);
-
- /**
- * @brief Retrieves the default line size.
- *
- * @return The line size.
- */
- float GetDefaultLineSize() const;
-
- /**
- * @brief Sets the relative line size to the original line size.
- *
- * @param[in] relativeLineSize The relativeline size.
- *
- * @return True if relativeLineSize has been updated, false otherwise
- */
- bool SetRelativeLineSize(float lineSize);
-
- /**
- * @brief Retrieves the relative line size.
- *
- * @return The relative line size.
- */
- float GetRelativeLineSize() const;
-
- /**
- * @brief Sets the input text's color.
- *
- * @param[in] color The input text's color.
- */
- void SetInputColor(const Vector4& color);
-
- /**
- * @brief Retrieves the input text's color.
- *
- * @return The input text's color.
- */
- const Vector4& GetInputColor() const;
-
- /**
- * @brief Sets the input text's font family name.
- *
- * @param[in] fontFamily The text's font family name.
- */
- void SetInputFontFamily(const std::string& fontFamily);
-
- /**
- * @brief Retrieves the input text's font family name.
- *
- * @return The input text's font family name.
- */
- const std::string& GetInputFontFamily() const;
-
- /**
- * @brief Sets the input font's weight.
- *
- * @param[in] weight The input font's weight.
- */
- void SetInputFontWeight(FontWeight weight);
-
- /**
- * @return Whether the font's weight has been defined.
- */
- bool IsInputFontWeightDefined() const;
-
- /**
- * @brief Retrieves the input font's weight.
- *
- * @return The input font's weight.
- */
- FontWeight GetInputFontWeight() const;
-
- /**
- * @brief Sets the input font's width.
- *
- * @param[in] width The input font's width.
- */
- void SetInputFontWidth(FontWidth width);
-
- /**
- * @return Whether the font's width has been defined.
- */
- bool IsInputFontWidthDefined() const;
-
- /**
- * @brief Retrieves the input font's width.
- *
- * @return The input font's width.
- */
- FontWidth GetInputFontWidth() const;
-
- /**
- * @brief Sets the input font's slant.
- *
- * @param[in] slant The input font's slant.
- */
- void SetInputFontSlant(FontSlant slant);
-
- /**
- * @return Whether the font's slant has been defined.
- */
- bool IsInputFontSlantDefined() const;
-
- /**
- * @brief Retrieves the input font's slant.
- *
- * @return The input font's slant.
- */
- FontSlant GetInputFontSlant() const;
-
- /**
- * @brief Sets the input font's point size.
- *
- * @param[in] size The input font's point size.
- */
- void SetInputFontPointSize(float size);
-
- /**
- * @brief Retrieves the input font's point size.
- *
- * @return The input font's point size.
- */
- float GetInputFontPointSize() const;
-
- /**
- * @brief Sets the input line spacing.
- *
- * @param[in] lineSpacing The line spacing.
- */
- void SetInputLineSpacing(float lineSpacing);
-
- /**
- * @brief Retrieves the input line spacing.
- *
- * @return The line spacing.
- */
- float GetInputLineSpacing() const;
-
- /**
- * @brief Sets the input shadow's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] shadowProperties The shadow's properties string.
- */
- void SetInputShadowProperties(const std::string& shadowProperties);
-
- /**
- * @brief Retrieves the input shadow's properties string.
- *
- * @return The shadow's properties string.
- */
- const std::string& GetInputShadowProperties() const;
-
- /**
- * @brief Sets the input underline's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] underlineProperties The underline's properties string.
- */
- void SetInputUnderlineProperties(const std::string& underlineProperties);
-
- /**
- * @brief Retrieves the input underline's properties string.
- *
- * @return The underline's properties string.
- */
- const std::string& GetInputUnderlineProperties() const;
-
- /**
- * @brief Sets the input emboss's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] embossProperties The emboss's properties string.
- */
- void SetInputEmbossProperties(const std::string& embossProperties);
-
- /**
- * @brief Retrieves the input emboss's properties string.
- *
- * @return The emboss's properties string.
- */
- const std::string& GetInputEmbossProperties() const;
-
- /**
- * @brief Sets input the outline's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] outlineProperties The outline's properties string.
- */
- void SetInputOutlineProperties(const std::string& outlineProperties);
-
- /**
- * @brief Retrieves the input outline's properties string.
- *
- * @return The outline's properties string.
- */
- const std::string& GetInputOutlineProperties() const;
-
- /**
- * @brief Sets the input strikethrough's properties string.
- *
- * @note The string is stored to be recovered.
- *
- * @param[in] strikethroughProperties The strikethrough's properties string.
- */
- void SetInputStrikethroughProperties(const std::string& strikethroughProperties);
-
- /**
- * @brief Retrieves the input strikethrough's properties string.
- *
- * @return The strikethrough's properties string.
- */
- const std::string& GetInputStrikethroughProperties() const;
-
- /**
- * @brief Set the control's interface.
- *
- * @param[in] controlInterface The control's interface.
- */
- void SetControlInterface(ControlInterface* controlInterface);
-
- /**
- * @brief Set the anchor control's interface.
- *
- * @param[in] anchorControlInterface The control's interface.
- */
- void SetAnchorControlInterface(AnchorControlInterface* anchorControlInterface);
-
- /**
- * @brief Sets the character spacing.
- *
- * @note A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
- *
- * @param[in] characterSpacing The character spacing.
- */
- void SetCharacterSpacing(float characterSpacing);
-
- /**
- * @brief Retrieves the character spacing.
- *
- * @note A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
- *
- * @return The character spacing.
- */
- const float GetCharacterSpacing() const;
-
-public: // Queries & retrieves.
- /**
- * @brief Return the layout engine.
- *
- * @return A reference to the layout engine.
- */
- Layout::Engine& GetLayoutEngine();
-
- /**
- * @brief Return a view of the text.
- *
- * @return A reference to the view.
- */
- View& GetView();
-
- /**
- * @copydoc Control::GetNaturalSize()
- */
- Vector3 GetNaturalSize();
-
- /**
- * @copydoc Control::GetHeightForWidth()
- */
- float GetHeightForWidth(float width);
-
- /**
- * @brief Calculates the point size for text for given layout()
- */
- void FitPointSizeforLayout(Size layoutSize);
-
- /**
- * @brief Checks if the point size fits within the layout size.
- *
- * @return Whether the point size fits within the layout size.
- */
- bool CheckForTextFit(float pointSize, Size& layoutSize);
-
- /**
- * @brief Retrieves the text's number of lines for a given width.
- * @param[in] width The width of the text's area.
- * @ return The number of lines.
- */
- int GetLineCount(float width);
-
- /**
- * @brief Retrieves the text's model.
- *
- * @return A pointer to the text's model.
- */
- const ModelInterface* const GetTextModel() const;
-
- /**
- * @brief Used to get scrolled distance by user input
- *
- * @return Distance from last scroll offset to new scroll offset
- */
- float GetScrollAmountByUserInput();
-
- /**
- * @brief Get latest scroll amount, control size and layout size
- *
- * This method is used to get information of control's scroll
- * @param[out] scrollPosition The current scrolled position
- * @param[out] controlHeight The size of a UI control
- * @param[out] layoutHeight The size of a bounding box to layout text within.
- *
- * @return Whether the text scroll position is changed or not after last update.
- */
- bool GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight);
-
- /**
- * @brief Used to set the hidden input option
- */
- void SetHiddenInputOption(const Property::Map& options);
-
- /**
- * @brief Used to get the hidden input option
- */
- void GetHiddenInputOption(Property::Map& options);
-
- /**
- * @brief Used to set the input filter option
- */
- void SetInputFilterOption(const Property::Map& options);
-
- /**
- * @brief Used to get the input filter option
- */
- void GetInputFilterOption(Property::Map& options);
-
- /**
- * @brief Sets the Placeholder Properties.
- *
- * @param[in] map The placeholder property map
- */
- void SetPlaceholderProperty(const Property::Map& map);
-
- /**
- * @brief Retrieves the Placeholder Property map.
- *
- * @param[out] map The property map
- */
- void GetPlaceholderProperty(Property::Map& map);
-
- /**
- * @brief Checks text direction.
- * @return The text direction.
- */
- Toolkit::DevelText::TextDirection::Type GetTextDirection();
-
- /**
- * @brief Retrieves vertical line alignment
- * @return The vertical line alignment
- */
- Toolkit::DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const;
-
- /**
- * @brief Sets vertical line alignment
- * @param[in] alignment The vertical line alignment for the text
- */
- void SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment);
-
- /**
- * @brief Retrieves ellipsis position
- * @return The ellipsis position
- */
- Toolkit::DevelText::EllipsisPosition::Type GetEllipsisPosition() const;
-
- /**
- * @brief Sets ellipsis position
- * @param[in] ellipsisPosition The ellipsis position for the text
- */
- void SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition);
-
- /**
- * @brief Retrieves ignoreSpaceAfterText value from model
- * @return The value of ignoreSpaceAfterText
- */
- bool IsIgnoreSpacesAfterText() const;
-
- /**
- * @brief Sets ignoreSpaceAfterText value to model
- * @param[in] ignore The value of ignoreSpacesAfterText for the text
- */
- void SetIgnoreSpacesAfterText(bool ignore);
-
- /**
- * @brief Sets SetMatchLayoutDirection value to model
- * @param[in] match The value of matchLayoutDirection for the text
- */
- void SetMatchLayoutDirection(DevelText::MatchLayoutDirection type);
-
- /**
- * @brief Retrieves matchLayoutDirection value from model
- * @return The value of matchLayoutDirection
- */
- DevelText::MatchLayoutDirection GetMatchLayoutDirection() const;
-
- /**
- * @brief Sets layoutDirection type value.
- * @param[in] layoutDirection The value of the layout direction type.
- */
- void SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection);
-
- /**
- * @brief Gets layoutDirection type value.
- * @param[in] actor The actor which will get the layout direction type.
- * @return The value of the layout direction type.
- */
- Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
-
- /**
- * @brief Get the rendered size of a specific text range.
- * if the requested text is at multilines, multiple sizes will be returned for each text located in a separate line.
- * if a line contains characters with different directions, multiple sizes will be returned for each block of contiguous characters with the same direction.
- *
- * @param[in] startIndex start index of the text requested to calculate size for.
- * @param[in] endIndex end index(included) of the text requested to calculate size for.
- * @return list of sizes of the reuested text.
- */
- Vector<Vector2> GetTextSize(CharacterIndex startIndex, CharacterIndex endIndex);
-
- /**
- * @brief Get the top/left rendered position of a specific text range.
- * if the requested text is at multilines, multiple positions will be returned for each text located in a separate line.
- * if a line contains characters with different directions, multiple positions will be returned for each block of contiguous characters with the same direction.
- *
- * @param[in] startIndex start index of the text requested to get position to.
- * @param[in] endIndex end index(included) of the text requested to get position to.
- * @return list of positions of the requested text.
- */
- Vector<Vector2> GetTextPosition(CharacterIndex startIndex, CharacterIndex endIndex);
-
- /**
- * @brief Gets the bounding box of a specific text range.
- *
- * @param[in] startIndex start index of the text requested to get bounding box to.
- * @param[in] endIndex end index(included) of the text requested to get bounding box to.
- * @return bounding box of the requested text.
- */
- Rect<> GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex);
-
- /**
- * @brief Sets the layout direction changed.
- */
- void ChangedLayoutDirection();
-
- /**
- * @brief Retrieves if showing real text or not.
- * @return The value of showing real text.
- */
- bool IsShowingRealText() const;
-
-public: // Relayout.
- /**
- * @brief Triggers a relayout which updates View (if necessary).
- *
- * @note UI Controls are expected to minimize calls to this method e.g. call once after size negotiation.
- * @param[in] size A the size of a bounding box to layout text within.
- * @param[in] layoutDirection The direction of the system language.
- *
- * @return Whether the text model or decorations were updated.
- */
- UpdateTextType Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection = Dali::LayoutDirection::LEFT_TO_RIGHT);
-
- /**
- * @brief Request a relayout using the ControlInterface.
- */
- void RequestRelayout();
-
-public: // Input style change signals.
- /**
- * @return Whether the queue of input style changed signals is empty.
- */
- bool IsInputStyleChangedSignalsQueueEmpty();
-
- /**
- * @brief Process all pending input style changed signals.
- *
- * Calls the Text::ControlInterface::InputStyleChanged() method which is overriden by the
- * text controls. Text controls may send signals to state the input style has changed.
- */
- void ProcessInputStyleChangedSignals();
-
-public: // Text-input Event Queuing.
- /**
- * @brief Called by editable UI controls when keyboard focus is gained.
- */
- void KeyboardFocusGainEvent();
-
- /**
- * @brief Called by editable UI controls when focus is lost.
- */
- void KeyboardFocusLostEvent();
-
- /**
- * @brief Called by editable UI controls when key events are received.
- *
- * @param[in] event The key event.
- * @param[in] type Used to distinguish between regular key events and InputMethodContext events.
- */
- bool KeyEvent(const Dali::KeyEvent& event);
-
- /**
- * @brief Called by anchor when a tap gesture occurs.
- * @param[in] x The x position relative to the top-left of the parent control.
- * @param[in] y The y position relative to the top-left of the parent control.
- */
- void AnchorEvent(float x, float y);
-
- /**
- * @brief Called by editable UI controls when a tap gesture occurs.
- * @param[in] tapCount The number of taps.
- * @param[in] x The x position relative to the top-left of the parent control.
- * @param[in] y The y position relative to the top-left of the parent control.
- */
- void TapEvent(unsigned int tapCount, float x, float y);
-
- /**
- * @brief Called by editable UI controls when a pan gesture occurs.
- *
- * @param[in] state The state of the gesture.
- * @param[in] displacement This distance panned since the last pan gesture.
- */
- void PanEvent(GestureState state, const Vector2& displacement);
-
- /**
- * @brief Called by editable UI controls when a long press gesture occurs.
- *
- * @param[in] state The state of the gesture.
- * @param[in] x The x position relative to the top-left of the parent control.
- * @param[in] y The y position relative to the top-left of the parent control.
- */
- void LongPressEvent(GestureState state, float x, float y);
-
- /**
- * @brief Used to get the Primary cursor position.
- *
- * @return Primary cursor position.
- */
- CharacterIndex GetPrimaryCursorPosition() const;
-
- /**
- * @brief Used to set the Primary cursor position.
- *
- * @param[in] index for the Primary cursor position.
- * @param[in] focused true if UI control has gained focus to receive key event, false otherwise.
- * @return[in] true if cursor position changed, false otherwise.
- */
- bool SetPrimaryCursorPosition(CharacterIndex index, bool focused);
-
- /**
- * @brief Creates a selection event.
- *
- * It could be called from the TapEvent (double tap) or when the text selection popup's sellect all button is pressed.
- *
- * @param[in] x The x position relative to the top-left of the parent control.
- * @param[in] y The y position relative to the top-left of the parent control.
- * @param[in] selection type like the whole text is selected or unselected.
- */
- void SelectEvent(float x, float y, SelectionType selection);
-
- /**
- * @copydoc Text::SelectableControlInterface::SetTextSelectionRange()
- */
- void SetTextSelectionRange(const uint32_t* start, const uint32_t* end);
-
- /**
- * @copydoc Text::SelectableControlInterface::GetTextSelectionRange()
- */
- Uint32Pair GetTextSelectionRange() const;
-
- /**
- * @copydoc Text::SelectableControlInterface::SelectWholeText()
- */
- void SelectWholeText();
-
- /**
- * @copydoc Text::EditableControlInterface::CopyText()
- */
- string CopyText();
-
- /**
- * @copydoc Text::EditableControlInterface::CutText()
- */
- string CutText();
-
- /**
- * @copydoc Text::EditableControlInterface::PasteText()
- */
- void PasteText();
-
- /**
- * @copydoc Text::SelectableControlInterface::SelectNone()
- */
- void SelectNone();
-
- /**
- * @copydoc Text::SelectableControlInterface::SelectText()
- */
- void SelectText(const uint32_t start, const uint32_t end);
-
- /**
- * @copydoc Text::SelectableControlInterface::GetSelectedText()
- */
- string GetSelectedText() const;
-
- /**
- * @copydoc Text::EditableControlInterface::IsEditable()
- */
- virtual bool IsEditable() const;
-
- /**
- * @copydoc Text::EditableControlInterface::SetEditable()
- */
- virtual void SetEditable(bool editable);
-
- /**
- * @copydoc Dali::Toolkit::Internal::TextEditor::ScrollBy()
- */
- virtual void ScrollBy(Vector2 scroll);
-
- /**
- * @brief Whether the text is scrollable.
- * @return Returns true if the text is scrollable.
- */
- bool IsScrollable(const Vector2& displacement);
-
- /**
- * @copydoc Dali::Toolkit::Internal::TextEditor::GetHorizontalScrollPosition()
- */
- float GetHorizontalScrollPosition();
-
- /**
- * @copydoc Dali::Toolkit::Internal::TextEditor::GetVerticalScrollPosition()
- */
- float GetVerticalScrollPosition();
-
- /**
- * @brief Event received from input method context
- *
- * @param[in] inputMethodContext The input method context.
- * @param[in] inputMethodContextEvent The event received.
- * @return A data struture indicating if update is needed, cursor position and current text.
- */
- InputMethodContext::CallbackData OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent);
-
- /**
- * @brief Event from Clipboard notifying an Item has been selected for pasting
- */
- void PasteClipboardItemEvent();
-
- /**
- * @brief Return true when text control should clear key input focus when escape key is pressed.
- *
- * @return Whether text control should clear key input focus or not when escape key is pressed.
- */
- bool ShouldClearFocusOnEscape() const;
-
- /**
- * @brief Create an actor that renders the text background color
- *
- * @return the created actor or an empty handle if no background color needs to be rendered.
- */
- Actor CreateBackgroundActor();
-
- /**
- * @brief Used to reset the cursor position after setting a new text.
- *
- * @param[in] cursorIndex Where to place the cursor.
- */
- void ResetCursorPosition(CharacterIndex cursorIndex);
-
- /**
- * @brief The method acquires current position of cursor
- * @return unsigned value with cursor position
- */
- CharacterIndex GetCursorPosition();
-
- /**
- * @brief Resets a provided vector with actors that marks the position of anchors in markup enabled text
- *
- * @param[out] anchorActors the vector of actor (empty collection if no anchors available).
- */
- void GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors);
-
- /**
- * @brief Return an index of first anchor in the anchor vector whose boundaries includes given character offset
- *
- * @param[in] characterOffset A position in text coords.
- *
- * @return the index in anchor vector (-1 if an anchor not found)
- */
- int GetAnchorIndex(size_t characterOffset);
-
-protected: // Inherit from Text::Decorator::ControllerInterface.
- /**
- * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::GetTargetSize()
- */
- void GetTargetSize(Vector2& targetSize) override;
-
- /**
- * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::AddDecoration()
- */
- void AddDecoration(Actor& actor, DecorationType type, bool needsClipping) override;
-
- /**
- * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::DecorationEvent()
- */
- void DecorationEvent(HandleType handle, HandleState state, float x, float y) override;
-
-protected: // Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
- /**
- * @copydoc Dali::Toolkit::TextSelectionPopup::TextPopupButtonCallbackInterface::TextPopupButtonTouched()
- */
- void TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button) override;
-
-protected: // Inherit from HiddenText.
- /**
- * @brief Invoked from HiddenText when showing time of the last character was expired
- */
- void DisplayTimeExpired() override;
-
-private: // Private contructors & copy operator.
- /**
- * @brief Private constructor.
- */
- Controller()
- : Controller(nullptr, nullptr, nullptr, nullptr)
- {
- }
-
- /**
- * @brief Private constructor.
- */
- Controller(ControlInterface* controlInterface)
- : Controller(controlInterface, nullptr, nullptr, nullptr)
- {
- }
-
- /**
- * @brief Private constructor.
- */
- Controller(ControlInterface* controlInterface,
- EditableControlInterface* editableControlInterface,
- SelectableControlInterface* selectableControlInterface,
- AnchorControlInterface* anchorControlInterface);
-
- Controller(const Controller& handle) = delete;
- Controller& operator=(const Controller& handle) = delete;
-
-protected: // Destructor.
- /**
- * @brief A reference counted object may only be deleted by calling Unreference().
- */
- virtual ~Controller();
-
-public:
- struct Impl; ///< Made public for testing purposes
-
-private:
- struct EventHandler;
- struct InputFontHandler;
- struct InputProperties;
- struct PlaceholderHandler;
- struct Relayouter;
- struct TextUpdater;
-
- Impl* mImpl;
-};
-
-} // namespace Dali::Toolkit::Text
-
-#endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
#include <dali-toolkit/internal/text/property-string-parser.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
*/
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/public-api/text/text-enumerations.h>
#include <dali/devel-api/scripting/scripting.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.
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
#include <dali-toolkit/internal/text/property-string-parser.h>
namespace Dali
#define DALI_TOOLKIT_INTERNAL_TEXT_FONT_STYLE_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.
#include <dali/devel-api/scripting/scripting.h>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
namespace Dali
{
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
-#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
+#include <dali-toolkit/internal/text/controller/text-controller-impl-event-handler.h>
using namespace Dali;
#define DALI_TOOLKIT_TEXT_SELECTION_HANDLE_CONTROLLER_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.
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
namespace Dali
{
#include <dali/public-api/rendering/visual-renderer.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
-#include <dali-toolkit/internal/text/text-controller.h>
#include <dali-toolkit/internal/visuals/text-visual-shader-factory.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>