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