Reduce text visual memory consumption for text with no styles and emojis
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-label-impl.cpp
1 /*
2  * Copyright (c) 2017 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/public-api/object/type-registry-helper.h>
23 #include <dali/devel-api/object/property-helper-devel.h>
24 #include <dali/integration-api/debug.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/public-api/text/rendering-backend.h>
28 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
29 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
30 #include <dali-toolkit/internal/text/property-string-parser.h>
31 #include <dali-toolkit/internal/text/rendering/text-backend.h>
32 #include <dali-toolkit/internal/text/text-effects-style.h>
33 #include <dali-toolkit/internal/text/text-font-style.h>
34 #include <dali-toolkit/internal/text/text-view.h>
35 #include <dali-toolkit/internal/text/text-definitions.h>
36 #include <dali-toolkit/internal/styling/style-manager-impl.h>
37
38 #include <dali-toolkit/devel-api/align-enums.h>
39 #include <dali-toolkit/devel-api/controls/control-devel.h>
40 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
41 #include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
42 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
43 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
44
45 using namespace Dali::Toolkit::Text;
46
47 namespace Dali
48 {
49
50 namespace Toolkit
51 {
52
53 namespace Internal
54 {
55
56 namespace
57 {
58   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
59 }
60
61 namespace
62 {
63
64 #if defined ( DEBUG_ENABLED )
65   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
66 #endif
67
68 const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
69 {
70   { "IMMEDIATE", Toolkit::DevelTextLabel::AutoScrollStopMode::IMMEDIATE },
71   { "FINISH_LOOP",  Toolkit::DevelTextLabel::AutoScrollStopMode::FINISH_LOOP  },
72 };
73 const unsigned int AUTO_SCROLL_STOP_MODE_TABLE_COUNT = sizeof( AUTO_SCROLL_STOP_MODE_TABLE ) / sizeof( AUTO_SCROLL_STOP_MODE_TABLE[0] );
74
75 const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
76 {
77   { "BEGIN",  Toolkit::Text::Layout::HORIZONTAL_ALIGN_BEGIN  },
78   { "CENTER", Toolkit::Text::Layout::HORIZONTAL_ALIGN_CENTER },
79   { "END",    Toolkit::Text::Layout::HORIZONTAL_ALIGN_END    },
80 };
81 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
82
83 const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
84 {
85   { "TOP",    Toolkit::Text::Layout::VERTICAL_ALIGN_TOP    },
86   { "CENTER", Toolkit::Text::Layout::VERTICAL_ALIGN_CENTER },
87   { "BOTTOM", Toolkit::Text::Layout::VERTICAL_ALIGN_BOTTOM },
88 };
89 const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( VERTICAL_ALIGNMENT_STRING_TABLE ) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
90
91 const Scripting::StringEnum LINE_WRAP_MODE_STRING_TABLE[] =
92 {
93   { "WRAP_MODE_WORD",      Toolkit::Text::Layout::LineWrap::WORD  },
94   { "WRAP_MODE_CHARACTER", Toolkit::Text::Layout::LineWrap::CHARACTER }
95 };
96 const unsigned int LINE_WRAP_MODE_STRING_TABLE_COUNT = sizeof( LINE_WRAP_MODE_STRING_TABLE ) / sizeof( LINE_WRAP_MODE_STRING_TABLE[0] );
97
98 // Type registration
99 BaseHandle Create()
100 {
101   return Toolkit::TextLabel::New();
102 }
103
104 // Setup properties, signals and actions using the type-registry.
105 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create );
106
107 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "renderingBackend",          INTEGER, RENDERING_BACKEND      ) // Deprecated property
108 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "text",                      STRING,  TEXT                   )
109 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontFamily",                STRING,  FONT_FAMILY            )
110 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontStyle",                 MAP,     FONT_STYLE             )
111 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "pointSize",                 FLOAT,   POINT_SIZE             )
112 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "multiLine",                 BOOLEAN, MULTI_LINE             )
113 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "horizontalAlignment",       STRING,  HORIZONTAL_ALIGNMENT   )
114 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "verticalAlignment",         STRING,  VERTICAL_ALIGNMENT     )
115 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textColor",                 VECTOR4, TEXT_COLOR             )
116 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadowOffset",              VECTOR2, SHADOW_OFFSET          )
117 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadowColor",               VECTOR4, SHADOW_COLOR           )
118 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineEnabled",          BOOLEAN, UNDERLINE_ENABLED      )
119 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineColor",            VECTOR4, UNDERLINE_COLOR        )
120 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineHeight",           FLOAT,   UNDERLINE_HEIGHT       )
121 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "enableMarkup",              BOOLEAN, ENABLE_MARKUP          )
122 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "enableAutoScroll",          BOOLEAN, ENABLE_AUTO_SCROLL     )
123 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollSpeed",           INTEGER, AUTO_SCROLL_SPEED      )
124 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollLoopCount",       INTEGER, AUTO_SCROLL_LOOP_COUNT )
125 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollGap",             FLOAT,   AUTO_SCROLL_GAP        )
126 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "lineSpacing",               FLOAT,   LINE_SPACING           )
127 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underline",                 MAP,     UNDERLINE              )
128 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadow",                    MAP,     SHADOW                 )
129 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "emboss",                    MAP,     EMBOSS                 )
130 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "outline",                   MAP,     OUTLINE                )
131 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "pixelSize",           FLOAT,   PIXEL_SIZE             )
132 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "ellipsis",            BOOLEAN, ELLIPSIS               )
133 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollLoopDelay", FLOAT,   AUTO_SCROLL_LOOP_DELAY )
134 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollStopMode",  STRING,  AUTO_SCROLL_STOP_MODE  )
135 DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "lineCount", INTEGER, LINE_COUNT             )
136 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "lineWrapMode",        STRING,  LINE_WRAP_MODE         )
137 DALI_DEVEL_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColorAnimatable", Color::BLACK, TEXT_COLOR_ANIMATABLE )
138 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR_ANIMATABLE, 0)
139 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR_ANIMATABLE, 1)
140 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorBlue",  TEXT_COLOR_BLUE,  TEXT_COLOR_ANIMATABLE, 2)
141 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR_ANIMATABLE, 3)
142 DALI_TYPE_REGISTRATION_END()
143
144 } // namespace
145
146 Toolkit::TextLabel TextLabel::New()
147 {
148   // Create the implementation, temporarily owned by this handle on stack
149   IntrusivePtr< TextLabel > impl = new TextLabel();
150
151   // Pass ownership to CustomActor handle
152   Toolkit::TextLabel handle( *impl );
153
154   // Second-phase init of the implementation
155   // This can only be done after the CustomActor connection has been made...
156   impl->Initialize();
157
158   return handle;
159 }
160
161 void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
162 {
163   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
164
165   if( label )
166   {
167     TextLabel& impl( GetImpl( label ) );
168     switch( index )
169     {
170       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
171       {
172         DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
173
174         int backend = value.Get< int >();
175
176 #ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
177         if( Text::RENDERING_VECTOR_BASED == backend )
178         {
179           backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
180         }
181 #endif
182         if( impl.mRenderingBackend != backend )
183         {
184           impl.mRenderingBackend = backend;
185           impl.mTextUpdateNeeded = true;
186
187           if( impl.mController )
188           {
189             // When using the vector-based rendering, the size of the GLyphs are different
190             TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
191             impl.mController->SetGlyphType( glyphType );
192           }
193         }
194         break;
195       }
196       case Toolkit::TextLabel::Property::TEXT:
197       {
198         if( impl.mController )
199         {
200           impl.mController->SetText( value.Get< std::string >() );
201         }
202         break;
203       }
204       case Toolkit::TextLabel::Property::FONT_FAMILY:
205       {
206         if( impl.mController )
207         {
208           const std::string& fontFamily = value.Get< std::string >();
209
210           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str() );
211           impl.mController->SetDefaultFontFamily( fontFamily );
212         }
213         break;
214       }
215       case Toolkit::TextLabel::Property::FONT_STYLE:
216       {
217         SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
218         break;
219       }
220       case Toolkit::TextLabel::Property::POINT_SIZE:
221       {
222         if( impl.mController )
223         {
224           const float pointSize = value.Get< float >();
225
226           if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
227           {
228             impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
229           }
230         }
231         break;
232       }
233       case Toolkit::TextLabel::Property::MULTI_LINE:
234       {
235         if( impl.mController )
236         {
237           impl.mController->SetMultiLineEnabled( value.Get< bool >() );
238         }
239         break;
240       }
241       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
242       {
243         if( impl.mController )
244         {
245           Layout::HorizontalAlignment alignment( Layout::HORIZONTAL_ALIGN_BEGIN );
246           if( Scripting::GetEnumeration< Toolkit::Text::Layout::HorizontalAlignment >( value.Get< std::string >().c_str(),
247                                                                                        HORIZONTAL_ALIGNMENT_STRING_TABLE,
248                                                                                        HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
249                                                                                        alignment ) )
250           {
251             impl.mController->SetHorizontalAlignment( alignment );
252           }
253         }
254         break;
255       }
256       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
257       {
258         if( impl.mController )
259         {
260           Layout::VerticalAlignment alignment( Layout::VERTICAL_ALIGN_BOTTOM );
261           if( Scripting::GetEnumeration< Toolkit::Text::Layout::VerticalAlignment >( value.Get< std::string >().c_str(),
262                                                                                      VERTICAL_ALIGNMENT_STRING_TABLE,
263                                                                                      VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
264                                                                                      alignment ) )
265           {
266             impl.mController->SetVerticalAlignment( alignment );
267           }
268         }
269         break;
270       }
271
272       case Toolkit::TextLabel::Property::TEXT_COLOR:
273       {
274         label.SetProperty( DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE, value );
275         impl.mTextUpdateNeeded = true;
276         break;
277       }
278
279       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
280       {
281         if( impl.mController )
282         {
283           const Vector2& shadowOffset = value.Get< Vector2 >();
284           if ( impl.mController->GetShadowOffset() != shadowOffset )
285           {
286             impl.mController->SetShadowOffset( shadowOffset );
287             impl.mTextUpdateNeeded = true;
288           }
289         }
290         break;
291       }
292       case Toolkit::TextLabel::Property::SHADOW_COLOR:
293       {
294         if( impl.mController )
295         {
296           const Vector4& shadowColor = value.Get< Vector4 >();
297           if ( impl.mController->GetShadowColor() != shadowColor )
298           {
299             impl.mController->SetShadowColor( shadowColor );
300             impl.mTextUpdateNeeded = true;
301           }
302         }
303         break;
304       }
305       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
306       {
307         if( impl.mController )
308         {
309           const Vector4& color = value.Get< Vector4 >();
310           if ( impl.mController->GetUnderlineColor() != color )
311           {
312             impl.mController->SetUnderlineColor( color );
313             impl.mTextUpdateNeeded = true;
314           }
315         }
316         break;
317       }
318       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
319       {
320         if( impl.mController )
321         {
322           const bool enabled = value.Get< bool >();
323           if ( impl.mController->IsUnderlineEnabled() != enabled )
324           {
325             impl.mController->SetUnderlineEnabled( enabled );
326             impl.mTextUpdateNeeded = true;
327           }
328         }
329         break;
330       }
331
332       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
333       {
334         if( impl.mController )
335         {
336           float height = value.Get< float >();
337           if( fabsf( impl.mController->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 )
338           {
339             impl.mController->SetUnderlineHeight( height );
340             impl.mTextUpdateNeeded = true;
341           }
342         }
343         break;
344       }
345       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
346       {
347         if( impl.mController )
348         {
349           const bool enableMarkup = value.Get<bool>();
350           impl.mController->SetMarkupProcessorEnabled( enableMarkup );
351         }
352         break;
353       }
354       case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
355       {
356         if( impl.mController )
357         {
358           const bool enableAutoScroll = value.Get<bool>();
359           // If request to auto scroll is the same as current state then do nothing.
360           if ( enableAutoScroll != impl.mController->IsAutoScrollEnabled() )
361           {
362              // If request is disable (false) and auto scrolling is enabled then need to stop it
363              if ( enableAutoScroll == false )
364              {
365                if( impl.mTextScroller )
366                {
367                  impl.mTextScroller->StopScrolling();
368                }
369              }
370              // If request is enable (true) then start autoscroll as not already running
371              else
372              {
373                impl.mController->SetTextElideEnabled( false );
374                impl.mController->SetAutoScrollEnabled( enableAutoScroll );
375              }
376           }
377         }
378         break;
379       }
380       case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_STOP_MODE:
381       {
382         if( !impl.mTextScroller )
383         {
384           impl.mTextScroller = Text::TextScroller::New( impl );
385         }
386         DevelTextLabel::AutoScrollStopMode::Type stopMode = impl.mTextScroller->GetStopMode();
387         if( Scripting::GetEnumerationProperty< Toolkit::DevelTextLabel::AutoScrollStopMode::Type >( value,
388                                                                                                     AUTO_SCROLL_STOP_MODE_TABLE,
389                                                                                                     AUTO_SCROLL_STOP_MODE_TABLE_COUNT,
390                                                                                                     stopMode ) )
391         {
392             impl.mTextScroller->SetStopMode( stopMode );
393         }
394         break;
395       }
396       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
397       {
398         if( !impl.mTextScroller )
399         {
400           impl.mTextScroller = Text::TextScroller::New( impl );
401         }
402         impl.mTextScroller->SetSpeed( value.Get<int>() );
403         break;
404       }
405       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
406       {
407         if( !impl.mTextScroller )
408         {
409           impl.mTextScroller = Text::TextScroller::New( impl );
410         }
411         impl.mTextScroller->SetLoopCount( value.Get<int>() );
412         break;
413       }
414       case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
415       {
416          if( !impl.mTextScroller )
417         {
418           impl.mTextScroller = Text::TextScroller::New( impl );
419         }
420         impl.mTextScroller->SetLoopDelay( value.Get<float>() );
421         break;
422       }
423       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
424       {
425         if( !impl.mTextScroller )
426         {
427           impl.mTextScroller = Text::TextScroller::New( impl );
428         }
429         impl.mTextScroller->SetGap( value.Get<float>() );
430         break;
431       }
432       case Toolkit::TextLabel::Property::LINE_SPACING:
433       {
434         if( impl.mController )
435         {
436           const float lineSpacing = value.Get<float>();
437           impl.mController->SetDefaultLineSpacing( lineSpacing );
438           impl.mTextUpdateNeeded = true;
439         }
440         break;
441       }
442       case Toolkit::TextLabel::Property::UNDERLINE:
443       {
444         const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
445         if( update )
446         {
447           impl.mTextUpdateNeeded = true;
448         }
449         break;
450       }
451       case Toolkit::TextLabel::Property::SHADOW:
452       {
453         const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
454         if( update )
455         {
456           impl.mTextUpdateNeeded = true;
457         }
458         break;
459       }
460       case Toolkit::TextLabel::Property::EMBOSS:
461       {
462         const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
463         if( update )
464         {
465           impl.mTextUpdateNeeded = true;
466         }
467         break;
468       }
469       case Toolkit::TextLabel::Property::OUTLINE:
470       {
471         const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
472         if( update )
473         {
474           impl.mTextUpdateNeeded = true;
475         }
476         break;
477       }
478       case Toolkit::DevelTextLabel::Property::PIXEL_SIZE:
479       {
480         if( impl.mController )
481         {
482           const float pixelSize = value.Get< float >();
483           DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize );
484
485           if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
486           {
487             impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
488           }
489         }
490         break;
491       }
492       case Toolkit::DevelTextLabel::Property::ELLIPSIS:
493       {
494         if( impl.mController )
495         {
496           const bool ellipsis = value.Get<bool>();
497           DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis );
498
499           impl.mController->SetTextElideEnabled( ellipsis );
500         }
501         break;
502       }
503       case Toolkit::DevelTextLabel::Property::LINE_WRAP_MODE:
504       {
505         const std::string& wrapModeStr = value.Get< std::string >();
506         DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p LINE_WRAP_MODE %s\n", impl.mController.Get(), wrapModeStr.c_str() );
507
508         Layout::LineWrap::Mode lineWrapMode( Layout::LineWrap::WORD );
509         if( Scripting::GetEnumeration< Layout::LineWrap::Mode >( wrapModeStr.c_str(),
510                                                                  LINE_WRAP_MODE_STRING_TABLE,
511                                                                  LINE_WRAP_MODE_STRING_TABLE_COUNT,
512                                                                  lineWrapMode ) )
513         {
514           impl.mController->SetLineWrapMode( lineWrapMode );
515         }
516         break;
517       }
518     }
519   }
520 }
521
522 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
523 {
524   Property::Value value;
525
526   Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
527
528   if( label )
529   {
530     TextLabel& impl( GetImpl( label ) );
531     switch( index )
532     {
533       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
534       {
535         DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
536
537         value = impl.mRenderingBackend;
538         break;
539       }
540       case Toolkit::TextLabel::Property::TEXT:
541       {
542         if( impl.mController )
543         {
544           std::string text;
545           impl.mController->GetText( text );
546           value = text;
547         }
548         break;
549       }
550       case Toolkit::TextLabel::Property::FONT_FAMILY:
551       {
552         if( impl.mController )
553         {
554           value = impl.mController->GetDefaultFontFamily();
555         }
556         break;
557       }
558       case Toolkit::TextLabel::Property::FONT_STYLE:
559       {
560         GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
561         break;
562       }
563       case Toolkit::TextLabel::Property::POINT_SIZE:
564       {
565         if( impl.mController )
566         {
567           value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE );
568         }
569         break;
570       }
571       case Toolkit::TextLabel::Property::MULTI_LINE:
572       {
573         if( impl.mController )
574         {
575           value = impl.mController->IsMultiLineEnabled();
576         }
577         break;
578       }
579       case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
580       {
581         if( impl.mController )
582         {
583           const char* name = Scripting::GetEnumerationName< Toolkit::Text::Layout::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(),
584                                                                                                           HORIZONTAL_ALIGNMENT_STRING_TABLE,
585                                                                                                           HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
586           if( name )
587           {
588             value = std::string( name );
589           }
590         }
591         break;
592       }
593       case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
594       {
595         if( impl.mController )
596         {
597           const char* name = Scripting::GetEnumerationName< Toolkit::Text::Layout::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
598                                                                                                         VERTICAL_ALIGNMENT_STRING_TABLE,
599                                                                                                         VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
600           if( name )
601           {
602             value = std::string( name );
603           }
604         }
605         break;
606       }
607       case Toolkit::TextLabel::Property::TEXT_COLOR:
608       {
609         value = label.GetProperty( Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE );
610         break;
611       }
612       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
613       {
614         if ( impl.mController )
615         {
616           value = impl.mController->GetShadowOffset();
617         }
618         break;
619       }
620       case Toolkit::TextLabel::Property::SHADOW_COLOR:
621       {
622         if ( impl.mController )
623         {
624           value = impl.mController->GetShadowColor();
625         }
626         break;
627       }
628       case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
629       {
630         if ( impl.mController )
631         {
632           value = impl.mController->GetUnderlineColor();
633         }
634         break;
635       }
636       case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
637       {
638         if ( impl.mController )
639         {
640           value = impl.mController->IsUnderlineEnabled();
641         }
642         break;
643       }
644       case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT:
645       {
646         if ( impl.mController )
647         {
648           value = impl.mController->GetUnderlineHeight();
649         }
650         break;
651       }
652       case Toolkit::TextLabel::Property::ENABLE_MARKUP:
653       {
654         if( impl.mController )
655         {
656           value = impl.mController->IsMarkupProcessorEnabled();
657         }
658         break;
659       }
660       case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
661       {
662         if( impl.mController )
663         {
664           value = impl.mController->IsAutoScrollEnabled();
665         }
666         break;
667       }
668       case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_STOP_MODE:
669       {
670         if( impl.mTextScroller )
671         {
672           const char* mode = Scripting::GetEnumerationName< Toolkit::DevelTextLabel::AutoScrollStopMode::Type >( impl.mTextScroller->GetStopMode(),
673                                                                                                                  AUTO_SCROLL_STOP_MODE_TABLE,
674                                                                                                                  AUTO_SCROLL_STOP_MODE_TABLE_COUNT );
675           if( mode )
676           {
677             value = std::string( mode );
678           }
679         }
680         break;
681       }
682       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
683       {
684         TextLabel& impl( GetImpl( label ) );
685         if ( impl.mTextScroller )
686         {
687           value = impl.mTextScroller->GetSpeed();
688         }
689         break;
690       }
691       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
692       {
693         if( impl.mController )
694         {
695           TextLabel& impl( GetImpl( label ) );
696           if ( impl.mTextScroller )
697           {
698             value = impl.mTextScroller->GetLoopCount();
699           }
700         }
701         break;
702       }
703       case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
704       {
705         if( impl.mController )
706         {
707           TextLabel& impl( GetImpl( label ) );
708           if ( impl.mTextScroller )
709           {
710             value = impl.mTextScroller->GetLoopDelay();
711           }
712         }
713         break;
714       }
715       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
716       {
717         TextLabel& impl( GetImpl( label ) );
718         if ( impl.mTextScroller )
719         {
720           value = impl.mTextScroller->GetGap();
721         }
722         break;
723       }
724       case Toolkit::TextLabel::Property::LINE_SPACING:
725       {
726         if( impl.mController )
727         {
728           value = impl.mController->GetDefaultLineSpacing();
729         }
730         break;
731       }
732       case Toolkit::TextLabel::Property::UNDERLINE:
733       {
734         GetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
735         break;
736       }
737       case Toolkit::TextLabel::Property::SHADOW:
738       {
739         GetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
740         break;
741       }
742       case Toolkit::TextLabel::Property::EMBOSS:
743       {
744         GetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
745         break;
746       }
747       case Toolkit::TextLabel::Property::OUTLINE:
748       {
749         GetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
750         break;
751       }
752       case Toolkit::DevelTextLabel::Property::PIXEL_SIZE:
753       {
754         if( impl.mController )
755         {
756           value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE );
757         }
758         break;
759       }
760       case Toolkit::DevelTextLabel::Property::ELLIPSIS:
761       {
762         if( impl.mController )
763         {
764           value = impl.mController->IsTextElideEnabled();
765         }
766         break;
767       }
768       case Toolkit::DevelTextLabel::Property::LINE_WRAP_MODE:
769       {
770         if( impl.mController )
771         {
772           value = impl.mController->GetLineWrapMode();
773         }
774         break;
775       }
776       case Toolkit::DevelTextLabel::Property::LINE_COUNT:
777       {
778         if( impl.mController )
779         {
780           float width = label.GetProperty( Actor::Property::SIZE_WIDTH ).Get<float>();
781           value = impl.mController->GetLineCount( width );
782         }
783         break;
784       }
785     }
786   }
787
788   return value;
789 }
790
791 void TextLabel::OnInitialize()
792 {
793   Actor self = Self();
794
795   Property::Map propertyMap;
796   propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::TEXT );
797
798   mVisual =  Toolkit::VisualFactory::Get().CreateVisual( propertyMap );
799   DevelControl::RegisterVisual( *this, Toolkit::TextLabel::Property::TEXT, mVisual  );
800
801   TextVisual::SetAnimatableTextColorProperty( mVisual, Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE );
802
803   mController = TextVisual::GetController(mVisual);
804   if( mController )
805   {
806     mController->SetControlInterface(this);
807   }
808
809   // Use height-for-width negotiation by default
810   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
811   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
812
813   // Enable the text ellipsis.
814   mController->SetTextElideEnabled( true );   // If false then text larger than control will overflow
815
816   Layout::Engine& engine = mController->GetLayoutEngine();
817   engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
818 }
819
820 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
821 {
822   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
823
824   switch ( change )
825   {
826     case StyleChange::DEFAULT_FONT_CHANGE:
827     {
828       // Property system did not set the font so should update it.
829       const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
830       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str() );
831       mController->UpdateAfterFontChange( newFont );
832       RelayoutRequest();
833       break;
834     }
835     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
836     {
837       GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
838       RelayoutRequest();
839       break;
840     }
841     case StyleChange::THEME_CHANGE:
842     {
843       // Nothing to do, let control base class handle this
844       break;
845     }
846   }
847
848   // Up call to Control
849   Control::OnStyleChange( styleManager, change );
850 }
851
852 Vector3 TextLabel::GetNaturalSize()
853 {
854   return mController->GetNaturalSize();
855 }
856
857 float TextLabel::GetHeightForWidth( float width )
858 {
859   Padding padding;
860   Self().GetPadding( padding );
861   return mController->GetHeightForWidth( width ) + padding.top + padding.bottom;
862 }
863
864 void TextLabel::OnPropertySet( Property::Index index, Property::Value propertyValue )
865 {
866   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnPropertySet index[%d]\n", index );
867
868   switch ( index )
869   {
870     case Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE:
871     {
872       const Vector4& textColor = propertyValue.Get< Vector4 >();
873       if( mController->GetDefaultColor() != textColor )
874       {
875          mController->SetDefaultColor( textColor );
876          mTextUpdateNeeded = true;
877       }
878       break;
879     }
880     default:
881     {
882       Control::OnPropertySet( index, propertyValue ); // up call to control for non-handled properties
883       break;
884     }
885   }
886 }
887
888 void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
889 {
890   DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout\n" );
891
892   Padding padding;
893   Self().GetPadding( padding );
894   Vector2 contentSize( size.x - ( padding.left + padding.right ), size.y - ( padding.top + padding.bottom ) );
895
896   const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize );
897
898   if( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
899      || mTextUpdateNeeded )
900   {
901     DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout IsAutoScrollEnabled[%s] [%p]\n", ( mController->IsAutoScrollEnabled())?"true":"false", this );
902
903     // Update the visual
904     TextVisual::EnableRendererUpdate( mVisual );
905
906     Padding padding;
907     Self().GetPadding( padding );
908
909     Property::Map visualTransform;
910     visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, contentSize )
911                    .Add( Toolkit::DevelVisual::Transform::Property::SIZE_POLICY, Vector2( DevelVisual::Transform::Policy::ABSOLUTE, DevelVisual::Transform::Policy::ABSOLUTE ) )
912                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET, Vector2(padding.left, padding.top) )
913                    .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::DevelVisual::Transform::Policy::ABSOLUTE, Toolkit::DevelVisual::Transform::Policy::ABSOLUTE ) )
914                    .Add( Toolkit::DevelVisual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
915                    .Add( Toolkit::DevelVisual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
916     mVisual.SetTransformAndSize( visualTransform, size );
917
918     if ( mController->IsAutoScrollEnabled() )
919     {
920       SetUpAutoScrolling();
921     }
922
923     mTextUpdateNeeded = false;
924   }
925 }
926
927 void TextLabel::RequestTextRelayout()
928 {
929   RelayoutRequest();
930 }
931
932 void TextLabel::SetUpAutoScrolling()
933 {
934   const Size& controlSize = mController->GetView().GetControlSize();
935   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.
936   const Text::CharacterDirection direction = mController->GetAutoScrollDirection();
937
938   DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling textNaturalSize[%f,%f] controlSize[%f,%f]\n",
939                  textNaturalSize.x,textNaturalSize.y , controlSize.x,controlSize.y );
940
941   if ( !mTextScroller )
942   {
943     DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling Creating default TextScoller\n" );
944
945     // If speed, loopCount or gap not set via property system then will need to create a TextScroller with defaults
946     mTextScroller = Text::TextScroller::New( *this );
947   }
948
949   // Create a texture of the text for scrolling
950   Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
951   PixelData data = typesetter->Render( textNaturalSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
952   Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
953                                   data.GetPixelFormat(),
954                                   data.GetWidth(),
955                                   data.GetHeight() );
956   texture.Upload( data );
957
958   TextureSet textureSet = TextureSet::New();
959   textureSet.SetTexture( 0u, texture );
960
961   // Filter mode needs to be set to linear to produce better quality while scaling.
962   Sampler sampler = Sampler::New();
963   sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
964   textureSet.SetSampler( 0u, sampler );
965
966   // Set parameters for scrolling
967   Renderer renderer = static_cast<Internal::Visual::Base&>( GetImplementation( mVisual ) ).GetRenderer();
968   mTextScroller->SetParameters( Self(), renderer, textureSet, controlSize, textNaturalSize, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment() );
969 }
970
971 void TextLabel::ScrollingFinished()
972 {
973   // Pure Virtual from TextScroller Interface
974   DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n");
975   mController->SetAutoScrollEnabled( false );
976   mController->SetTextElideEnabled( true );
977   RequestTextRelayout();
978 }
979
980 TextLabel::TextLabel()
981 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
982   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
983   mTextUpdateNeeded( false )
984 {
985 }
986
987 TextLabel::~TextLabel()
988 {
989 }
990
991 } // namespace Internal
992
993 } // namespace Toolkit
994
995 } // namespace Dali