Merge "Add ApplyCustomFragmentPrefix" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-label-impl.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/adaptor-framework/image-loading.h>
24 #include <dali/devel-api/common/stage.h>
25 #include <dali/devel-api/object/property-helper-devel.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/public-api/common/dali-common.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
32 #include <dali-toolkit/devel-api/text/rendering-backend.h>
33 #include <dali-toolkit/internal/styling/style-manager-impl.h>
34 #include <dali-toolkit/internal/text/property-string-parser.h>
35 #include <dali-toolkit/internal/text/rendering/text-backend.h>
36 #include <dali-toolkit/internal/text/text-definitions.h>
37 #include <dali-toolkit/internal/text/text-effects-style.h>
38 #include <dali-toolkit/internal/text/text-font-style.h>
39 #include <dali-toolkit/internal/text/text-view.h>
40 #include <dali-toolkit/public-api/text/text-enumerations.h>
41
42 #include <dali-toolkit/devel-api/controls/control-devel.h>
43 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
44 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
45 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
46 #include <dali-toolkit/public-api/align-enumerations.h>
47 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
48 #include <dali-toolkit/public-api/visuals/visual-properties.h>
49
50 // DEVEL INCLUDES
51 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
52
53 using namespace Dali::Toolkit::Text;
54
55 namespace Dali
56 {
57 namespace Toolkit
58 {
59 namespace Internal
60 {
61 namespace
62 {
63 const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT_RENDERING_BACKEND;
64
65 /**
66  * @brief How the text visual should be aligned vertically inside the control.
67  *
68  * 0.0f aligns the text to the top, 0.5f aligns the text to the center, 1.0f aligns the text to the bottom.
69  * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
70  */
71 const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] =
72   {
73     0.0f, // VerticalAlignment::TOP
74     0.5f, // VerticalAlignment::CENTER
75     1.0f  // VerticalAlignment::BOTTOM
76 };
77
78 const std::string TEXT_FIT_ENABLE_KEY("enable");
79 const std::string TEXT_FIT_MIN_SIZE_KEY("minSize");
80 const std::string TEXT_FIT_MAX_SIZE_KEY("maxSize");
81 const std::string TEXT_FIT_STEP_SIZE_KEY("stepSize");
82 const std::string TEXT_FIT_FONT_SIZE_TYPE_KEY("fontSizeType");
83
84 #if defined(DEBUG_ENABLED)
85 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
86 #endif
87
88 const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
89   {
90     {"IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE},
91     {"FINISH_LOOP", Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP},
92 };
93 const unsigned int AUTO_SCROLL_STOP_MODE_TABLE_COUNT = sizeof(AUTO_SCROLL_STOP_MODE_TABLE) / sizeof(AUTO_SCROLL_STOP_MODE_TABLE[0]);
94
95 // Type registration
96 BaseHandle Create()
97 {
98   return Toolkit::TextLabel::New();
99 }
100
101 // clang-format off
102 // Setup properties, signals and actions using the type-registry.
103 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextLabel, Toolkit::Control, Create);
104
105 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "text",                         STRING,  TEXT                           )
106 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "fontFamily",                   STRING,  FONT_FAMILY                    )
107 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "fontStyle",                    MAP,     FONT_STYLE                     )
108 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "pointSize",                    FLOAT,   POINT_SIZE                     )
109 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "multiLine",                    BOOLEAN, MULTI_LINE                     )
110 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "horizontalAlignment",          STRING,  HORIZONTAL_ALIGNMENT           )
111 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "verticalAlignment",            STRING,  VERTICAL_ALIGNMENT             )
112 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "enableMarkup",                 BOOLEAN, ENABLE_MARKUP                  )
113 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "enableAutoScroll",             BOOLEAN, ENABLE_AUTO_SCROLL             )
114 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "autoScrollSpeed",              INTEGER, AUTO_SCROLL_SPEED              )
115 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "autoScrollLoopCount",          INTEGER, AUTO_SCROLL_LOOP_COUNT         )
116 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "autoScrollGap",                FLOAT,   AUTO_SCROLL_GAP                )
117 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "lineSpacing",                  FLOAT,   LINE_SPACING                   )
118 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "underline",                    MAP,     UNDERLINE                      )
119 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "shadow",                       MAP,     SHADOW                         )
120 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "emboss",                       MAP,     EMBOSS                         )
121 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "outline",                      MAP,     OUTLINE                        )
122 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "pixelSize",                    FLOAT,   PIXEL_SIZE                     )
123 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "ellipsis",                     BOOLEAN, ELLIPSIS                       )
124 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "autoScrollLoopDelay",          FLOAT,   AUTO_SCROLL_LOOP_DELAY         )
125 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "autoScrollStopMode",           STRING,  AUTO_SCROLL_STOP_MODE          )
126 DALI_PROPERTY_REGISTRATION_READ_ONLY(Toolkit,       TextLabel, "lineCount",                    INTEGER, LINE_COUNT                     )
127 DALI_PROPERTY_REGISTRATION(Toolkit,                 TextLabel, "lineWrapMode",                 INTEGER, LINE_WRAP_MODE                 )
128 DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY(Toolkit, TextLabel, "textDirection",                INTEGER, TEXT_DIRECTION                 )
129 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "verticalLineAlignment",        INTEGER, VERTICAL_LINE_ALIGNMENT        )
130 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "textBackground",               MAP,     BACKGROUND                     )
131 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "ignoreSpacesAfterText",        BOOLEAN, IGNORE_SPACES_AFTER_TEXT       )
132 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "matchSystemLanguageDirection", BOOLEAN, MATCH_SYSTEM_LANGUAGE_DIRECTION)
133 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "textFit",                      MAP,     TEXT_FIT                       )
134 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "minLineSize",                  FLOAT,   MIN_LINE_SIZE                  )
135 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "renderingBackend",             INTEGER, RENDERING_BACKEND              )
136 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "fontSizeScale",                FLOAT,   FONT_SIZE_SCALE                )
137 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "ellipsisPosition",             INTEGER, ELLIPSIS_POSITION              )
138
139 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, TextLabel, "textColor",      Color::BLACK,     TEXT_COLOR   )
140 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit,    TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR, 0)
141 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit,    TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1)
142 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit,    TextLabel, "textColorBlue",  TEXT_COLOR_BLUE,  TEXT_COLOR, 2)
143 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit,    TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR, 3)
144
145 DALI_SIGNAL_REGISTRATION(Toolkit, TextLabel, "anchorClicked", SIGNAL_ANCHOR_CLICKED)
146
147 DALI_TYPE_REGISTRATION_END()
148 // clang-format on
149
150 /// Parses the property map for the TEXT_FIT property
151 void ParseTextFitProperty(Text::ControllerPtr& controller, const Property::Map* propertiesMap)
152 {
153   if(propertiesMap && !propertiesMap->Empty())
154   {
155     bool                     enabled      = false;
156     float                    minSize      = 0.f;
157     float                    maxSize      = 0.f;
158     float                    stepSize     = 0.f;
159     bool                     isMinSizeSet = false, isMaxSizeSet = false, isStepSizeSet = false;
160     Controller::FontSizeType type = Controller::FontSizeType::POINT_SIZE;
161
162     const unsigned int numberOfItems = propertiesMap->Count();
163
164     // Parses and applies
165     for(unsigned int index = 0u; index < numberOfItems; ++index)
166     {
167       const KeyValuePair& valueGet = propertiesMap->GetKeyValue(index);
168
169       if((Controller::TextFitInfo::Property::TEXT_FIT_ENABLE == valueGet.first.indexKey) || (TEXT_FIT_ENABLE_KEY == valueGet.first.stringKey))
170       {
171         /// Enable key.
172         enabled = valueGet.second.Get<bool>();
173       }
174       else if((Controller::TextFitInfo::Property::TEXT_FIT_MIN_SIZE == valueGet.first.indexKey) || (TEXT_FIT_MIN_SIZE_KEY == valueGet.first.stringKey))
175       {
176         /// min size.
177         minSize      = valueGet.second.Get<float>();
178         isMinSizeSet = true;
179       }
180       else if((Controller::TextFitInfo::Property::TEXT_FIT_MAX_SIZE == valueGet.first.indexKey) || (TEXT_FIT_MAX_SIZE_KEY == valueGet.first.stringKey))
181       {
182         /// max size.
183         maxSize      = valueGet.second.Get<float>();
184         isMaxSizeSet = true;
185       }
186       else if((Controller::TextFitInfo::Property::TEXT_FIT_STEP_SIZE == valueGet.first.indexKey) || (TEXT_FIT_STEP_SIZE_KEY == valueGet.first.stringKey))
187       {
188         /// step size.
189         stepSize      = valueGet.second.Get<float>();
190         isStepSizeSet = true;
191       }
192       else if((Controller::TextFitInfo::Property::TEXT_FIT_FONT_SIZE_TYPE == valueGet.first.indexKey) || (TEXT_FIT_FONT_SIZE_TYPE_KEY == valueGet.first.stringKey))
193       {
194         if("pixelSize" == valueGet.second.Get<std::string>())
195         {
196           type = Controller::FontSizeType::PIXEL_SIZE;
197         }
198       }
199     }
200
201     controller->SetTextFitEnabled(enabled);
202     if(isMinSizeSet)
203     {
204       controller->SetTextFitMinSize(minSize, type);
205     }
206     if(isMaxSizeSet)
207     {
208       controller->SetTextFitMaxSize(maxSize, type);
209     }
210     if(isStepSizeSet)
211     {
212       controller->SetTextFitStepSize(stepSize, type);
213     }
214   }
215 }
216
217 } // namespace
218
219 Toolkit::TextLabel TextLabel::New()
220 {
221   // Create the implementation, temporarily owned by this handle on stack
222   IntrusivePtr<TextLabel> impl = new TextLabel();
223
224   // Pass ownership to CustomActor handle
225   Toolkit::TextLabel handle(*impl);
226
227   // Second-phase init of the implementation
228   // This can only be done after the CustomActor connection has been made...
229   impl->Initialize();
230
231   return handle;
232 }
233
234 void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
235 {
236   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast(Dali::BaseHandle(object));
237
238   if(label)
239   {
240     TextLabel& impl(GetImpl(label));
241     DALI_ASSERT_ALWAYS(impl.mController && "No text contoller");
242
243     switch(index)
244     {
245       case Toolkit::DevelTextLabel::Property::RENDERING_BACKEND:
246       {
247         int backend = value.Get<int>();
248
249 #ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
250         if(DevelText::RENDERING_VECTOR_BASED == backend)
251         {
252           backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
253         }
254 #endif
255         if(impl.mRenderingBackend != backend)
256         {
257           impl.mRenderingBackend = backend;
258           impl.mTextUpdateNeeded = true;
259
260           // When using the vector-based rendering, the size of the GLyphs are different
261           TextAbstraction::GlyphType glyphType = (DevelText::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
262           impl.mController->SetGlyphType(glyphType);
263         }
264         break;
265       }
266       case Toolkit::TextLabel::Property::TEXT:
267       {
268         impl.mController->SetText(value.Get<std::string>());
269         break;
270       }
271       case Toolkit::TextLabel::Property::FONT_FAMILY:
272       {
273         const std::string& fontFamily = value.Get<std::string>();
274
275         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str());
276         impl.mController->SetDefaultFontFamily(fontFamily);
277         break;
278       }
279       case Toolkit::TextLabel::Property::FONT_STYLE:
280       {
281         SetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
282         break;
283       }
284       case Toolkit::TextLabel::Property::POINT_SIZE:
285       {
286         const float pointSize = value.Get<float>();
287
288         if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE), pointSize))
289         {
290           impl.mController->SetDefaultFontSize(pointSize, Text::Controller::POINT_SIZE);
291         }
292         break;
293       }
294       case Toolkit::TextLabel::Property::MULTI_LINE:
295       {
296         impl.mController->SetMultiLineEnabled(value.Get<bool>());
297         break;
298       }
299       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
300       {
301         Text::HorizontalAlignment::Type alignment(static_cast<Text::HorizontalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
302         if(Text::GetHorizontalAlignmentEnumeration(value, alignment))
303         {
304           impl.mController->SetHorizontalAlignment(alignment);
305         }
306         break;
307       }
308       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
309       {
310         Toolkit::Text::VerticalAlignment::Type alignment(static_cast<Text::VerticalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
311         if(Text::GetVerticalAlignmentEnumeration(value, alignment))
312         {
313           impl.mController->SetVerticalAlignment(alignment);
314         }
315         break;
316       }
317       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
318       {
319         const bool enableMarkup = value.Get<bool>();
320         impl.mController->SetMarkupProcessorEnabled(enableMarkup);
321         break;
322       }
323       case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
324       {
325         const bool enableAutoScroll = value.Get<bool>();
326         // If request to auto scroll is the same as current state then do nothing.
327         if(enableAutoScroll != impl.mController->IsAutoScrollEnabled())
328         {
329           // If request is disable (false) and auto scrolling is enabled then need to stop it
330           if(enableAutoScroll == false)
331           {
332             if(impl.mTextScroller)
333             {
334               impl.mTextScroller->StopScrolling();
335             }
336           }
337           // If request is enable (true) then start autoscroll as not already running
338           else
339           {
340             impl.mController->SetAutoScrollEnabled(enableAutoScroll);
341           }
342         }
343         break;
344       }
345       case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
346       {
347         Text::TextScrollerPtr                        textScroller = impl.GetTextScroller();
348         Toolkit::TextLabel::AutoScrollStopMode::Type stopMode     = textScroller->GetStopMode();
349         if(Scripting::GetEnumerationProperty<Toolkit::TextLabel::AutoScrollStopMode::Type>(value,
350                                                                                            AUTO_SCROLL_STOP_MODE_TABLE,
351                                                                                            AUTO_SCROLL_STOP_MODE_TABLE_COUNT,
352                                                                                            stopMode))
353         {
354           textScroller->SetStopMode(stopMode);
355         }
356         break;
357       }
358       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
359       {
360         impl.GetTextScroller()->SetSpeed(value.Get<int>());
361         break;
362       }
363       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
364       {
365         impl.GetTextScroller()->SetLoopCount(value.Get<int>());
366         break;
367       }
368       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
369       {
370         impl.GetTextScroller()->SetLoopDelay(value.Get<float>());
371         break;
372       }
373       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
374       {
375         impl.GetTextScroller()->SetGap(value.Get<float>());
376         break;
377       }
378       case Toolkit::TextLabel::Property::LINE_SPACING:
379       {
380         const float lineSpacing = value.Get<float>();
381         impl.mTextUpdateNeeded  = impl.mController->SetDefaultLineSpacing(lineSpacing) || impl.mTextUpdateNeeded;
382         break;
383       }
384       case Toolkit::TextLabel::Property::UNDERLINE:
385       {
386         impl.mTextUpdateNeeded = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded;
387         break;
388       }
389       case Toolkit::TextLabel::Property::SHADOW:
390       {
391         impl.mTextUpdateNeeded = SetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded;
392         break;
393       }
394       case Toolkit::TextLabel::Property::EMBOSS:
395       {
396         impl.mTextUpdateNeeded = SetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded;
397         break;
398       }
399       case Toolkit::TextLabel::Property::OUTLINE:
400       {
401         impl.mTextUpdateNeeded = SetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded;
402         break;
403       }
404       case Toolkit::TextLabel::Property::PIXEL_SIZE:
405       {
406         const float pixelSize = value.Get<float>();
407         DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize);
408
409         if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE), pixelSize))
410         {
411           impl.mController->SetDefaultFontSize(pixelSize, Text::Controller::PIXEL_SIZE);
412         }
413         break;
414       }
415       case Toolkit::TextLabel::Property::ELLIPSIS:
416       {
417         const bool ellipsis = value.Get<bool>();
418         DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis);
419
420         impl.mController->SetTextElideEnabled(ellipsis);
421         break;
422       }
423       case Toolkit::TextLabel::Property::LINE_WRAP_MODE:
424       {
425         Text::LineWrap::Mode lineWrapMode(static_cast<Text::LineWrap::Mode>(-1)); // Set to invalid value to ensure a valid mode does get set
426         if(GetLineWrapModeEnumeration(value, lineWrapMode))
427         {
428           DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode);
429           impl.mController->SetLineWrapMode(lineWrapMode);
430         }
431         break;
432       }
433       case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT:
434       {
435         if(impl.mController->GetTextModel())
436         {
437           DevelText::VerticalLineAlignment::Type alignment = static_cast<DevelText::VerticalLineAlignment::Type>(value.Get<int>());
438
439           impl.mController->SetVerticalLineAlignment(alignment);
440
441           // Property doesn't affect the layout, only Visual must be updated
442           TextVisual::EnableRendererUpdate(impl.mVisual);
443
444           // No need to trigger full re-layout. Instead call UpdateRenderer() directly
445           TextVisual::UpdateRenderer(impl.mVisual);
446         }
447         break;
448       }
449       case Toolkit::DevelTextLabel::Property::BACKGROUND:
450       {
451         impl.mTextUpdateNeeded = SetBackgroundProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded;
452         break;
453       }
454       case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
455       {
456         impl.mController->SetIgnoreSpacesAfterText(value.Get<bool>());
457         break;
458       }
459       case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
460       {
461         impl.mController->SetMatchLayoutDirection(value.Get<bool>() ? DevelText::MatchLayoutDirection::LOCALE : DevelText::MatchLayoutDirection::CONTENTS);
462         break;
463       }
464       case Toolkit::DevelTextLabel::Property::TEXT_FIT:
465       {
466         ParseTextFitProperty(impl.mController, value.GetMap());
467         break;
468       }
469       case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
470       {
471         const float lineSize   = value.Get<float>();
472         impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize(lineSize) || impl.mTextUpdateNeeded;
473         break;
474       }
475       case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE:
476       {
477         const float scale = value.Get<float>();
478         DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale);
479
480         if(!Equals(impl.mController->GetFontSizeScale(), scale))
481         {
482           impl.mController->SetFontSizeScale(scale);
483         }
484         break;
485       }
486       case Toolkit::DevelTextLabel::Property::ELLIPSIS_POSITION:
487       {
488         DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
489         if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
490         {
491           DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
492           impl.mController->SetEllipsisPosition(ellipsisPositionType);
493         }
494         break;
495       }
496     }
497
498     // Request relayout when text update is needed. It's necessary to call it
499     // as changing the property not via UI interaction brings no effect if only
500     // the mTextUpdateNeeded is changed.
501     if(impl.mTextUpdateNeeded)
502     {
503       // need to request relayout as size of text may have changed
504       impl.RequestTextRelayout();
505     }
506   }
507 }
508
509 Text::ControllerPtr TextLabel::GetTextController()
510 {
511   return mController;
512 }
513
514 Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index)
515 {
516   Property::Value value;
517
518   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast(Dali::BaseHandle(object));
519
520   if(label)
521   {
522     TextLabel& impl(GetImpl(label));
523     DALI_ASSERT_DEBUG(impl.mController && "No text contoller");
524
525     switch(index)
526     {
527       case Toolkit::DevelTextLabel::Property::RENDERING_BACKEND:
528       {
529         value = impl.mRenderingBackend;
530         break;
531       }
532       case Toolkit::TextLabel::Property::TEXT:
533       {
534         std::string text;
535         impl.mController->GetText(text);
536         value = text;
537         break;
538       }
539       case Toolkit::TextLabel::Property::FONT_FAMILY:
540       {
541         value = impl.mController->GetDefaultFontFamily();
542         break;
543       }
544       case Toolkit::TextLabel::Property::FONT_STYLE:
545       {
546         GetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
547         break;
548       }
549       case Toolkit::TextLabel::Property::POINT_SIZE:
550       {
551         value = impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE);
552         break;
553       }
554       case Toolkit::TextLabel::Property::MULTI_LINE:
555       {
556         value = impl.mController->IsMultiLineEnabled();
557         break;
558       }
559       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
560       {
561         const char* name = Text::GetHorizontalAlignmentString(impl.mController->GetHorizontalAlignment());
562
563         if(name)
564         {
565           value = std::string(name);
566         }
567         break;
568       }
569       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
570       {
571         const char* name = Text::GetVerticalAlignmentString(impl.mController->GetVerticalAlignment());
572         if(name)
573         {
574           value = std::string(name);
575         }
576         break;
577       }
578       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
579       {
580         value = impl.mController->IsMarkupProcessorEnabled();
581         break;
582       }
583       case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
584       {
585         value = impl.mController->IsAutoScrollEnabled();
586         break;
587       }
588       case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
589       {
590         if(impl.mTextScroller)
591         {
592           const char* mode = Scripting::GetEnumerationName<Toolkit::TextLabel::AutoScrollStopMode::Type>(impl.mTextScroller->GetStopMode(),
593                                                                                                          AUTO_SCROLL_STOP_MODE_TABLE,
594                                                                                                          AUTO_SCROLL_STOP_MODE_TABLE_COUNT);
595           if(mode)
596           {
597             value = std::string(mode);
598           }
599         }
600         break;
601       }
602       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
603       {
604         if(impl.mTextScroller)
605         {
606           value = impl.mTextScroller->GetSpeed();
607         }
608         break;
609       }
610       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
611       {
612         if(impl.mTextScroller)
613         {
614           value = impl.mTextScroller->GetLoopCount();
615         }
616         break;
617       }
618       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
619       {
620         if(impl.mTextScroller)
621         {
622           value = impl.mTextScroller->GetLoopDelay();
623         }
624         break;
625       }
626       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
627       {
628         if(impl.mTextScroller)
629         {
630           value = impl.mTextScroller->GetGap();
631         }
632         break;
633       }
634       case Toolkit::TextLabel::Property::LINE_SPACING:
635       {
636         value = impl.mController->GetDefaultLineSpacing();
637         break;
638       }
639       case Toolkit::TextLabel::Property::UNDERLINE:
640       {
641         GetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
642         break;
643       }
644       case Toolkit::TextLabel::Property::SHADOW:
645       {
646         GetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
647         break;
648       }
649       case Toolkit::TextLabel::Property::EMBOSS:
650       {
651         GetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
652         break;
653       }
654       case Toolkit::TextLabel::Property::OUTLINE:
655       {
656         GetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
657         break;
658       }
659       case Toolkit::TextLabel::Property::PIXEL_SIZE:
660       {
661         value = impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE);
662         break;
663       }
664       case Toolkit::TextLabel::Property::ELLIPSIS:
665       {
666         value = impl.mController->IsTextElideEnabled();
667         break;
668       }
669       case Toolkit::TextLabel::Property::LINE_WRAP_MODE:
670       {
671         value = impl.mController->GetLineWrapMode();
672         break;
673       }
674       case Toolkit::TextLabel::Property::LINE_COUNT:
675       {
676         float width = label.GetProperty(Actor::Property::SIZE_WIDTH).Get<float>();
677         value       = impl.mController->GetLineCount(width);
678         break;
679       }
680       case Toolkit::DevelTextLabel::Property::TEXT_DIRECTION:
681       {
682         value = impl.mController->GetTextDirection();
683         break;
684       }
685       case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT:
686       {
687         value = impl.mController->GetVerticalLineAlignment();
688         break;
689       }
690       case Toolkit::DevelTextLabel::Property::BACKGROUND:
691       {
692         GetBackgroundProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
693         break;
694       }
695       case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
696       {
697         value = impl.mController->IsIgnoreSpacesAfterText();
698         break;
699       }
700       case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
701       {
702         value = impl.mController->GetMatchLayoutDirection() != DevelText::MatchLayoutDirection::CONTENTS;
703         break;
704       }
705       case Toolkit::DevelTextLabel::Property::TEXT_FIT:
706       {
707         const bool  enabled  = impl.mController->IsTextFitEnabled();
708         const float minSize  = impl.mController->GetTextFitMinSize();
709         const float maxSize  = impl.mController->GetTextFitMaxSize();
710         const float stepSize = impl.mController->GetTextFitStepSize();
711
712         Property::Map map;
713         map.Insert(TEXT_FIT_ENABLE_KEY, enabled);
714         map.Insert(TEXT_FIT_MIN_SIZE_KEY, minSize);
715         map.Insert(TEXT_FIT_MAX_SIZE_KEY, maxSize);
716         map.Insert(TEXT_FIT_STEP_SIZE_KEY, stepSize);
717         map.Insert(TEXT_FIT_FONT_SIZE_TYPE_KEY, "pointSize");
718
719         value = map;
720         break;
721       }
722       case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
723       {
724         value = impl.mController->GetDefaultLineSize();
725         break;
726       }
727       case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE:
728       {
729         value = impl.mController->GetFontSizeScale();
730         break;
731       }
732       case Toolkit::DevelTextLabel::Property::ELLIPSIS_POSITION:
733       {
734         value = impl.mController->GetEllipsisPosition();
735         break;
736       }
737     }
738   }
739
740   return value;
741 }
742
743 bool TextLabel::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
744 {
745   Dali::BaseHandle handle(object);
746
747   bool               connected(true);
748   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast(handle);
749
750   if(0 == strcmp(signalName.c_str(), SIGNAL_ANCHOR_CLICKED))
751   {
752     if(label)
753     {
754       Internal::TextLabel& labelImpl(GetImpl(label));
755       labelImpl.AnchorClickedSignal().Connect(tracker, functor);
756     }
757   }
758   else
759   {
760     // signalName does not match any signal
761     connected = false;
762   }
763
764   return connected;
765 }
766
767 DevelTextLabel::AnchorClickedSignalType& TextLabel::AnchorClickedSignal()
768 {
769   return mAnchorClickedSignal;
770 }
771
772 void TextLabel::OnInitialize()
773 {
774   Actor self = Self();
775
776   Property::Map propertyMap;
777   propertyMap.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT);
778
779   mVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap);
780   DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual);
781
782   TextVisual::SetAnimatableTextColorProperty(mVisual, Toolkit::TextLabel::Property::TEXT_COLOR);
783
784   mController = TextVisual::GetController(mVisual);
785   DALI_ASSERT_DEBUG(mController && "Invalid Text Controller")
786
787   mController->SetControlInterface(this);
788   mController->SetAnchorControlInterface(this);
789
790   // Use height-for-width negotiation by default
791   self.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
792   self.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT);
793
794   // Enable highlightability
795   self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
796
797   // Enable the text ellipsis.
798   mController->SetTextElideEnabled(true); // If false then text larger than control will overflow
799
800   // Sets layoutDirection value
801   Dali::Stage                 stage           = Dali::Stage::GetCurrent();
802   Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(stage.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
803   mController->SetLayoutDirection(layoutDirection);
804
805   self.LayoutDirectionChangedSignal().Connect(this, &TextLabel::OnLayoutDirectionChanged);
806
807   // Forward input events to controller
808   EnableGestureDetection(static_cast<GestureType::Value>(GestureType::TAP));
809   GetTapGestureDetector().SetMaximumTapsRequired(1);
810
811   Layout::Engine& engine = mController->GetLayoutEngine();
812   engine.SetCursorWidth(0u); // Do not layout space for the cursor.
813
814   DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
815     return std::unique_ptr<Dali::Accessibility::Accessible>(
816       new AccessibleImpl(actor, Dali::Accessibility::Role::LABEL));
817   });
818 }
819
820 void TextLabel::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
821 {
822   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
823
824   switch(change)
825   {
826     case StyleChange::DEFAULT_FONT_CHANGE:
827     {
828       // Property system did not set the font so should update it.
829       const std::string& newFont = GetImpl(styleManager).GetDefaultFontFamily();
830       DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str());
831       mController->UpdateAfterFontChange(newFont);
832       RelayoutRequest();
833       break;
834     }
835     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
836     {
837       GetImpl(styleManager).ApplyThemeStyle(Toolkit::Control(GetOwner()));
838       RelayoutRequest();
839       break;
840     }
841     case StyleChange::THEME_CHANGE:
842     {
843       // Nothing to do, let control base class handle this
844       break;
845     }
846   }
847
848   // Up call to Control
849   Control::OnStyleChange(styleManager, change);
850 }
851
852 void TextLabel::OnTap(const TapGesture& gesture)
853 {
854   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::OnTap %p\n", mController.Get());
855
856   // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
857   Extents padding;
858   padding                   = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
859   const Vector2& localPoint = gesture.GetLocalPoint();
860   mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
861
862   // parents can also listen for tap gesture events
863   Dali::DevelActor::SetNeedGesturePropagation(Self(), true);
864 }
865
866 void TextLabel::AnchorClicked(const std::string& href)
867 {
868   Dali::Toolkit::TextLabel handle(GetOwner());
869   mAnchorClickedSignal.Emit(handle, href.c_str(), href.length());
870 }
871
872 Vector3 TextLabel::GetNaturalSize()
873 {
874   Extents padding;
875   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
876
877   Vector3 naturalSize = mController->GetNaturalSize();
878   naturalSize.width += (padding.start + padding.end);
879   naturalSize.height += (padding.top + padding.bottom);
880
881   return naturalSize;
882 }
883
884 float TextLabel::GetHeightForWidth(float width)
885 {
886   Extents padding;
887   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
888
889   return mController->GetHeightForWidth(width) + padding.top + padding.bottom;
890 }
891
892 void TextLabel::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
893 {
894   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::OnPropertySet index[%d]\n", index);
895
896   switch(index)
897   {
898     case Toolkit::TextLabel::Property::TEXT_COLOR:
899     {
900       const Vector4& textColor = propertyValue.Get<Vector4>();
901       if(mController->GetDefaultColor() != textColor)
902       {
903         mController->SetDefaultColor(textColor);
904         mTextUpdateNeeded = true;
905       }
906       break;
907     }
908     default:
909     {
910       Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
911       break;
912     }
913   }
914 }
915
916 void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container)
917 {
918   DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout\n");
919
920   Actor self = Self();
921
922   Extents padding;
923   padding = self.GetProperty<Extents>(Toolkit::Control::Property::PADDING);
924
925   Vector2 contentSize(size.x - (padding.start + padding.end), size.y - (padding.top + padding.bottom));
926
927   if(mController->IsTextFitEnabled())
928   {
929     mController->FitPointSizeforLayout(contentSize);
930     mController->SetTextFitContentSize(contentSize);
931   }
932
933   // Support Right-To-Left
934   Dali::LayoutDirection::Type layoutDirection = mController->GetLayoutDirection(self);
935
936   const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
937
938   if((Text::Controller::NONE_UPDATED != (Text::Controller::MODEL_UPDATED & updateTextType)) || mTextUpdateNeeded)
939   {
940     DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout IsAutoScrollEnabled[%s] [%p]\n", (mController->IsAutoScrollEnabled()) ? "true" : "false", this);
941
942     // Update the visual
943     TextVisual::EnableRendererUpdate(mVisual);
944
945     // Support Right-To-Left of padding
946     if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
947     {
948       std::swap(padding.start, padding.end);
949     }
950
951     // Calculate the size of the visual that can fit the text
952     Size layoutSize = mController->GetTextModel()->GetLayoutSize();
953     layoutSize.x    = contentSize.x;
954
955     const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
956     if(shadowOffset.y > Math::MACHINE_EPSILON_1)
957     {
958       layoutSize.y += shadowOffset.y;
959     }
960
961     float outlineWidth = mController->GetTextModel()->GetOutlineWidth();
962     layoutSize.y += outlineWidth * 2.0f;
963     layoutSize.y = std::min(layoutSize.y, contentSize.y);
964
965     // Calculate the offset for vertical alignment only, as the layout engine will do the horizontal alignment.
966     Vector2 alignmentOffset;
967     alignmentOffset.x = 0.0f;
968     alignmentOffset.y = (contentSize.y - layoutSize.y) * VERTICAL_ALIGNMENT_TABLE[mController->GetVerticalAlignment()];
969
970     Property::Map visualTransform;
971     visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, layoutSize)
972       .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
973       .Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2(padding.start, padding.top) + alignmentOffset)
974       .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
975       .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN)
976       .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN);
977     mVisual.SetTransformAndSize(visualTransform, size);
978
979     if(mController->IsAutoScrollEnabled())
980     {
981       SetUpAutoScrolling();
982     }
983
984     mTextUpdateNeeded = false;
985   }
986 }
987
988 void TextLabel::RequestTextRelayout()
989 {
990   RelayoutRequest();
991   // Signal that a Relayout may be needed
992 }
993
994 void TextLabel::SetUpAutoScrolling()
995 {
996   const Size&                    controlSize     = mController->GetView().GetControlSize();
997   const Size                     textNaturalSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only.
998   const Text::CharacterDirection direction       = mController->GetAutoScrollDirection();
999
1000   DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling textNaturalSize[%f,%f] controlSize[%f,%f]\n", textNaturalSize.x, textNaturalSize.y, controlSize.x, controlSize.y);
1001
1002   if(!mTextScroller)
1003   {
1004     DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling Creating default TextScoller\n");
1005
1006     // If speed, loopCount or gap not set via property system then will need to create a TextScroller with defaults
1007     mTextScroller = Text::TextScroller::New(*this);
1008   }
1009
1010   // Calculate the actual gap before scrolling wraps.
1011   int     textPadding = std::max(controlSize.x - textNaturalSize.x, 0.0f);
1012   float   wrapGap     = std::max(mTextScroller->GetGap(), textPadding);
1013   Vector2 textureSize = textNaturalSize + Vector2(wrapGap, 0.0f); // Add the gap as a part of the texture
1014
1015   // Create a texture of the text for scrolling
1016   Size      verifiedSize   = textureSize;
1017   const int maxTextureSize = Dali::GetMaxTextureSize();
1018
1019   //if the texture size width exceed maxTextureSize, modify the visual model size and enabled the ellipsis
1020   bool actualellipsis = mController->IsTextElideEnabled();
1021   if(verifiedSize.width > maxTextureSize)
1022   {
1023     verifiedSize.width = maxTextureSize;
1024     if(textNaturalSize.width > maxTextureSize)
1025     {
1026       mController->SetTextElideEnabled(true);
1027     }
1028     GetHeightForWidth(maxTextureSize);
1029     wrapGap = std::max(maxTextureSize - textNaturalSize.width, 0.0f);
1030   }
1031
1032   Text::TypesetterPtr typesetter = Text::Typesetter::New(mController->GetTextModel());
1033
1034   PixelData data    = typesetter->Render(verifiedSize, mController->GetTextDirection(), Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888); // ignore the horizontal alignment
1035   Texture   texture = Texture::New(Dali::TextureType::TEXTURE_2D,
1036                                  data.GetPixelFormat(),
1037                                  data.GetWidth(),
1038                                  data.GetHeight());
1039   texture.Upload(data);
1040
1041   TextureSet textureSet = TextureSet::New();
1042   textureSet.SetTexture(0u, texture);
1043
1044   // Filter mode needs to be set to linear to produce better quality while scaling.
1045   Sampler sampler = Sampler::New();
1046   sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR);
1047   sampler.SetWrapMode(Dali::WrapMode::DEFAULT, Dali::WrapMode::REPEAT, Dali::WrapMode::DEFAULT); // Wrap the texture in the x direction
1048   textureSet.SetSampler(0u, sampler);
1049
1050   // Set parameters for scrolling
1051   Renderer renderer = static_cast<Internal::Visual::Base&>(GetImplementation(mVisual)).GetRenderer();
1052   mTextScroller->SetParameters(Self(), renderer, textureSet, controlSize, verifiedSize, wrapGap, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment());
1053   mController->SetTextElideEnabled(actualellipsis);
1054 }
1055
1056 void TextLabel::ScrollingFinished()
1057 {
1058   // Pure Virtual from TextScroller Interface
1059   DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n");
1060   mController->SetAutoScrollEnabled(false);
1061   RequestTextRelayout();
1062 }
1063
1064 void TextLabel::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type)
1065 {
1066   mController->ChangedLayoutDirection();
1067 }
1068
1069 TextLabel::TextLabel()
1070 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
1071   mRenderingBackend(DEFAULT_RENDERING_BACKEND),
1072   mTextUpdateNeeded(false)
1073 {
1074 }
1075
1076 TextLabel::~TextLabel()
1077 {
1078 }
1079
1080 std::string TextLabel::AccessibleImpl::GetNameRaw()
1081 {
1082   auto self = Toolkit::TextLabel::DownCast(Self());
1083   return self.GetProperty(Toolkit::TextLabel::Property::TEXT).Get<std::string>();
1084 }
1085
1086 Property::Index TextLabel::AccessibleImpl::GetNamePropertyIndex()
1087 {
1088   return Toolkit::TextLabel::Property::TEXT;
1089 }
1090
1091 std::string TextLabel::AccessibleImpl::GetText(size_t startOffset, size_t endOffset)
1092 {
1093   if(endOffset <= startOffset)
1094   {
1095     return {};
1096   }
1097
1098   auto self = Toolkit::TextLabel::DownCast(Self());
1099   auto text = self.GetProperty(Toolkit::TextLabel::Property::TEXT).Get<std::string>();
1100
1101   if(startOffset > text.size() || endOffset > text.size())
1102   {
1103     return {};
1104   }
1105
1106   return text.substr(startOffset, endOffset - startOffset);
1107 }
1108
1109 size_t TextLabel::AccessibleImpl::GetCharacterCount()
1110 {
1111   auto self = Toolkit::TextLabel::DownCast(Self());
1112   auto text = self.GetProperty(Toolkit::TextLabel::Property::TEXT).Get<std::string>();
1113
1114   return text.size();
1115 }
1116
1117 size_t TextLabel::AccessibleImpl::GetCursorOffset()
1118 {
1119   return {};
1120 }
1121
1122 bool TextLabel::AccessibleImpl::SetCursorOffset(size_t offset)
1123 {
1124   return {};
1125 }
1126
1127 Dali::Accessibility::Range TextLabel::AccessibleImpl::GetTextAtOffset(size_t offset, Dali::Accessibility::TextBoundary boundary)
1128 {
1129   auto self = Toolkit::TextLabel::DownCast(Self());
1130   auto text = self.GetProperty(Toolkit::TextLabel::Property::TEXT).Get<std::string>();
1131   auto textSize = text.size();
1132
1133   auto range = Dali::Accessibility::Range{};
1134
1135   switch(boundary)
1136   {
1137     case Dali::Accessibility::TextBoundary::CHARACTER:
1138     {
1139       if(offset < textSize)
1140       {
1141         range.content     = text[offset];
1142         range.startOffset = offset;
1143         range.endOffset   = offset + 1;
1144       }
1145       break;
1146     }
1147     case Dali::Accessibility::TextBoundary::WORD:
1148     case Dali::Accessibility::TextBoundary::LINE:
1149     {
1150       auto textString = text.c_str();
1151       auto breaks = std::vector<char>(textSize, 0);
1152
1153       if(boundary == Dali::Accessibility::TextBoundary::WORD)
1154       {
1155         Accessibility::Accessible::FindWordSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
1156       }
1157       else
1158       {
1159         Accessibility::Accessible::FindLineSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
1160       }
1161
1162       auto index = 0u;
1163       auto counter = 0u;
1164       while(index < textSize && counter <= offset)
1165       {
1166         auto start = index;
1167         if(breaks[index])
1168         {
1169           while(breaks[index])
1170           {
1171             index++;
1172           }
1173           counter++;
1174         }
1175         else
1176         {
1177           if(boundary == Dali::Accessibility::TextBoundary::WORD)
1178           {
1179             index++;
1180           }
1181           if(boundary == Dali::Accessibility::TextBoundary::LINE)
1182           {
1183             counter++;
1184           }
1185         }
1186
1187         if((counter > 0) && ((counter - 1) == offset))
1188         {
1189           range.content     = text.substr(start, index - start + 1);
1190           range.startOffset = start;
1191           range.endOffset   = index + 1;
1192         }
1193
1194         if(boundary == Dali::Accessibility::TextBoundary::LINE)
1195         {
1196           index++;
1197         }
1198       }
1199       break;
1200     }
1201     case Dali::Accessibility::TextBoundary::SENTENCE:
1202     {
1203       /* not supported by default */
1204       break;
1205     }
1206     case Dali::Accessibility::TextBoundary::PARAGRAPH:
1207     {
1208       /* Paragraph is not supported by libunibreak library */
1209       break;
1210     }
1211     default:
1212       break;
1213   }
1214
1215   return range;
1216 }
1217
1218 Dali::Accessibility::Range TextLabel::AccessibleImpl::GetRangeOfSelection(size_t selectionIndex)
1219 {
1220   // Since DALi supports only one selection indexes higher than 0 are ignored
1221   if(selectionIndex > 0)
1222   {
1223     return {};
1224   }
1225
1226   auto self  = Toolkit::TextLabel::DownCast(Self());
1227   auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
1228   std::string value{};
1229   controller->RetrieveSelection(value);
1230   auto indices = controller->GetSelectionIndexes();
1231
1232   return {static_cast<size_t>(indices.first), static_cast<size_t>(indices.second), value};
1233 }
1234
1235 bool TextLabel::AccessibleImpl::RemoveSelection(size_t selectionIndex)
1236 {
1237   // Since DALi supports only one selection indexes higher than 0 are ignored
1238   if(selectionIndex > 0)
1239   {
1240     return false;
1241   }
1242
1243   auto self = Toolkit::TextLabel::DownCast(Self());
1244   Dali::Toolkit::GetImpl(self).GetTextController()->SetSelection(0, 0);
1245   return true;
1246 }
1247
1248 bool TextLabel::AccessibleImpl::SetRangeOfSelection(size_t selectionIndex, size_t startOffset, size_t endOffset)
1249 {
1250   // Since DALi supports only one selection indexes higher than 0 are ignored
1251   if(selectionIndex > 0)
1252   {
1253     return false;
1254   }
1255
1256   auto self = Toolkit::TextLabel::DownCast(Self());
1257   Dali::Toolkit::GetImpl(self).GetTextController()->SetSelection(startOffset, endOffset);
1258   return true;
1259 }
1260
1261 } // namespace Internal
1262
1263 } // namespace Toolkit
1264
1265 } // namespace Dali