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