Merge "DALi Version 1.3.16" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / text / text-visual.cpp
1 /*
2  * Copyright (c) 2018 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/visuals/text/text-visual.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/constraints.h>
23 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
24
25 // INTERNAL HEADER
26 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
27 #include <dali-toolkit/devel-api/visuals/text-visual-properties-devel.h>
28 #include <dali-toolkit/public-api/visuals/visual-properties.h>
29 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
30 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
31 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
32 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
33 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
34 #include <dali-toolkit/internal/text/text-font-style.h>
35 #include <dali-toolkit/internal/text/text-effects-style.h>
36 #include <dali-toolkit/internal/text/script-run.h>
37 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
38 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
39
40 namespace Dali
41 {
42
43 namespace Toolkit
44 {
45
46 namespace Internal
47 {
48
49 namespace
50 {
51
52 // Property names - common properties defined in visual-string-constants.h/cpp
53 const char * const FONT_FAMILY_PROPERTY( "fontFamily" );
54 const char * const FONT_STYLE_PROPERTY( "fontStyle" );
55 const char * const POINT_SIZE_PROPERTY( "pointSize" );
56 const char * const MULTI_LINE_PROPERTY( "multiLine" );
57 const char * const HORIZONTAL_ALIGNMENT_PROPERTY( "horizontalAlignment" );
58 const char * const VERTICAL_ALIGNMENT_PROPERTY( "verticalAlignment" );
59 const char * const TEXT_COLOR_PROPERTY( "textColor" );
60 const char * const ENABLE_MARKUP_PROPERTY( "enableMarkup" );
61 const char * const SHADOW_PROPERTY( "shadow" );
62 const char * const UNDERLINE_PROPERTY( "underline" );
63 const char * const OUTLINE_PROPERTY( "outline" );
64 const char * const BACKGROUND_PROPERTY( "textBackground" );
65
66 const Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
67
68 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
69   attribute mediump vec2 aPosition;\n
70   uniform mediump mat4 uMvpMatrix;\n
71   uniform mediump vec3 uSize;\n
72   uniform mediump vec4 pixelArea;\n
73
74   uniform mediump mat4 uModelMatrix;\n
75   uniform mediump mat4 uViewMatrix;\n
76   uniform mediump mat4 uProjection;\n
77
78   varying mediump vec2 vTexCoord;\n
79
80   //Visual size and offset
81   uniform mediump vec2 offset;\n
82   uniform mediump vec2 size;\n
83   uniform mediump vec4 offsetSizeMode;\n
84   uniform mediump vec2 origin;\n
85   uniform mediump vec2 anchorPoint;\n
86
87   vec4 ComputeVertexPosition()\n
88   {\n
89     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
90     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
91     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
92   }\n
93
94   void main()\n
95   {\n
96     mediump vec4 nonAlignedVertex = uViewMatrix*uModelMatrix*ComputeVertexPosition();\n
97     mediump vec4 pixelAlignedVertex = vec4 ( floor(nonAlignedVertex.xyz), 1.0 );\n
98     mediump vec4 vertexPosition = uProjection*pixelAlignedVertex;\n
99
100     vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
101     gl_Position = vertexPosition;\n
102   }\n
103 );
104
105 const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT = DALI_COMPOSE_SHADER(
106   varying mediump vec2 vTexCoord;\n
107   uniform sampler2D sTexture;\n
108   uniform lowp vec4 uTextColorAnimatable;\n
109   uniform lowp vec4 uColor;\n
110   uniform lowp vec3 mixColor;\n
111   uniform lowp float opacity;\n
112   uniform lowp float preMultipliedAlpha;\n
113   \n
114   lowp vec4 visualMixColor()\n
115   {\n
116     return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
117   }\n
118   \n
119   void main()\n
120   {\n
121     mediump float textTexture = texture2D( sTexture, vTexCoord ).r;\n
122
123     // Set the color of the text to what it is animated to.
124     gl_FragColor = uTextColorAnimatable * textTexture * uColor * visualMixColor();
125   }\n
126 );
127
128 const char* FRAGMENT_SHADER_MULTI_COLOR_TEXT = DALI_COMPOSE_SHADER(
129   varying mediump vec2 vTexCoord;\n
130   uniform sampler2D sTexture;\n
131   uniform lowp vec4 uColor;\n
132   uniform lowp vec3 mixColor;\n
133   uniform lowp float opacity;\n
134   uniform lowp float preMultipliedAlpha;\n
135   \n
136   lowp vec4 visualMixColor()\n
137   {\n
138     return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
139   }\n
140   \n
141   void main()\n
142   {\n
143     mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
144     textTexture.rgb *= mix( 1.0, textTexture.a, preMultipliedAlpha );\n
145
146     gl_FragColor = textTexture * uColor * visualMixColor();
147   }\n
148 );
149
150 const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE = DALI_COMPOSE_SHADER(
151   varying mediump vec2 vTexCoord;\n
152   uniform sampler2D sTexture;\n
153   uniform sampler2D sStyle;\n
154   uniform lowp vec4 uTextColorAnimatable;\n
155   uniform lowp vec4 uColor;\n
156   uniform lowp vec3 mixColor;\n
157   uniform lowp float opacity;\n
158   uniform lowp float preMultipliedAlpha;\n
159   \n
160   lowp vec4 visualMixColor()\n
161   {\n
162     return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
163   }\n
164   \n
165   void main()\n
166   {\n
167     mediump float textTexture = texture2D( sTexture, vTexCoord ).r;\n
168     mediump vec4 styleTexture = texture2D( sStyle, vTexCoord );\n
169
170     // Draw the text as overlay above the style
171     gl_FragColor = ( uTextColorAnimatable * textTexture + styleTexture * ( 1.0 - textTexture ) ) * uColor * visualMixColor();\n
172   }\n
173 );
174
175 const char* FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE = DALI_COMPOSE_SHADER(
176   varying mediump vec2 vTexCoord;\n
177   uniform sampler2D sTexture;\n
178   uniform sampler2D sStyle;\n
179   uniform lowp vec4 uColor;\n
180   uniform lowp vec3 mixColor;\n
181   uniform lowp float opacity;\n
182   uniform lowp float preMultipliedAlpha;\n
183   \n
184   lowp vec4 visualMixColor()\n
185   {\n
186     return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
187   }\n
188   \n
189   void main()\n
190   {\n
191     mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
192     mediump vec4 styleTexture = texture2D( sStyle, vTexCoord );\n
193     textTexture.rgb *= mix( 1.0, textTexture.a, preMultipliedAlpha );\n
194
195     // Draw the text as overlay above the style
196     gl_FragColor = ( textTexture + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * visualMixColor();\n
197   }\n
198 );
199
200 const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI = DALI_COMPOSE_SHADER(
201   varying mediump vec2 vTexCoord;\n
202   uniform sampler2D sTexture;\n
203   uniform sampler2D sMask;\n
204   uniform lowp vec4 uTextColorAnimatable;\n
205   uniform lowp vec4 uColor;\n
206   uniform lowp vec3 mixColor;\n
207   uniform lowp float opacity;\n
208   uniform lowp float preMultipliedAlpha;\n
209   \n
210   lowp vec4 visualMixColor()\n
211   {\n
212     return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
213   }\n
214   \n
215   void main()\n
216   {\n
217     mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
218     mediump float maskTexture = texture2D( sMask, vTexCoord ).r;\n
219
220     // Set the color of non-transparent pixel in text to what it is animated to.
221     // Markup text with multiple text colors are not animated (but can be supported later on if required).
222     // Emoji color are not animated.
223     mediump float vstep = step( 0.0001, textTexture.a );\n
224     textTexture.rgb = mix( textTexture.rgb, uTextColorAnimatable.rgb, vstep * maskTexture ) * mix( 1.0, textTexture.a, preMultipliedAlpha );\n
225
226     // Draw the text as overlay above the style
227     gl_FragColor = textTexture * uColor * visualMixColor();\n
228   }\n
229 );
230
231 const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI = DALI_COMPOSE_SHADER(
232   varying mediump vec2 vTexCoord;\n
233   uniform sampler2D sTexture;\n
234   uniform sampler2D sStyle;\n
235   uniform sampler2D sMask;\n
236   uniform lowp float uHasMultipleTextColors;\n
237   uniform lowp vec4 uTextColorAnimatable;\n
238   uniform lowp vec4 uColor;\n
239   uniform lowp vec3 mixColor;\n
240   uniform lowp float opacity;\n
241   uniform lowp float preMultipliedAlpha;\n
242   \n
243   lowp vec4 visualMixColor()\n
244   {\n
245     return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
246   }\n
247   \n
248   void main()\n
249   {\n
250     mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
251     mediump vec4 styleTexture = texture2D( sStyle, vTexCoord );\n
252     mediump float maskTexture = texture2D( sMask, vTexCoord ).r;\n
253
254     // Set the color of non-transparent pixel in text to what it is animated to.
255     // Markup text with multiple text colors are not animated (but can be supported later on if required).
256     // Emoji color are not animated.
257     mediump float vstep = step( 0.0001, textTexture.a );\n
258     textTexture.rgb = mix( textTexture.rgb, uTextColorAnimatable.rgb, vstep * maskTexture * ( 1.0 - uHasMultipleTextColors ) ) * mix( 1.0, textTexture.a, preMultipliedAlpha );\n
259
260     // Draw the text as overlay above the style
261     gl_FragColor = ( textTexture + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * visualMixColor();\n
262   }\n
263 );
264
265 /**
266  * Return Property index for the given string key
267  * param[in] stringKey the string index key
268  * return the key as an index
269  */
270
271 Dali::Property::Index StringKeyToIndexKey( const std::string& stringKey )
272 {
273   Dali::Property::Index result = Property::INVALID_KEY;
274
275   if( stringKey == VISUAL_TYPE )
276   {
277     result = Toolkit::Visual::Property::TYPE;
278   }
279   else if( stringKey == TEXT_PROPERTY )
280   {
281     result = Toolkit::TextVisual::Property::TEXT;
282   }
283   else if( stringKey == FONT_FAMILY_PROPERTY )
284   {
285     result = Toolkit::TextVisual::Property::FONT_FAMILY;
286   }
287   else if( stringKey == FONT_STYLE_PROPERTY )
288   {
289     result = Toolkit::TextVisual::Property::FONT_STYLE;
290   }
291   else if( stringKey == POINT_SIZE_PROPERTY )
292   {
293     result = Toolkit::TextVisual::Property::POINT_SIZE;
294   }
295   else if( stringKey == MULTI_LINE_PROPERTY )
296   {
297     result = Toolkit::TextVisual::Property::MULTI_LINE;
298   }
299   else if( stringKey == HORIZONTAL_ALIGNMENT_PROPERTY )
300   {
301     result = Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT;
302   }
303   else if( stringKey == VERTICAL_ALIGNMENT_PROPERTY )
304   {
305     result = Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT;
306   }
307   else if( stringKey == TEXT_COLOR_PROPERTY )
308   {
309     result = Toolkit::TextVisual::Property::TEXT_COLOR;
310   }
311   else if( stringKey == ENABLE_MARKUP_PROPERTY )
312   {
313     result = Toolkit::TextVisual::Property::ENABLE_MARKUP;
314   }
315   else if( stringKey == SHADOW_PROPERTY )
316   {
317     result = Toolkit::TextVisual::Property::SHADOW;
318   }
319   else if( stringKey == UNDERLINE_PROPERTY )
320   {
321     result = Toolkit::TextVisual::Property::UNDERLINE;
322   }
323   else if( stringKey == OUTLINE_PROPERTY )
324   {
325     result = Toolkit::DevelTextVisual::Property::OUTLINE;
326   }
327   else if( stringKey == BACKGROUND_PROPERTY )
328   {
329     result = Toolkit::DevelTextVisual::Property::BACKGROUND;
330   }
331
332   return result;
333 }
334
335 } // unnamed namespace
336
337 TextVisualPtr TextVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
338 {
339   TextVisualPtr TextVisualPtr( new TextVisual( factoryCache ) );
340   TextVisualPtr->SetProperties( properties );
341   return TextVisualPtr;
342 }
343
344 void TextVisual::ConvertStringKeysToIndexKeys( Property::Map& propertyMap )
345 {
346   Property::Map outMap;
347
348   for( Property::Map::SizeType index = 0u, count = propertyMap.Count(); index < count; ++index )
349   {
350     const KeyValuePair& keyValue = propertyMap.GetKeyValue( index );
351
352     Property::Index indexKey = keyValue.first.indexKey;
353
354     if ( keyValue.first.type == Property::Key::STRING )
355     {
356       indexKey = StringKeyToIndexKey( keyValue.first.stringKey );
357     }
358
359     outMap.Insert( indexKey, keyValue.second );
360   }
361
362   propertyMap = outMap;
363 }
364
365 float TextVisual::GetHeightForWidth( float width )
366 {
367   return mController->GetHeightForWidth( width );
368 }
369
370 void TextVisual::GetNaturalSize( Vector2& naturalSize )
371 {
372   naturalSize = mController->GetNaturalSize().GetVectorXY();
373 }
374
375 void TextVisual::DoCreatePropertyMap( Property::Map& map ) const
376 {
377   Property::Value value;
378
379   map.Clear();
380   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
381
382   std::string text;
383   mController->GetText( text );
384   map.Insert( Toolkit::TextVisual::Property::TEXT, text );
385
386   map.Insert( Toolkit::TextVisual::Property::FONT_FAMILY, mController->GetDefaultFontFamily() );
387
388   GetFontStyleProperty( mController, value, Text::FontStyle::DEFAULT );
389   map.Insert( Toolkit::TextVisual::Property::FONT_STYLE, value );
390
391   map.Insert( Toolkit::TextVisual::Property::POINT_SIZE, mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ) );
392
393   map.Insert( Toolkit::TextVisual::Property::MULTI_LINE, mController->IsMultiLineEnabled() );
394
395   map.Insert( Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT, mController->GetHorizontalAlignment() );
396
397   map.Insert( Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT, mController->GetVerticalAlignment() );
398
399   map.Insert( Toolkit::TextVisual::Property::TEXT_COLOR, mController->GetDefaultColor() );
400
401   map.Insert( Toolkit::TextVisual::Property::ENABLE_MARKUP, mController->IsMarkupProcessorEnabled() );
402
403   GetShadowProperties( mController, value, Text::EffectStyle::DEFAULT );
404   map.Insert( Toolkit::TextVisual::Property::SHADOW, value );
405
406   GetUnderlineProperties( mController, value, Text::EffectStyle::DEFAULT );
407   map.Insert( Toolkit::TextVisual::Property::UNDERLINE, value );
408
409   GetOutlineProperties( mController, value, Text::EffectStyle::DEFAULT );
410   map.Insert( Toolkit::DevelTextVisual::Property::OUTLINE, value );
411
412   GetBackgroundProperties( mController, value, Text::EffectStyle::DEFAULT );
413   map.Insert( Toolkit::DevelTextVisual::Property::BACKGROUND, value );
414 }
415
416 void TextVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
417 {
418   map.Clear();
419   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
420   std::string text;
421   mController->GetText( text );
422   map.Insert( Toolkit::TextVisual::Property::TEXT, text );
423 }
424
425
426 TextVisual::TextVisual( VisualFactoryCache& factoryCache )
427 : Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
428   mController( Text::Controller::New() ),
429   mTypesetter( Text::Typesetter::New( mController->GetTextModel() ) ),
430   mAnimatableTextColorPropertyIndex( Property::INVALID_INDEX ),
431   mRendererUpdateNeeded( false )
432 {
433 }
434
435 TextVisual::~TextVisual()
436 {
437 }
438
439 void TextVisual::DoSetProperties( const Property::Map& propertyMap )
440 {
441   for( Property::Map::SizeType index = 0u, count = propertyMap.Count(); index < count; ++index )
442   {
443     const KeyValuePair& keyValue = propertyMap.GetKeyValue( index );
444
445     Property::Index indexKey = keyValue.first.indexKey;
446
447     if( keyValue.first.type == Property::Key::STRING )
448     {
449       indexKey = StringKeyToIndexKey( keyValue.first.stringKey );
450     }
451
452     DoSetProperty( indexKey, keyValue.second );
453   }
454
455   // Elide the text if it exceeds the boundaries.
456   mController->SetTextElideEnabled( true );
457
458   // Retrieve the layout engine to set the cursor's width.
459   Text::Layout::Engine& engine = mController->GetLayoutEngine();
460
461   // Sets 0 as cursor's width.
462   engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
463 }
464
465 void TextVisual::DoSetOnStage( Actor& actor )
466 {
467   mControl = actor;
468
469   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
470   Shader shader = GetTextShader(mFactoryCache, TextType::SINGLE_COLOR_TEXT, TextType::NO_EMOJI, TextType::NO_STYLES);
471
472   mImpl->mRenderer = Renderer::New( geometry, shader );
473   mImpl->mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
474
475   // Enable the pre-multiplied alpha to improve the text quality
476   EnablePreMultipliedAlpha(true);
477
478   const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
479   Dali::Property::Index shaderTextColorIndex = mImpl->mRenderer.RegisterProperty( "uTextColorAnimatable", defaultColor );
480
481   if ( mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX )
482   {
483     // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer.
484     if( shaderTextColorIndex != Property::INVALID_INDEX )
485     {
486       Constraint constraint = Constraint::New<Vector4>( mImpl->mRenderer, shaderTextColorIndex, EqualToConstraint() );
487       constraint.AddSource( Source( actor, mAnimatableTextColorPropertyIndex ) );
488       constraint.Apply();
489     }
490   }
491
492   // Renderer needs textures and to be added to control
493   mRendererUpdateNeeded = true;
494
495   UpdateRenderer();
496 }
497
498 void TextVisual::DoSetOffStage( Actor& actor )
499 {
500   if( mImpl->mRenderer )
501   {
502     // Removes the renderer from the actor.
503     actor.RemoveRenderer( mImpl->mRenderer );
504
505     RemoveTextureSet();
506
507     // Resets the renderer.
508     mImpl->mRenderer.Reset();
509   }
510
511   // Resets the control handle.
512   mControl.Reset();
513 }
514
515 void TextVisual::OnSetTransform()
516 {
517   UpdateRenderer();
518 }
519
520 void TextVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
521 {
522   switch( index )
523   {
524     case Toolkit::TextVisual::Property::ENABLE_MARKUP:
525     {
526       const bool enableMarkup = propertyValue.Get<bool>();
527       mController->SetMarkupProcessorEnabled( enableMarkup );
528       break;
529     }
530     case Toolkit::TextVisual::Property::TEXT:
531     {
532       mController->SetText( propertyValue.Get<std::string>() );
533       break;
534     }
535     case Toolkit::TextVisual::Property::FONT_FAMILY:
536     {
537       SetFontFamilyProperty( mController, propertyValue );
538       break;
539     }
540     case Toolkit::TextVisual::Property::FONT_STYLE:
541     {
542       SetFontStyleProperty( mController, propertyValue, Text::FontStyle::DEFAULT );
543       break;
544     }
545     case Toolkit::TextVisual::Property::POINT_SIZE:
546     {
547       const float pointSize = propertyValue.Get<float>();
548       if( !Equals( mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
549       {
550         mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
551       }
552       break;
553     }
554     case Toolkit::TextVisual::Property::MULTI_LINE:
555     {
556       mController->SetMultiLineEnabled( propertyValue.Get<bool>() );
557       break;
558     }
559     case Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT:
560     {
561       if( mController )
562       {
563         Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
564         if( Toolkit::Text::GetHorizontalAlignmentEnumeration( propertyValue, alignment ) )
565         {
566           mController->SetHorizontalAlignment( alignment );
567         }
568       }
569       break;
570     }
571     case Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT:
572     {
573       if( mController )
574       {
575         Toolkit::Text::VerticalAlignment::Type alignment( static_cast< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
576         if( Toolkit::Text::GetVerticalAlignmentEnumeration( propertyValue, alignment) )
577         {
578           mController->SetVerticalAlignment( alignment );
579         }
580       }
581       break;
582     }
583     case Toolkit::TextVisual::Property::TEXT_COLOR:
584     {
585       const Vector4& textColor = propertyValue.Get< Vector4 >();
586       if( mController->GetDefaultColor() != textColor )
587       {
588         mController->SetDefaultColor( textColor );
589       }
590       break;
591     }
592     case Toolkit::TextVisual::Property::SHADOW:
593     {
594       SetShadowProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
595       break;
596     }
597     case Toolkit::TextVisual::Property::UNDERLINE:
598     {
599       SetUnderlineProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
600       break;
601     }
602     case Toolkit::DevelTextVisual::Property::OUTLINE:
603     {
604       SetOutlineProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
605       break;
606     }
607     case Toolkit::DevelTextVisual::Property::BACKGROUND:
608     {
609       SetBackgroundProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
610       break;
611     }
612   }
613 }
614
615 void TextVisual::UpdateRenderer()
616 {
617   Actor control = mControl.GetHandle();
618   if( !control )
619   {
620     // Nothing to do.
621     return;
622   }
623
624   // Calculates the size to be used to relayout.
625   Vector2 relayoutSize;
626
627   const bool isWidthRelative = fabsf( mImpl->mTransform.mOffsetSizeMode.z ) < Math::MACHINE_EPSILON_1000;
628   const bool isHeightRelative = fabsf( mImpl->mTransform.mOffsetSizeMode.w ) < Math::MACHINE_EPSILON_1000;
629
630   // Round the size and offset to avoid pixel alignement issues.
631   relayoutSize.width = floorf( 0.5f + ( isWidthRelative ? mImpl->mControlSize.width * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width ) );
632   relayoutSize.height = floorf( 0.5f + ( isHeightRelative ? mImpl->mControlSize.height * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height ) );
633
634   std::string text;
635   mController->GetText( text );
636
637   if( ( fabsf( relayoutSize.width ) < Math::MACHINE_EPSILON_1000 ) || ( fabsf( relayoutSize.height ) < Math::MACHINE_EPSILON_1000 ) || text.empty() )
638   {
639     // Removes the texture set.
640     RemoveTextureSet();
641
642     // Remove any renderer previously set.
643     if( mImpl->mRenderer )
644     {
645       control.RemoveRenderer( mImpl->mRenderer );
646     }
647
648     // Nothing else to do if the relayout size is zero.
649     ResourceReady( Toolkit::Visual::ResourceStatus::READY );
650     return;
651   }
652
653   const Text::Controller::UpdateTextType updateTextType = mController->Relayout( relayoutSize );
654
655   if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType )
656    || mRendererUpdateNeeded )
657   {
658     mRendererUpdateNeeded = false;
659
660     // Removes the texture set.
661     RemoveTextureSet();
662
663     // Remove any renderer previously set.
664     if( mImpl->mRenderer )
665     {
666       control.RemoveRenderer( mImpl->mRenderer );
667     }
668
669     if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) &&
670         ( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) )
671     {
672       // Check whether it is a markup text with multiple text colors
673       const Vector4* const colorsBuffer = mController->GetTextModel()->GetColors();
674       bool hasMultipleTextColors = ( NULL != colorsBuffer );
675
676       // Check whether the text contains any color glyph
677       bool containsColorGlyph = false;
678
679       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
680       const Text::GlyphInfo* const glyphsBuffer = mController->GetTextModel()->GetGlyphs();
681       const Text::Length numberOfGlyphs = mController->GetTextModel()->GetNumberOfGlyphs();
682       for ( Text::Length glyphIndex = 0; glyphIndex < numberOfGlyphs; glyphIndex++ )
683       {
684         // Retrieve the glyph's info.
685         const Text::GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
686
687         // Whether the current glyph is a color one.
688         if( fontClient.IsColorGlyph( glyphInfo->fontId, glyphInfo->index ) )
689         {
690           containsColorGlyph = true;
691           break;
692         }
693       }
694
695       // Check whether the text contains any style colors (e.g. underline color, shadow color, etc.)
696
697       bool shadowEnabled = false;
698       const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
699       if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
700       {
701         shadowEnabled = true;
702       }
703
704       const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
705       const bool outlineEnabled = ( mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1 );
706       const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();;
707
708       const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled );
709
710       TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled );
711       mImpl->mRenderer.SetTextures( textureSet );
712
713       Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled );
714       mImpl->mRenderer.SetShader(shader);
715
716       mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
717
718       mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
719
720       mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
721
722       //Register transform properties
723       mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
724
725       control.AddRenderer( mImpl->mRenderer );
726
727       // Text rendered and ready to display
728       ResourceReady( Toolkit::Visual::ResourceStatus::READY );
729     }
730   }
731 }
732
733 void TextVisual::RemoveTextureSet()
734 {
735   if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
736   {
737     // Removes the text's image from the texture atlas.
738     Vector4 atlasRect;
739
740     const Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
741     if( index != Property::INVALID_INDEX )
742     {
743       const Property::Value& atlasRectValue = mImpl->mRenderer.GetProperty( index );
744       atlasRectValue.Get( atlasRect );
745
746       const TextureSet& textureSet = mImpl->mRenderer.GetTextures();
747       mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
748     }
749   }
750 }
751
752 TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
753 {
754   // Filter mode needs to be set to linear to produce better quality while scaling.
755   Sampler sampler = Sampler::New();
756   sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
757
758   TextureSet textureSet = TextureSet::New();
759
760   // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
761   Pixel::Format textPixelFormat = ( containsColorGlyph || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8;
762
763   // Check the text direction
764   Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
765
766   // Create a texture for the text without any styles
767   PixelData data = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
768
769   // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
770   // In that case, create a texture. TODO: should tile the text.
771
772   Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
773                                   data.GetPixelFormat(),
774                                   data.GetWidth(),
775                                   data.GetHeight() );
776
777   texture.Upload( data );
778
779   textureSet.SetTexture( 0u, texture );
780   textureSet.SetSampler( 0u, sampler );
781
782   if ( styleEnabled )
783   {
784     // Create RGBA texture for all the text styles (without the text itself)
785     PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
786
787     Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
788                                          styleData.GetPixelFormat(),
789                                          styleData.GetWidth(),
790                                          styleData.GetHeight() );
791
792     styleTexture.Upload( styleData );
793
794     textureSet.SetTexture( 1u, styleTexture );
795     textureSet.SetSampler( 1u, sampler );
796   }
797
798   if ( containsColorGlyph && !hasMultipleTextColors )
799   {
800     // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
801     PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
802
803     Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
804                                         maskData.GetPixelFormat(),
805                                         maskData.GetWidth(),
806                                         maskData.GetHeight() );
807
808     maskTexture.Upload( maskData );
809
810     if ( !styleEnabled )
811     {
812       textureSet.SetTexture( 1u, maskTexture );
813       textureSet.SetSampler( 1u, sampler );
814     }
815     else
816     {
817       textureSet.SetTexture( 2u, maskTexture );
818       textureSet.SetSampler( 2u, sampler );
819     }
820   }
821
822   return textureSet;
823 }
824
825 Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
826 {
827   Shader shader;
828
829   if( hasMultipleTextColors && !styleEnabled )
830   {
831     // We don't animate text color if the text contains multiple colors
832     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT );
833     if( !shader )
834     {
835       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT );
836       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
837       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT, shader );
838     }
839   }
840   else if( hasMultipleTextColors && styleEnabled )
841   {
842     // We don't animate text color if the text contains multiple colors
843     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
844     if( !shader )
845     {
846       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
847       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
848       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE, shader );
849     }
850   }
851   else if( !hasMultipleTextColors && !containsColorGlyph && !styleEnabled )
852   {
853     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT );
854     if( !shader )
855     {
856       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT );
857       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
858       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT, shader );
859     }
860   }
861   else if( !hasMultipleTextColors && !containsColorGlyph && styleEnabled )
862   {
863     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
864     if( !shader )
865     {
866       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
867       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
868       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE, shader );
869     }
870   }
871   else if( !hasMultipleTextColors && containsColorGlyph && !styleEnabled )
872   {
873     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
874     if( !shader )
875     {
876       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
877       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
878       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI, shader );
879     }
880   }
881   else // if( !hasMultipleTextColors && containsColorGlyph && styleEnabled )
882   {
883     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
884     if( !shader )
885     {
886       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
887       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
888       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI, shader );
889     }
890   }
891
892   return shader;
893 }
894
895 } // namespace Internal
896
897 } // namespace Toolkit
898
899 } // namespace Dali