Fix corner radius shader of the ImageVisual
[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 ),
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   Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( control.GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
615
616   const Text::Controller::UpdateTextType updateTextType = mController->Relayout( relayoutSize, layoutDirection );
617
618   if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType )
619    || mRendererUpdateNeeded )
620   {
621     mRendererUpdateNeeded = false;
622
623     // Removes the texture set.
624     RemoveTextureSet();
625
626     // Remove any renderer previously set.
627     if( mImpl->mRenderer )
628     {
629       control.RemoveRenderer( mImpl->mRenderer );
630     }
631
632     if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) &&
633         ( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) )
634     {
635       // Check whether it is a markup text with multiple text colors
636       const Vector4* const colorsBuffer = mController->GetTextModel()->GetColors();
637       bool hasMultipleTextColors = ( NULL != colorsBuffer );
638
639       // Check whether the text contains any color glyph
640       bool containsColorGlyph = false;
641
642       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
643       const Text::GlyphInfo* const glyphsBuffer = mController->GetTextModel()->GetGlyphs();
644       const Text::Length numberOfGlyphs = mController->GetTextModel()->GetNumberOfGlyphs();
645       for ( Text::Length glyphIndex = 0; glyphIndex < numberOfGlyphs; glyphIndex++ )
646       {
647         // Retrieve the glyph's info.
648         const Text::GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
649
650         // Whether the current glyph is a color one.
651         if( fontClient.IsColorGlyph( glyphInfo->fontId, glyphInfo->index ) )
652         {
653           containsColorGlyph = true;
654           break;
655         }
656       }
657
658       // Check whether the text contains any style colors (e.g. underline color, shadow color, etc.)
659
660       bool shadowEnabled = false;
661       const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
662       if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
663       {
664         shadowEnabled = true;
665       }
666
667       const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
668       const bool outlineEnabled = ( mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1 );
669       const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();;
670
671       const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled );
672
673       TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled );
674       mImpl->mRenderer.SetTextures( textureSet );
675
676       Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled );
677       mImpl->mRenderer.SetShader(shader);
678
679       mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
680
681       mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
682
683       mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
684
685       //Register transform properties
686       mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
687
688       control.AddRenderer( mImpl->mRenderer );
689
690       // Text rendered and ready to display
691       ResourceReady( Toolkit::Visual::ResourceStatus::READY );
692     }
693   }
694 }
695
696 void TextVisual::RemoveTextureSet()
697 {
698   if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
699   {
700     // Removes the text's image from the texture atlas.
701     Vector4 atlasRect;
702
703     const Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
704     if( index != Property::INVALID_INDEX )
705     {
706       const Property::Value& atlasRectValue = mImpl->mRenderer.GetProperty( index );
707       atlasRectValue.Get( atlasRect );
708
709       const TextureSet& textureSet = mImpl->mRenderer.GetTextures();
710       mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
711     }
712   }
713 }
714
715 TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
716 {
717   // Filter mode needs to be set to linear to produce better quality while scaling.
718   Sampler sampler = Sampler::New();
719   sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
720
721   TextureSet textureSet = TextureSet::New();
722
723   // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
724   Pixel::Format textPixelFormat = ( containsColorGlyph || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8;
725
726   // Check the text direction
727   Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
728
729   // Create a texture for the text without any styles
730   PixelData data = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
731
732   // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
733   // In that case, create a texture. TODO: should tile the text.
734
735   Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
736                                   data.GetPixelFormat(),
737                                   data.GetWidth(),
738                                   data.GetHeight() );
739
740   texture.Upload( data );
741
742   textureSet.SetTexture( 0u, texture );
743   textureSet.SetSampler( 0u, sampler );
744
745   if ( styleEnabled )
746   {
747     // Create RGBA texture for all the text styles (without the text itself)
748     PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
749
750     Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
751                                          styleData.GetPixelFormat(),
752                                          styleData.GetWidth(),
753                                          styleData.GetHeight() );
754
755     styleTexture.Upload( styleData );
756
757     textureSet.SetTexture( 1u, styleTexture );
758     textureSet.SetSampler( 1u, sampler );
759   }
760
761   if ( containsColorGlyph && !hasMultipleTextColors )
762   {
763     // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
764     PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
765
766     Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
767                                         maskData.GetPixelFormat(),
768                                         maskData.GetWidth(),
769                                         maskData.GetHeight() );
770
771     maskTexture.Upload( maskData );
772
773     if ( !styleEnabled )
774     {
775       textureSet.SetTexture( 1u, maskTexture );
776       textureSet.SetSampler( 1u, sampler );
777     }
778     else
779     {
780       textureSet.SetTexture( 2u, maskTexture );
781       textureSet.SetSampler( 2u, sampler );
782     }
783   }
784
785   return textureSet;
786 }
787
788 Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
789 {
790   Shader shader;
791
792   if( hasMultipleTextColors && !styleEnabled )
793   {
794     // We don't animate text color if the text contains multiple colors
795     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT );
796     if( !shader )
797     {
798       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT );
799       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
800       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT, shader );
801     }
802   }
803   else if( hasMultipleTextColors && styleEnabled )
804   {
805     // We don't animate text color if the text contains multiple colors
806     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
807     if( !shader )
808     {
809       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
810       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
811       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE, shader );
812     }
813   }
814   else if( !hasMultipleTextColors && !containsColorGlyph && !styleEnabled )
815   {
816     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT );
817     if( !shader )
818     {
819       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT );
820       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
821       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT, shader );
822     }
823   }
824   else if( !hasMultipleTextColors && !containsColorGlyph && styleEnabled )
825   {
826     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
827     if( !shader )
828     {
829       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
830       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
831       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE, shader );
832     }
833   }
834   else if( !hasMultipleTextColors && containsColorGlyph && !styleEnabled )
835   {
836     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
837     if( !shader )
838     {
839       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
840       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
841       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI, shader );
842     }
843   }
844   else // if( !hasMultipleTextColors && containsColorGlyph && styleEnabled )
845   {
846     shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
847     if( !shader )
848     {
849       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
850       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
851       factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI, shader );
852     }
853   }
854
855   return shader;
856 }
857
858 } // namespace Internal
859
860 } // namespace Toolkit
861
862 } // namespace Dali