Text cleaning.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / text / text-utils-devel.cpp
1 /*
2  * Copyright (c) 2019 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 // FILE HEADER
19 #include <dali-toolkit/devel-api/text/text-utils-devel.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/text-abstraction/font-client.h>
23 #include <dali/devel-api/text-abstraction/text-renderer.h>
24 #include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/scripting/enum-helper.h>
27 #include <cstring>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/internal/text/bidirectional-support.h>
31 #include <dali-toolkit/internal/text/character-set-conversion.h>
32 #include <dali-toolkit/internal/text/color-segmentation.h>
33 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
34 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
35 #include <dali-toolkit/internal/text/markup-processor.h>
36 #include <dali-toolkit/internal/text/multi-language-support.h>
37 #include <dali-toolkit/internal/text/segmentation.h>
38 #include <dali-toolkit/internal/text/shaper.h>
39 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
40 #include <dali-toolkit/internal/text/text-font-style.h>
41 #include <dali-toolkit/internal/text/text-model.h>
42
43 namespace Dali
44 {
45
46 using namespace TextAbstraction;
47
48 namespace Toolkit
49 {
50 using namespace Text;
51
52 namespace DevelText
53 {
54
55 namespace Layout
56 {
57
58 /**
59  * @brief The text's layout.
60  */
61 enum Type
62 {
63   SINGLELINE, ///< The text is laid out on a single line.
64   MULTILINE,  ///< The text is laid out in multiple lines.
65   CIRCULAR,   ///< The text is laid out on a single line following a circular path.
66 };
67
68 } // namespace Layout
69
70 namespace CircularAlignment
71 {
72
73 /**
74  * @brief The enumerations for the circular alignment.
75  */
76 enum Type
77 {
78   BEGIN,  ///< The text is aligned to the @p begin angle of the arc (or to the @p begin+increment if it's a RTL text).
79   CENTER, ///< The text is centered within the arc.
80   END,    ///< The text is aligned to the @p begin+increment angle of the arc (or to the @p begin if it's a RTL text).
81 };
82
83 } // namespace CircularAlignment
84
85 const float TO_POINT_26_DOT_6 = 64.f;
86 const float TO_FLOAT = 1.f / 255.f;
87 const float TO_UCHAR = 255.f;
88 const bool RTL = true;
89 const float TWO_PI = 2.f * Dali::Math::PI; ///< 360 degrees in radians
90 const float RAD_135 = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians;
91 const float RAD_225 = RAD_135    + Math::PI_2; ///< 225 degrees in radians;
92 const float RAD_270 = 3.f * Math::PI_2;        ///< 270 degrees in radians;
93 const float RAD_315 = RAD_225    + Math::PI_2; ///< 315 degrees in radians;
94
95 DALI_ENUM_TO_STRING_TABLE_BEGIN( LAYOUT_TYPE )
96 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, SINGLELINE )
97 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, MULTILINE )
98 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, CIRCULAR )
99 DALI_ENUM_TO_STRING_TABLE_END( LAYOUT_TYPE )
100
101 DALI_ENUM_TO_STRING_TABLE_BEGIN( CIRCULAR_ALIGNMENT_TYPE )
102 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, BEGIN )
103 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, CENTER )
104 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, END )
105 DALI_ENUM_TO_STRING_TABLE_END( CIRCULAR_ALIGNMENT_TYPE )
106
107 bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout)
108 {
109   return Scripting::GetEnumerationProperty(propertyValue, LAYOUT_TYPE_TABLE, LAYOUT_TYPE_TABLE_COUNT, layout);
110 }
111
112 bool GetCircularAlignmentEnumeration(const Property::Value& propertyValue, DevelText::CircularAlignment::Type& circularAlignment)
113 {
114   return Scripting::GetEnumerationProperty(propertyValue, CIRCULAR_ALIGNMENT_TYPE_TABLE, CIRCULAR_ALIGNMENT_TYPE_TABLE_COUNT, circularAlignment);
115 }
116
117 Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout )
118 {
119   if( textParameters.text.empty() )
120   {
121     Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( textParameters.textWidth,
122                                                                           textParameters.textHeight,
123                                                                           Dali::Pixel::RGBA8888 );
124
125     const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
126     unsigned char* buffer = pixelBuffer.GetBuffer();
127     memset(buffer, 0, bufferSize);
128
129     return pixelBuffer;
130   }
131
132   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
133   FontClient fontClient = FontClient::Get();
134   MetricsPtr metrics;
135   Text::Layout::Engine layoutEngine;             ///< The layout engine.
136   Text::ModelPtr textModel = Text::Model::New(); ///< Pointer to the text's model.
137   Vector<ColorBlendingMode> blendingMode;        ///< How embedded items and bitmap font glyphs are blended with color text.
138   Vector<bool> isEmoji;                          ///< Whether the glyph is an emoji.
139
140   // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
141   metrics = Metrics::New( fontClient );
142   layoutEngine.SetMetrics( metrics );
143
144   TextAbstraction::TextRenderer::Parameters rendererParameters( textModel->mVisualModel->mGlyphs,
145                                                                 textModel->mVisualModel->mGlyphPositions,
146                                                                 textModel->mVisualModel->mColors,
147                                                                 textModel->mVisualModel->mColorIndices,
148                                                                 blendingMode,
149                                                                 isEmoji );
150
151   rendererParameters.width = textParameters.textWidth;
152   rendererParameters.height = textParameters.textHeight;
153   rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888
154
155   Vector<Character>& utf32Characters = textModel->mLogicalModel->mText;                                             // Characters encoded in utf32.
156   Vector<Character> mirroredUtf32Characters;                                                                        // The utf32Characters Characters but mirrored if there are RTL text.
157   Vector<LineBreakInfo>& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo;                                  // The line break info.
158   Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
159   Vector<FontDescriptionRun>& fontDescriptionRuns = textModel->mLogicalModel->mFontDescriptionRuns;                 // Desired font descriptions.
160   Vector<FontRun>& validFonts = textModel->mLogicalModel->mFontRuns;                                                // Validated fonts.
161   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = textModel->mLogicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph.
162   //Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = textModel->mLogicalModel->mBidirectionalLineInfo;     // The bidirectional info per line.
163   Vector<CharacterDirection>& directions = textModel->mLogicalModel->mCharacterDirections;                          // Character's directions.
164   Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns;                                               // colors of the text.
165
166   Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters;                        // Glyphs to character map.
167   Vector<GlyphIndex>& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph;                              // Characters to glyphs map.
168   Vector<Length>& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
169   Vector<Length>& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
170   Vector<LineRun>& lines = textModel->mVisualModel->mLines;                                                         // The laid out lines.
171
172   Vector<GlyphIndex> newParagraphGlyphs;                   // Glyphs for the new paragraph characters.
173
174   // the default font's description.
175   FontDescription defaultFontDescription;
176   PointSize26Dot6 defaultPointSize = FontClient::DEFAULT_POINT_SIZE;
177
178   Length numberOfCharacters = 0u;                          // The number of characters (not glyphs!).
179   bool isTextMirrored = false;                             // Whether the text has been mirrored.
180
181   const uint8_t* utf8 = NULL;                              // pointer to the first character of the text (encoded in utf8)
182   Length textSize = 0u;                                    // The length of the utf8 string.
183
184   ////////////////////////////////////////////////////////////////////////////////
185   // Process the markup string if the mark-up processor is enabled.
186   ////////////////////////////////////////////////////////////////////////////////
187
188   MarkupProcessData markupProcessData( colorRuns,
189                                        fontDescriptionRuns,
190                                        textModel->mLogicalModel->mEmbeddedItems );
191
192   if (textParameters.markupEnabled)
193   {
194     ProcessMarkupString(textParameters.text, markupProcessData);
195     textSize = markupProcessData.markupProcessedText.size();
196
197     // This is a bit horrible but std::string returns a (signed) char*
198     utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
199   }
200   else
201   {
202     textSize = textParameters.text.size();
203
204     // This is a bit horrible but std::string returns a (signed) char*
205     utf8 = reinterpret_cast<const uint8_t*>(textParameters.text.c_str());
206   }
207
208   ////////////////////////////////////////////////////////////////////////////////
209   // Convert from utf8 to utf32
210   ////////////////////////////////////////////////////////////////////////////////
211
212   utf32Characters.Resize(textSize);
213
214   // Transform a text array encoded in utf8 into an array encoded in utf32.
215   // It returns the actual number of characters.
216   numberOfCharacters = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
217   utf32Characters.Resize( numberOfCharacters );
218
219   ////////////////////////////////////////////////////////////////////////////////
220   // Retrieve the Line and Word Break Info.
221   ////////////////////////////////////////////////////////////////////////////////
222
223   lineBreakInfo.Resize( numberOfCharacters, LINE_NO_BREAK );
224
225   SetLineBreakInfo( utf32Characters,
226                     0u,
227                     numberOfCharacters,
228                     lineBreakInfo );
229
230   ////////////////////////////////////////////////////////////////////////////////
231   // Retrieve the script runs.
232   ////////////////////////////////////////////////////////////////////////////////
233
234   multilanguageSupport.SetScripts( utf32Characters,
235                                    0u,
236                                    numberOfCharacters,
237                                    scripts );
238
239   // Check if there are emojis.
240   // If there are an RGBA8888 pixel format is needed.
241   for( const auto& run : scripts )
242   {
243     if( run.script == TextAbstraction::Script::EMOJI )
244     {
245       rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888;
246       break;
247     }
248   }
249
250   ////////////////////////////////////////////////////////////////////////////////
251   // Retrieve the font runs.
252   ////////////////////////////////////////////////////////////////////////////////
253
254   // Set the description font run with the given text parameters.
255   FontDescriptionRun fontDescriptionRun;
256   fontDescriptionRun.characterRun.characterIndex = 0u;
257   fontDescriptionRun.characterRun.numberOfCharacters = numberOfCharacters;
258
259   fontDescriptionRun.familyLength = 0u;
260   fontDescriptionRun.familyName = nullptr;
261   fontDescriptionRun.familyDefined = !textParameters.fontFamily.empty();
262   if( fontDescriptionRun.familyDefined )
263   {
264     // The allocated memory will be freed when the logical model is destroyed.
265     fontDescriptionRun.familyLength = textParameters.fontFamily.size();
266     fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
267     memcpy( fontDescriptionRun.familyName, textParameters.fontFamily.c_str(), fontDescriptionRun.familyLength );
268   }
269
270   fontDescriptionRun.weightDefined = !textParameters.fontWeight.empty();
271   if( fontDescriptionRun.weightDefined )
272   {
273     fontDescriptionRun.weight = StringToWeight( textParameters.fontWeight.c_str() );
274   }
275
276   fontDescriptionRun.widthDefined = !textParameters.fontWidth.empty();
277   if( fontDescriptionRun.widthDefined )
278   {
279     fontDescriptionRun.width = StringToWidth( textParameters.fontWidth.c_str() );
280   }
281
282   fontDescriptionRun.slantDefined = !textParameters.fontSlant.empty();
283   if( fontDescriptionRun.slantDefined )
284   {
285     fontDescriptionRun.slant = StringToSlant( textParameters.fontSlant.c_str() );
286   }
287
288   fontDescriptionRun.sizeDefined = !EqualsZero( textParameters.fontSize );
289   if( fontDescriptionRun.sizeDefined )
290   {
291     fontDescriptionRun.size = static_cast<unsigned int>( textParameters.fontSize * TO_POINT_26_DOT_6 );
292   }
293
294   fontDescriptionRuns.PushBack( fontDescriptionRun );
295
296   // Validates the fonts. If there is a character with no assigned font it sets a default one.
297   // After this call, fonts are validated.
298   multilanguageSupport.ValidateFonts( utf32Characters,
299                                       scripts,
300                                       fontDescriptionRuns,
301                                       defaultFontDescription,
302                                       defaultPointSize,
303                                       0u,
304                                       numberOfCharacters,
305                                       validFonts );
306
307   ////////////////////////////////////////////////////////////////////////////////
308   // Retrieve the Bidirectional info.
309   ////////////////////////////////////////////////////////////////////////////////
310
311   bidirectionalInfo.Reserve( 1u );
312
313   SetBidirectionalInfo( utf32Characters,
314                         scripts,
315                         lineBreakInfo,
316                         0u,
317                         numberOfCharacters,
318                         bidirectionalInfo );
319
320   const bool hasBidirectionalText = 0u != bidirectionalInfo.Count();
321   if( hasBidirectionalText )
322   {
323     // Only set the character directions if there is right to left characters.
324     GetCharactersDirection( bidirectionalInfo,
325                             numberOfCharacters,
326                             0u,
327                             numberOfCharacters,
328                             directions );
329
330     // This paragraph has right to left text. Some characters may need to be mirrored.
331     // TODO: consider if the mirrored string can be stored as well.
332
333     isTextMirrored = GetMirroredText( utf32Characters,
334                                       directions,
335                                       bidirectionalInfo,
336                                       0u,
337                                       numberOfCharacters,
338                                       mirroredUtf32Characters );
339   }
340
341   ////////////////////////////////////////////////////////////////////////////////
342   // Retrieve the glyphs. Text shaping
343   ////////////////////////////////////////////////////////////////////////////////
344
345   const Vector<Character>& textToShape = isTextMirrored ? mirroredUtf32Characters : utf32Characters;
346
347   newParagraphGlyphs.Reserve( 1u );
348
349   // Shapes the text.
350   ShapeText( textToShape,
351              lineBreakInfo,
352              scripts,
353              validFonts,
354              0u,
355              0u,
356              numberOfCharacters,
357              rendererParameters.glyphs,
358              glyphsToCharacters,
359              charactersPerGlyph,
360              newParagraphGlyphs );
361
362   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
363   textModel->mVisualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
364   textModel->mVisualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
365
366   const Length numberOfGlyphs = rendererParameters.glyphs.Count();
367
368   // Once the text has been shaped and the glyphs created it's possible to replace the font id of those glyphs
369   // that represent an image or an item and create the embedded item layout info.
370   // Note: the position of the embedded item can't be set until the text is laid-out.
371   embeddedItemLayout.Reserve( textModel->mLogicalModel->mEmbeddedItems.Count() );
372   for( const auto& item : textModel->mLogicalModel->mEmbeddedItems )
373   {
374     // Get the glyph that matches with the character index.
375     const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
376     GlyphInfo& glyph = rendererParameters.glyphs[glyphIndex];
377
378     glyph.fontId = 0u;
379     Pixel::Format pixelFormat = Pixel::A8;
380     TextAbstraction::FontClient::EmbeddedItemDescription description = { std::string( item.url, item.urlLength ), item.width, item.height, item.colorBlendingMode };
381     glyph.index = fontClient.CreateEmbeddedItem( description, pixelFormat ); // Set here an index to an item.
382
383     if( ( Pixel::RGBA8888 == pixelFormat ) || ( Pixel::BGRA8888 == pixelFormat ) )
384     {
385       rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888;
386     }
387
388     // If the url is empty the item is going to be added after the text is rendered. It's needed to store the layout here.
389     if( description.url.empty() )
390     {
391       EmbeddedItemInfo embeddedInfo =
392       {
393         item.characterIndex,
394         glyphIndex,
395         Vector2::ZERO,
396         Size( static_cast<float>( item.width ), static_cast<float>( item.height ) ),
397         Size( static_cast<float>( item.width ), static_cast<float>( item.height ) ),
398         Degree( 0.f ),
399         item.colorBlendingMode
400       };
401
402       embeddedItemLayout.PushBack( embeddedInfo );
403     }
404   }
405
406   ////////////////////////////////////////////////////////////////////////////////
407   // Retrieve the glyph's metrics.
408   ////////////////////////////////////////////////////////////////////////////////
409
410   metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs );
411
412   ////////////////////////////////////////////////////////////////////////////////
413   // Set the color runs in glyphs.
414   ////////////////////////////////////////////////////////////////////////////////
415
416   SetColorSegmentationInfo( colorRuns,
417                             charactersToGlyph,
418                             glyphsPerCharacter,
419                             0u,
420                             0u,
421                             numberOfCharacters,
422                             textModel->mVisualModel->mColors,
423                             textModel->mVisualModel->mColorIndices );
424
425   // Insert the default color at the beginning of the vector.
426   textModel->mVisualModel->mColors.Insert( textModel->mVisualModel->mColors.Begin(),textParameters.textColor );
427
428   // Set how the embedded items are blended with text color.
429   blendingMode.Resize( numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE );
430
431   if( !textParameters.isTextColorSet )
432   {
433     // Traverse the color runs.
434     for( const auto& run : colorRuns )
435     {
436       const GlyphIndex firstGlyph = textModel->mVisualModel->mCharactersToGlyph[run.characterRun.characterIndex];
437       const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
438       const GlyphIndex lastGlyphPlusOne = textModel->mVisualModel->mCharactersToGlyph[lastCharacter] + textModel->mVisualModel->mGlyphsPerCharacter[lastCharacter];
439
440       for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index )
441       {
442         blendingMode[index] = ColorBlendingMode::MULTIPLY;
443       }
444     }
445   }
446
447   // Traverse the embedded items and update the blending mode vector.
448   for( const auto& item : textModel->mLogicalModel->mEmbeddedItems )
449   {
450     const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
451     blendingMode[glyphIndex] = item.colorBlendingMode;
452   }
453
454   ////////////////////////////////////////////////////////////////////////////////
455   // Set the isEmoji Vector
456   ////////////////////////////////////////////////////////////////////////////////
457
458   isEmoji.Resize( numberOfGlyphs, false );
459
460   for( const auto& run : scripts )
461   {
462     if( run.script == TextAbstraction::Script::EMOJI )
463     {
464       const GlyphIndex firstGlyph = textModel->mVisualModel->mCharactersToGlyph[run.characterRun.characterIndex];
465       const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
466       const GlyphIndex lastGlyphPlusOne = textModel->mVisualModel->mCharactersToGlyph[lastCharacter] + textModel->mVisualModel->mGlyphsPerCharacter[lastCharacter];
467
468       for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index )
469       {
470         isEmoji[index] = true;
471       }
472     }
473   }
474
475   ////////////////////////////////////////////////////////////////////////////////
476   // Layout the text.
477   ////////////////////////////////////////////////////////////////////////////////
478
479   // Sets the alignment
480   HorizontalAlignment::Type horizontalAlignment = Toolkit::HorizontalAlignment::CENTER;
481   HorizontalAlignment::Type horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER;
482   VerticalAlignment::Type verticalAlignment = VerticalAlignment::CENTER;
483   Layout::Type layout = Layout::SINGLELINE;
484   CircularAlignment::Type circularAlignment = CircularAlignment::BEGIN;
485
486   Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment );
487   GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment );
488   horizontalCircularAlignment = horizontalAlignment;
489
490   Property::Value verticalAlignmentStr( textParameters.verticalAlignment );
491   GetVerticalAlignmentEnumeration( verticalAlignmentStr, verticalAlignment );
492
493   Property::Value layoutStr( textParameters.layout );
494   GetLayoutEnumeration( layoutStr, layout );
495
496   Property::Value circularAlignmentStr( textParameters.circularAlignment );
497   GetCircularAlignmentEnumeration( circularAlignmentStr, circularAlignment );
498
499   // Whether the layout is multi-line.
500   const Text::Layout::Engine::Type horizontalLayout = ( Layout::MULTILINE == layout ) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX;
501   layoutEngine.SetLayout( horizontalLayout ); // TODO: multi-line.
502
503
504   // Whether the layout is circular.
505   const bool isCircularTextLayout = (Layout::CIRCULAR == layout);
506   const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle );
507
508   // Calculates the max ascender or the max descender.
509   // Is used to calculate the radius of the base line of the text.
510   float maxAscenderDescender = 0.f;
511   if( isCircularTextLayout )
512   {
513     FontId currentFontId = 0u;
514     for( const auto& glyph : rendererParameters.glyphs )
515     {
516       if( currentFontId != glyph.fontId )
517       {
518         currentFontId = glyph.fontId;
519         FontMetrics metrics;
520         fontClient.GetFontMetrics(currentFontId, metrics);
521         maxAscenderDescender = std::max( maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender );
522       }
523     }
524   }
525   const unsigned int radius = textParameters.radius - static_cast<unsigned int>( maxAscenderDescender );
526
527   // Convert CircularAlignment to HorizontalAlignment.
528   if( isCircularTextLayout )
529   {
530     switch( circularAlignment )
531     {
532       case CircularAlignment::BEGIN:
533       {
534         horizontalCircularAlignment = Toolkit::HorizontalAlignment::BEGIN;
535         break;
536       }
537       case CircularAlignment::CENTER:
538       {
539         horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER;
540         break;
541       }
542       case CircularAlignment::END:
543       {
544         horizontalCircularAlignment = Toolkit::HorizontalAlignment::END;
545         break;
546       }
547     }
548   }
549
550   // Set the layout parameters.
551   Size textLayoutArea( static_cast<float>( textParameters.textWidth ),
552                      static_cast<float>( textParameters.textHeight ) );
553
554   if( isCircularTextLayout )
555   {
556     // In a circular layout, the length of the text area depends on the radius.
557     rendererParameters.radius = radius;
558     textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast<float>( rendererParameters.radius ) );
559   }
560
561   textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment;
562   textModel->mLineWrapMode = LineWrap::WORD;
563   textModel->mIgnoreSpacesAfterText = false;
564   textModel->mMatchSystemLanguageDirection = false;
565   Text::Layout::Parameters layoutParameters( textLayoutArea,
566                                              textModel );
567
568   // Resize the vector of positions to have the same size than the vector of glyphs.
569   rendererParameters.positions.Resize( numberOfGlyphs );
570
571   // Whether the last character is a new paragraph character.
572   layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( textToShape[numberOfCharacters - 1u] );
573
574   // The initial glyph and the number of glyphs to layout.
575   layoutParameters.startGlyphIndex = 0u;
576   layoutParameters.numberOfGlyphs = numberOfGlyphs;
577   layoutParameters.startLineIndex = 0u;
578   layoutParameters.estimatedNumberOfLines = 1u;
579   layoutParameters.interGlyphExtraAdvance = 0.f;
580
581   // Update the visual model.
582   Size newLayoutSize;
583   bool isAutoScrollEnabled = false;
584   layoutEngine.LayoutText( layoutParameters,
585                            rendererParameters.positions,
586                            lines,
587                            newLayoutSize,
588                            textParameters.ellipsisEnabled,
589                            isAutoScrollEnabled );
590
591   ////////////////////////////////////////////////////////////////////////////////
592   // Reorder BiDirectional lines.
593   ////////////////////////////////////////////////////////////////////////////////
594
595   if( hasBidirectionalText )
596   {
597     Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = textModel->mLogicalModel->mBidirectionalLineInfo;
598     // Reorder the line.
599     bidirectionalLineInfo.Reserve( 1u );
600
601     ReorderLines( bidirectionalInfo,
602                   0u,
603                   numberOfCharacters,
604                   lines,
605                   bidirectionalLineInfo );
606
607     // Set the bidirectional info per line into the layout parameters.
608     layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
609     layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
610
611     // Re-layout the text. Reorder those lines with right to left characters.
612     layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
613                                            0u,
614                                            numberOfCharacters,
615                                            rendererParameters.positions );
616   }
617
618   ////////////////////////////////////////////////////////////////////////////////
619   // Align the text.
620   ////////////////////////////////////////////////////////////////////////////////
621
622   // Retrieve the line of text to know the direction and the width. @todo multi-line
623   const LineRun& line = lines[0u];
624
625   if( isCircularTextLayout )
626   {
627     // Set the circular alignment.
628     rendererParameters.circularLayout = isClockwise ? TextRenderer::Parameters::CLOCKWISE : TextRenderer::Parameters::COUNTER_CLOCKWISE;
629
630     // Update the text's height to be used by the ellipsis code.
631     textLayoutArea.height = newLayoutSize.height;
632
633     // Set the size of the text laid out on a straight horizontal line.
634     rendererParameters.circularWidth = static_cast<unsigned int>( newLayoutSize.width );
635     rendererParameters.circularHeight = static_cast<unsigned int>( newLayoutSize.height );
636
637     // Calculate the center of the circular text according the horizontal and vertical alingments and the radius.
638     switch( horizontalAlignment )
639     {
640       case HorizontalAlignment::BEGIN:
641       {
642         rendererParameters.centerX = static_cast<int>(textParameters.radius);
643         break;
644       }
645       case HorizontalAlignment::CENTER:
646       {
647         rendererParameters.centerX = static_cast<int>( textParameters.textWidth / 2u );
648         break;
649       }
650       case HorizontalAlignment::END:
651       {
652         rendererParameters.centerX = static_cast<int>( textParameters.textWidth ) - static_cast<int>(textParameters.radius);
653         break;
654       }
655     }
656
657     switch( verticalAlignment )
658     {
659       case VerticalAlignment::TOP:
660       {
661         rendererParameters.centerY = static_cast<int>(textParameters.radius);
662         break;
663       }
664       case VerticalAlignment::CENTER:
665       {
666         rendererParameters.centerY = static_cast<int>( textParameters.textHeight / 2u );
667         break;
668       }
669       case VerticalAlignment::BOTTOM:
670       {
671         rendererParameters.centerY = static_cast<int>( textParameters.textHeight ) - static_cast<int>(textParameters.radius);
672         break;
673       }
674     }
675
676     // Calculate the beginning angle according with the given horizontal alignment.
677     const bool isRTL = RTL == line.direction;
678
679     CircularAlignment::Type alignment = circularAlignment;
680     if( isRTL )
681     {
682       // Swap the alignment type if the line is right to left.
683       switch( alignment )
684       {
685         case CircularAlignment::BEGIN:
686         {
687           alignment = CircularAlignment::END;
688           break;
689         }
690         case CircularAlignment::CENTER:
691         {
692           // Nothing to do.
693           break;
694         }
695         case CircularAlignment::END:
696         {
697           alignment = CircularAlignment::BEGIN;
698           break;
699         }
700       }
701     }
702
703     float angleOffset = 0.f;
704
705     switch( alignment )
706     {
707       case CircularAlignment::BEGIN:
708       {
709         angleOffset = 0.f;
710         break;
711       }
712       case CircularAlignment::CENTER:
713       {
714         const bool isNeg = textParameters.incrementAngle < 0.f;
715         const float textWidth = static_cast<float>( rendererParameters.circularWidth );
716         angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
717         break;
718       }
719       case CircularAlignment::END:
720       {
721         const bool isNeg = textParameters.incrementAngle < 0.f;
722         const float textWidth = static_cast<float>( rendererParameters.circularWidth );
723         angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
724         break;
725       }
726     }
727
728     // Update the beginning angle with the calculated offset.
729     rendererParameters.beginAngle = Radian( Degree( textParameters.beginAngle ) ) + angleOffset;
730
731     // Set the vertical position of the glyphs.
732     for( auto& position : rendererParameters.positions )
733     {
734       position.y = 0.f;
735     }
736   }
737   else
738   {
739     // Calculate the vertical offset according with the given alignment.
740     float penY = 0.f;
741
742     switch( verticalAlignment )
743     {
744       case VerticalAlignment::TOP:
745       {
746         penY = line.ascender;
747         break;
748       }
749       case VerticalAlignment::CENTER:
750       {
751         penY = line.ascender + 0.5f * ( textLayoutArea.height - ( line.ascender - line.descender ) );
752         break;
753       }
754       case VerticalAlignment::BOTTOM:
755       {
756         penY = textLayoutArea.height;
757         break;
758       }
759     }
760
761     // Calculate the horizontal offset according with the given alignment.
762   float alignmentOffset = 0.f;
763     layoutEngine.Align( textLayoutArea,
764                       0u,
765                       numberOfCharacters,
766                       horizontalAlignment,
767                       lines,
768                       alignmentOffset,
769                       Dali::LayoutDirection::LEFT_TO_RIGHT,
770                       false );
771
772     // Update the position of the glyphs with the calculated offsets.
773     for( auto& position : rendererParameters.positions )
774   {
775     position.x += line.alignmentOffset;
776     position.y = penY;
777   }
778   }
779
780   // Cairo adds the bearing to the position of the glyph
781   // that has already been added by the DALi's layout engine,
782   // so it's needed to be removed here.
783   for( unsigned int index = 0u; index < rendererParameters.glyphs.Count(); ++index )
784   {
785     const GlyphInfo& glyph = rendererParameters.glyphs[index];
786     Vector2& position = rendererParameters.positions[index];
787
788     position.x -= glyph.xBearing;
789   }
790
791   // Set the position of the embedded items (if there is any).
792   EmbeddedItemInfo* embeddedItemLayoutBuffer = embeddedItemLayout.Begin();
793
794   for( Length index = 0u, endIndex = embeddedItemLayout.Count(); index < endIndex; ++index )
795   {
796     EmbeddedItemInfo& embeddedItem = *( embeddedItemLayoutBuffer + index );
797
798     embeddedItem.position = rendererParameters.positions[embeddedItem.glyphIndex];
799
800     if( isCircularTextLayout )
801     {
802       // Calculate the new position of the embedded item in the circular path.
803
804       // Center of the bitmap.
805       const float halfWidth = 0.5f * embeddedItem.size.width;
806       const float halfHeight = 0.5f * embeddedItem.size.height;
807       double centerX = static_cast<double>( embeddedItem.position.x + halfWidth );
808       double centerY = static_cast<double>(embeddedItem.position.y - halfHeight);
809
810       Dali::TextAbstraction::CircularTextParameters circularTextParameters;
811
812       circularTextParameters.radius = static_cast<double>( radius );
813       circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
814       circularTextParameters.beginAngle = static_cast<double>( -rendererParameters.beginAngle + Dali::Math::PI_2 );
815       circularTextParameters.centerX = 0.5f * static_cast<double>( textParameters.textWidth );
816       circularTextParameters.centerY = 0.5f * static_cast<double>( textParameters.textHeight );
817
818       // Calculate the rotation angle.
819       float radians = rendererParameters.beginAngle;
820       if( isClockwise )
821       {
822         radians += static_cast<float>( circularTextParameters.invRadius * centerX );
823         radians = -radians;
824       }
825       else
826       {
827         radians -= static_cast<float>( circularTextParameters.invRadius * centerX );
828         radians = -radians + Dali::Math::PI;
829       }
830       embeddedItem.angle = Degree( Radian( radians ) );
831
832       Dali::TextAbstraction::TransformToArc( circularTextParameters, centerX, centerY );
833
834       // Recalculate the size of the embedded item after the rotation to position it correctly.
835       float width = embeddedItem.size.width;
836       float height = embeddedItem.size.height;
837
838       // Transform the input angle into the range [0..2PI]
839       radians = fmod( radians, TWO_PI );
840       radians += ( radians < 0.f ) ? TWO_PI : 0.f;
841
842       // Does the same operations than rotate by shear.
843       if( ( radians > Math::PI_4 ) && ( radians <= RAD_135 ) )
844       {
845         std::swap( width, height );
846         radians -= Math::PI_2;
847       }
848       else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) )
849       {
850         radians -= Math::PI;
851       }
852       else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) )
853       {
854         std::swap( width, height );
855         radians -= RAD_270;
856       }
857
858       if( fabs( radians ) > Dali::Math::MACHINE_EPSILON_10 )
859       {
860         const float angleSinus = fabs( sin( radians ) );
861         const float angleCosinus = cos( radians );
862
863         // Calculate the rotated image dimensions.
864         embeddedItem.rotatedSize.height = width * angleSinus + height * angleCosinus;
865         embeddedItem.rotatedSize.width = height * angleSinus + width * angleCosinus + 1.f;
866       }
867
868       embeddedItem.position.x = floor( static_cast<float>( centerX ) - 0.5f * embeddedItem.rotatedSize.width );
869       embeddedItem.position.y = floor( static_cast<float>( centerY ) - 0.5f * embeddedItem.rotatedSize.height );
870     }
871     else
872     {
873       embeddedItem.position.y -= embeddedItem.size.height;
874     }
875   }
876
877   ////////////////////////////////////////////////////////////////////////////////
878   // Ellipsis the text.
879   ////////////////////////////////////////////////////////////////////////////////
880
881   if( textParameters.ellipsisEnabled )
882   {
883     const LineRun& line = lines[0u]; // TODO: multi-line
884
885     if( line.ellipsis )
886     {
887       Length finalNumberOfGlyphs = 0u;
888
889       if( ( line.ascender - line.descender ) > textLayoutArea.height )
890       {
891         // The height of the line is bigger than the height of the text area.
892         // Show the ellipsis glyph even if it doesn't fit in the text area.
893         // If no text is rendered then issues are rised and it may be a while
894         // until is find out that the text area is too small.
895
896         // Get the first glyph which is going to be replaced and the ellipsis glyph.
897         GlyphInfo& glyphInfo = rendererParameters.glyphs[0u];
898         const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphInfo.fontId ) );
899
900         // Change the 'x' and 'y' position of the ellipsis glyph.
901         Vector2& position = rendererParameters.positions[0u];
902         position.x = ellipsisGlyph.xBearing;
903         position.y = textLayoutArea.height - ellipsisGlyph.yBearing;
904
905         // Replace the glyph by the ellipsis glyph.
906         glyphInfo = ellipsisGlyph;
907
908         // Set the final number of glyphs
909         finalNumberOfGlyphs = 1u;
910       }
911       else
912       {
913
914         // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
915         float firstPenX = 0.f; // Used if rtl text is elided.
916         bool firstPenSet = false;
917
918         // Add the ellipsis glyph.
919         bool inserted = false;
920         float removedGlypsWidth = 0.f;
921         Length numberOfRemovedGlyphs = 0u;
922         if (line.glyphRun.numberOfGlyphs > 0u)
923         {
924           GlyphIndex index = line.glyphRun.numberOfGlyphs - 1u;
925
926           GlyphInfo* glyphs = rendererParameters.glyphs.Begin();
927           Vector2* glyphPositions = rendererParameters.positions.Begin();
928
929           float penY = 0.f;
930
931           // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
932           while( !inserted )
933           {
934             const GlyphInfo& glyphToRemove = *( glyphs + index );
935
936             if( 0u != glyphToRemove.fontId )
937             {
938               // i.e. The font id of the glyph shaped from the '\n' character is zero.
939
940               // Need to reshape the glyph as the font may be different in size.
941               const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphToRemove.fontId ) );
942
943               if( !firstPenSet )
944               {
945                 const Vector2& position = *( glyphPositions + index );
946
947                 // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
948                 penY = position.y;
949
950                 // Calculates the first penX which will be used if rtl text is elided.
951                 firstPenX = position.x - glyphToRemove.xBearing;
952                 if( firstPenX < -ellipsisGlyph.xBearing )
953                 {
954                   // Avoids to exceed the bounding box when rtl text is elided.
955                   firstPenX = -ellipsisGlyph.xBearing;
956                 }
957
958                 removedGlypsWidth = -ellipsisGlyph.xBearing;
959
960                 firstPenSet = true;
961               }
962
963               removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
964
965               // Calculate the width of the ellipsis glyph and check if it fits.
966               const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
967               if( ellipsisGlyphWidth < removedGlypsWidth )
968               {
969                 GlyphInfo& glyphInfo = *( glyphs + index );
970                 Vector2& position = *( glyphPositions + index );
971                 position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f;
972
973                 // Replace the glyph by the ellipsis glyph.
974                 glyphInfo = ellipsisGlyph;
975
976                 // Update the isEmoji vector
977                 isEmoji[index] = false;
978
979                 // Change the 'x' and 'y' position of the ellipsis glyph.
980
981                 if( position.x > firstPenX )
982                 {
983                   position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
984                 }
985
986                 position.x += ellipsisGlyph.xBearing;
987                 position.y = penY;
988
989                 inserted = true;
990               }
991             }
992
993             if( !inserted )
994             {
995               if( index > 0u )
996               {
997                 --index;
998               }
999               else
1000               {
1001                 // No space for the ellipsis.
1002                 inserted = true;
1003               }
1004               ++numberOfRemovedGlyphs;
1005             }
1006
1007             // Set the final number of glyphs
1008             finalNumberOfGlyphs = line.glyphRun.numberOfGlyphs - numberOfRemovedGlyphs;
1009           }
1010         }
1011
1012         // Resize the number of glyphs/positions
1013         rendererParameters.glyphs.Resize( finalNumberOfGlyphs );
1014         rendererParameters.positions.Resize( finalNumberOfGlyphs );
1015
1016         // Remove from the embedded items those exceding the last laid out glyph.
1017         embeddedItemLayout.Erase( std::remove_if( embeddedItemLayout.Begin(),
1018                                                   embeddedItemLayout.End(),
1019                                                   [finalNumberOfGlyphs]( const EmbeddedItemInfo& item )
1020                                                   {
1021                                                      return item.glyphIndex >= finalNumberOfGlyphs;
1022                                                   } ),
1023                                  embeddedItemLayout.End() );
1024       }
1025     }
1026   }
1027
1028   ////////////////////////////////////////////////////////////////////////////////
1029   // Render the text.
1030   ////////////////////////////////////////////////////////////////////////////////
1031
1032   rendererParameters.width = textParameters.textWidth;
1033   rendererParameters.height = textParameters.textHeight;
1034
1035   TextAbstraction::TextRenderer renderer = TextAbstraction::TextRenderer::Get();
1036   return renderer.Render( rendererParameters );
1037 }
1038
1039 Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
1040 {
1041   // The size of the pixel data.
1042   const int width = static_cast<int>(shadowParameters.input.GetWidth());
1043   const int height = static_cast<int>(shadowParameters.input.GetHeight());
1044
1045   // The shadow's offset.
1046   const int xOffset = static_cast<int>( shadowParameters.offset.x );
1047   const int yOffset = static_cast<int>( shadowParameters.offset.y );
1048
1049   // The size in bytes of the pixel of the input's buffer.
1050   const Pixel::Format inputFormat = shadowParameters.input.GetPixelFormat();
1051   const unsigned int inputPixelSize = Pixel::GetBytesPerPixel( inputFormat );
1052   const bool isA8 = Pixel::A8 == inputFormat;
1053
1054   // Creates the output pixel buffer.
1055   Devel::PixelBuffer outputPixelBuffer = Devel::PixelBuffer::New(width, height, Pixel::RGBA8888);
1056
1057   // Clear the output buffer
1058   unsigned char* outputPixelBufferPtr = outputPixelBuffer.GetBuffer();
1059   memset(outputPixelBufferPtr, 0, width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888));
1060
1061   // Gets the buffer of the input pixel buffer.
1062   const unsigned char* const inputPixelBuffer = shadowParameters.input.GetBuffer();
1063
1064   float textColor[4u];
1065   if (isA8)
1066   {
1067     memcpy(textColor, shadowParameters.textColor.AsFloat(), 4u * sizeof(float));
1068   }
1069   const float* const shadowColor = shadowParameters.color.AsFloat();
1070
1071   // Traverse the input pixel buffer and write the text on the foreground and the shadow on the background.
1072   for (int rowIndex = 0; rowIndex < height; ++rowIndex)
1073   {
1074     // Calculates the rowIndex to the input pixel buffer for the shadow and whether it's within the boundaries.
1075     const int yOffsetIndex = rowIndex - yOffset;
1076     const bool isValidRowIndex = ((yOffsetIndex >= 0) && (yOffsetIndex < height));
1077
1078     const int rows = rowIndex * width;
1079     const int offsetRows = yOffsetIndex * width;
1080     for (int columnIndex = 0; columnIndex < width; ++columnIndex)
1081     {
1082       // Index to the input buffer to retrieve the alpha value of the foreground text.
1083       const unsigned int index = inputPixelSize * static_cast<unsigned int>(rows + columnIndex);
1084
1085       // Build the index to the input buffer to retrieve the alpha value of the background shadow.
1086       unsigned int shadowIndex = 0u;
1087       bool isValidShadowIndex = false;
1088       if (isValidRowIndex)
1089       {
1090         const int xOffsetIndex = columnIndex - xOffset;
1091         isValidShadowIndex = ((xOffsetIndex >= 0) && (xOffsetIndex < width));
1092
1093         if (isValidShadowIndex)
1094         {
1095           shadowIndex = inputPixelSize * static_cast<unsigned int>(offsetRows + xOffsetIndex);
1096         }
1097       }
1098
1099       // If the input buffer is an alpha mask, retrieve the values for the foreground text and the background shadow.
1100       // If not retrieve the color.
1101       float inputShadowOffsetAlphaValue = 1.f;
1102       float inputAlphaValue = 1.f;
1103       if (isA8)
1104       {
1105         // Retrieve the alpha value for the shadow.
1106         inputShadowOffsetAlphaValue = isValidShadowIndex ? (static_cast<float>(*(inputPixelBuffer + shadowIndex)) / 255.f) : 0.f;
1107
1108         // Retrieve the alpha value for the text.
1109         inputAlphaValue = static_cast<float>(*(inputPixelBuffer + index)) / 255.f;
1110       }
1111       else
1112       {
1113         // The input buffer is not an alpha mask. Retrieve the color.
1114         textColor[0u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 0u) );
1115         textColor[1u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 1u) );
1116         textColor[2u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 2u) );
1117         textColor[3u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 3u) );
1118         inputAlphaValue = textColor[3u];
1119         inputShadowOffsetAlphaValue = isValidShadowIndex ? TO_FLOAT * static_cast<float>( *(inputPixelBuffer + shadowIndex + 3u) ) : 0.f;
1120       }
1121
1122       // Build the output color.
1123       float outputColor[4u];
1124
1125       if( shadowParameters.blendShadow )
1126       {
1127         // Blend the shadow's color with the text's color on top
1128         const float textAlpha = textColor[3u] * inputAlphaValue;
1129         const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue;
1130
1131         // Blends the alpha.
1132         outputColor[3u] = 1.f - ((1.f - textAlpha) * (1.f - shadowAlpha));
1133         const bool isOutputAlphaZero = outputColor[3u] < Dali::Math::MACHINE_EPSILON_1000;
1134         if( isOutputAlphaZero )
1135         {
1136           std::fill( outputColor, outputColor + 4u, 0.f );
1137         }
1138         else
1139         {
1140           // Blends the RGB components.
1141           float shadowComponent = 0.f;
1142           float textComponent = 0.f;
1143
1144           shadowComponent = shadowColor[0u] * inputShadowOffsetAlphaValue;
1145           textComponent = textColor[0u] * inputAlphaValue;
1146           outputColor[0u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
1147
1148           shadowComponent = shadowColor[1u] * inputShadowOffsetAlphaValue;
1149           textComponent = textColor[1u] * inputAlphaValue;
1150           outputColor[1u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
1151
1152           shadowComponent = shadowColor[2u] * inputShadowOffsetAlphaValue;
1153           textComponent = textColor[2u] * inputAlphaValue;
1154           outputColor[2u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
1155         }
1156       }
1157       else
1158       {
1159         // No blending!!!
1160         std::fill( outputColor, outputColor + 4u, 0.f );
1161
1162         const float textAlpha = textColor[3u];
1163         const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue;
1164
1165         // Write shadow first.
1166         if( shadowAlpha > Dali::Math::MACHINE_EPSILON_1000 )
1167         {
1168           outputColor[0u] = shadowColor[0u] * inputShadowOffsetAlphaValue;
1169           outputColor[1u] = shadowColor[1u] * inputShadowOffsetAlphaValue;
1170           outputColor[2u] = shadowColor[2u] * inputShadowOffsetAlphaValue;
1171           outputColor[3u] = shadowAlpha;
1172         }
1173
1174         // Write character on top.
1175         if( textAlpha > Dali::Math::MACHINE_EPSILON_1000 )
1176         {
1177           outputColor[0u] = textColor[0u];
1178           outputColor[1u] = textColor[1u];
1179           outputColor[2u] = textColor[2u];
1180           outputColor[3u] = textAlpha;
1181         }
1182       }
1183
1184       // Write the color into the output pixel buffer.
1185       const unsigned int outputIndex = 4u * (rows + columnIndex);
1186       *(outputPixelBufferPtr + outputIndex + 0u) = static_cast<unsigned char>( TO_UCHAR * outputColor[0u] );
1187       *(outputPixelBufferPtr + outputIndex + 1u) = static_cast<unsigned char>( TO_UCHAR * outputColor[1u] );
1188       *(outputPixelBufferPtr + outputIndex + 2u) = static_cast<unsigned char>( TO_UCHAR * outputColor[2u] );
1189       *(outputPixelBufferPtr + outputIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * outputColor[3u] );
1190     }
1191   }
1192
1193   // Returns the pixel buffer.
1194   return outputPixelBuffer;
1195 }
1196
1197 Devel::PixelBuffer ConvertToRgba8888(Devel::PixelBuffer pixelBuffer, const Vector4& color, bool multiplyByAlpha)
1198 {
1199   if (Dali::Pixel::A8 != pixelBuffer.GetPixelFormat())
1200   {
1201     // Does nothing.
1202     return pixelBuffer;
1203   }
1204
1205   const unsigned int width = pixelBuffer.GetWidth();
1206   const unsigned int height = pixelBuffer.GetHeight();
1207   Devel::PixelBuffer newPixelBuffer = Devel::PixelBuffer::New( width, height, Dali::Pixel::RGBA8888 );
1208
1209   unsigned char* dstBuffer = newPixelBuffer.GetBuffer();
1210   const unsigned char* const srcBuffer = pixelBuffer.GetBuffer();
1211
1212   const unsigned char r = static_cast<unsigned char>( TO_UCHAR * color.r );
1213   const unsigned char g = static_cast<unsigned char>( TO_UCHAR * color.g );
1214   const unsigned char b = static_cast<unsigned char>( TO_UCHAR * color.b );
1215
1216   unsigned char dstColor[4];
1217   for( unsigned int j = 0u; j < height; ++j )
1218   {
1219     const unsigned int lineIndex = j * width;
1220     for( unsigned int i=0u; i < width; ++i )
1221     {
1222       const unsigned int srcIndex = lineIndex + i;
1223
1224       const float srcAlpha = static_cast<float>( *( srcBuffer + srcIndex ) );
1225
1226       if( multiplyByAlpha )
1227       {
1228         dstColor[0u] = static_cast<unsigned char>( srcAlpha * color.r );
1229         dstColor[1u] = static_cast<unsigned char>( srcAlpha * color.g );
1230         dstColor[2u] = static_cast<unsigned char>( srcAlpha * color.b );
1231         dstColor[3u] = static_cast<unsigned char>( srcAlpha * color.a );
1232       }
1233       else
1234       {
1235         dstColor[0u] = r;
1236         dstColor[1u] = g;
1237         dstColor[2u] = b;
1238         dstColor[3u] = static_cast<unsigned char>( srcAlpha );
1239       }
1240
1241       const unsigned int dstIndex = srcIndex * 4u;
1242       memcpy( dstBuffer + dstIndex, dstColor, 4u );
1243     }
1244   }
1245
1246   return newPixelBuffer;
1247 }
1248
1249 void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend)
1250 {
1251   const Dali::Pixel::Format pixelFormat = dst.GetPixelFormat();
1252   if( src.GetPixelFormat() != pixelFormat )
1253   {
1254     DALI_LOG_ERROR("PixelBuffer::SetBuffer. The pixel format of the new data must be the same of the current pixel buffer.");
1255     return;
1256   }
1257
1258   const unsigned int srcWidth = src.GetWidth();
1259   const unsigned int srcHeight = src.GetHeight();
1260   const unsigned int dstWidth = dst.GetWidth();
1261   const unsigned int dstHeight = dst.GetHeight();
1262
1263   if( ( x > dstWidth ) ||
1264       ( y > dstHeight ) ||
1265       ( x + srcWidth > dstWidth ) ||
1266       ( y + srcHeight > dstHeight ) )
1267   {
1268     DALI_LOG_ERROR("PixelBuffer::SetBuffer. The source pixel buffer is out of the boundaries of the destination pixel buffer.");
1269     return;
1270   }
1271
1272   const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(pixelFormat);
1273   if( bytesPerPixel == 0u )
1274   {
1275     return;
1276   }
1277   const unsigned int alphaIndex = bytesPerPixel - 1u;
1278
1279   const unsigned char* const srcBuffer = src.GetBuffer();
1280   unsigned char* dstBuffer = dst.GetBuffer();
1281
1282   if( !blend )
1283   {
1284     const unsigned int currentLineSize = dstWidth * bytesPerPixel;
1285     const unsigned int newLineSize = srcWidth * bytesPerPixel;
1286     unsigned char* currentBuffer = dstBuffer + (y * dstWidth + x) * bytesPerPixel;
1287     for (unsigned int j = 0u; j < srcHeight; ++j)
1288     {
1289       memcpy(currentBuffer + j * currentLineSize, srcBuffer + j * newLineSize, newLineSize);
1290     }
1291   }
1292   else
1293   {
1294     float outputColor[4u];
1295
1296     // Blend the src pixel buffer with the dst pixel buffer as background.
1297     //
1298     //  fgColor, fgAlpha, bgColor, bgAlpha
1299     //
1300     //  alpha = 1 - ( 1 - fgAlpha ) * ( 1 - bgAlpha )
1301     //  color = ( fgColor * fgAlpha / alpha ) + ( bgColor * bgAlpha * ( 1 - fgAlpha ) / alpha )
1302
1303     // Jump till the 'x,y' position
1304     const unsigned int dstWidthBytes = dstWidth * bytesPerPixel;
1305     dstBuffer += ( y * dstWidthBytes + x * bytesPerPixel );
1306
1307     for (unsigned int j = 0u; j < srcHeight; ++j)
1308     {
1309       const unsigned int srcLineIndex = j * srcWidth;
1310       for (unsigned int i = 0u; i < srcWidth; ++i)
1311       {
1312         const float srcAlpha = TO_FLOAT * static_cast<float>( *( srcBuffer + bytesPerPixel * ( srcLineIndex + i ) + alphaIndex ) );
1313         const float dstAlpha = TO_FLOAT * static_cast<float>( *(dstBuffer + i*bytesPerPixel + alphaIndex) );
1314
1315         // Blends the alpha channel.
1316         const float oneMinusSrcAlpha = 1.f - srcAlpha;
1317         outputColor[alphaIndex] = 1.f - (oneMinusSrcAlpha * (1.f - dstAlpha));
1318
1319         // Blends the RGB channels.
1320         const bool isOutputAlphaZero = outputColor[alphaIndex] < Dali::Math::MACHINE_EPSILON_1000;
1321         if( isOutputAlphaZero )
1322         {
1323           std::fill( outputColor, outputColor + bytesPerPixel, 0.f );
1324         }
1325         else
1326         {
1327           const float srcAlphaOverOutputAlpha = srcAlpha / outputColor[alphaIndex];                                    // fgAlpha / alpha
1328           const float dstAlphaOneMinusSrcAlphaOverOutputAlpha = dstAlpha * oneMinusSrcAlpha / outputColor[alphaIndex]; // bgAlpha * ( 1 - fgAlpha ) / alpha
1329           for (unsigned int index = 0u; index < alphaIndex; ++index)
1330           {
1331             const float dstComponent = TO_FLOAT * static_cast<float>( *( dstBuffer + i * bytesPerPixel + index ) ) * dstAlpha;
1332             const float srcComponent = TO_FLOAT * static_cast<float>(*(srcBuffer + bytesPerPixel * (srcLineIndex + i) + index) ) * srcAlpha;
1333             outputColor[index] = ( srcComponent * srcAlphaOverOutputAlpha ) + ( dstComponent * dstAlphaOneMinusSrcAlphaOverOutputAlpha );
1334           }
1335         }
1336
1337         for (unsigned int index = 0u; index < bytesPerPixel; ++index)
1338         {
1339           *(dstBuffer + i * bytesPerPixel + index) = static_cast<unsigned char>( TO_UCHAR * outputColor[index] );
1340         }
1341       }
1342
1343       dstBuffer += dstWidthBytes;
1344     }
1345   }
1346 }
1347
1348 } // namespace DevelText
1349
1350 } // namespace Toolkit
1351
1352 } // namespace Dali