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