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