Blending algorithm optimized when cutout
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / text-typesetter.cpp
1 /*
2  * Copyright (c) 2024 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/text/rendering/text-typesetter.h>
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23 #include <dali/devel-api/text-abstraction/font-client.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/integration-api/trace.h>
26 #include <dali/public-api/common/constants.h>
27 #include <dali/public-api/math/math-utils.h>
28 #include <memory.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
32 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
33 #include <dali-toolkit/internal/text/line-helper-functions.h>
34 #include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
35 #include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
36 #include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
37 #include <dali-toolkit/internal/text/rendering/view-model.h>
38
39 namespace Dali
40 {
41 namespace Toolkit
42 {
43 namespace Text
44 {
45 namespace
46 {
47 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
48
49 const float HALF(0.5f);
50 const float ONE_AND_A_HALF(1.5f);
51
52 /**
53  * @brief Fast multiply & divide by 255. It wiil be useful when we applying alpha value in color
54  *
55  * @param x The value between [0..255]
56  * @param y The value between [0..255]
57  * @return (x*y)/255
58  */
59 inline uint8_t MultiplyAndNormalizeColor(const uint8_t x, const uint8_t y) noexcept
60 {
61   const uint32_t xy = static_cast<const uint32_t>(x) * y;
62   return ((xy << 15) + (xy << 7) + xy) >> 23;
63 }
64
65 /**
66  * @brief Fast multiply & Summation & divide by 255.
67  *
68  * @param x1 The value between [0..255]
69  * @param y1 The value between [0..255]
70  * @param x2 The value between [0..255]
71  * @param y2 The value between [0..255]
72  * @return min(255, (x1*y1)/255 + (x2*y2)/255)
73  */
74 inline uint8_t MultiplyAndSummationAndNormalizeColor(const uint8_t x1, const uint8_t y1, const uint8_t x2, const uint8_t y2) noexcept
75 {
76   const uint32_t xy1 = static_cast<const uint32_t>(x1) * y1;
77   const uint32_t xy2 = static_cast<const uint32_t>(x2) * y2;
78   const uint32_t res = std::min(65025u, xy1 + xy2); // 65025 is 255 * 255.
79   return ((res + ((res + 257) >> 8)) >> 8); // fast divide by 255.
80 }
81
82 /// Helper macro define for glyph typesetter. It will reduce some duplicated code line.
83 // clang-format off
84 /**
85  * @brief Prepare decode glyph bitmap data. It must be call END_GLYPH_BITMAP end of same scope.
86  */
87 #define BEGIN_GLYPH_BITMAP(data)                                                                                                                \
88 {                                                                                                                                               \
89   uint32_t   glyphOffet               = 0u;                                                                                                     \
90   const bool useLocalScanline         = data.glyphBitmap.compressionType != TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;  \
91   uint8_t* __restrict__ glyphScanline = useLocalScanline ? (uint8_t*)malloc(data.glyphBitmap.width * glyphPixelSize) : data.glyphBitmap.buffer; \
92   DALI_ASSERT_ALWAYS(glyphScanline && "Glyph scanline for buffer is null!");
93
94 /**
95  * @brief Macro to skip useless line fast.
96  */
97 #define SKIP_GLYPH_SCANLINE(skipLine)                                                                  \
98 if(useLocalScanline)                                                                                   \
99 {                                                                                                      \
100   for(int32_t lineIndex = 0; lineIndex < skipLine; ++lineIndex)                                        \
101   {                                                                                                    \
102     TextAbstraction::GlyphBufferData::DecompressScanline(data.glyphBitmap, glyphScanline, glyphOffet); \
103   }                                                                                                    \
104 }                                                                                                      \
105 else                                                                                                   \
106 {                                                                                                      \
107   glyphScanline += skipLine * static_cast<int32_t>(data.glyphBitmap.width * glyphPixelSize);           \
108 }
109
110 /**
111  * @brief Prepare scanline of glyph bitmap data per each lines. It must be call END_GLYPH_SCANLINE_DECODE end of same scope.
112  */
113 #define BEGIN_GLYPH_SCANLINE_DECODE(data)                                                              \
114 {                                                                                                      \
115   if(useLocalScanline)                                                                                 \
116   {                                                                                                    \
117     TextAbstraction::GlyphBufferData::DecompressScanline(data.glyphBitmap, glyphScanline, glyphOffet); \
118   }
119
120 /**
121  * @brief Finalize scanline of glyph bitmap data per each lines.
122  */
123 #define END_GLYPH_SCANLINE_DECODE(data)                       \
124   if(!useLocalScanline)                                       \
125   {                                                           \
126     glyphScanline += data.glyphBitmap.width * glyphPixelSize; \
127   }                                                           \
128 } // For ensure that we call BEGIN_GLYPH_SCANLINE_DECODE before
129
130 /**
131  * @brief Finalize decode glyph bitmap data.
132  */
133 #define END_GLYPH_BITMAP() \
134   if(useLocalScanline)     \
135   {                        \
136     free(glyphScanline);   \
137   }                        \
138 } // For ensure that we call BEGIN_GLYPH_BITMAP before
139
140 // clang-format on
141 /// Helper macro define end.
142
143 /**
144  * @brief Data struct used to set the buffer of the glyph's bitmap into the final bitmap's buffer.
145  */
146 struct GlyphData
147 {
148   Devel::PixelBuffer               bitmapBuffer;     ///< The buffer of the whole bitmap. The format is RGBA8888.
149   Vector2*                         position;         ///< The position of the glyph.
150   TextAbstraction::GlyphBufferData glyphBitmap;      ///< The glyph's bitmap.
151   uint32_t                         width;            ///< The bitmap's width.
152   uint32_t                         height;           ///< The bitmap's height.
153   int32_t                          horizontalOffset; ///< The horizontal offset to be added to the 'x' glyph's position.
154   int32_t                          verticalOffset;   ///< The vertical offset to be added to the 'y' glyph's position.
155 };
156
157 /**
158  * @brief Sets the glyph's buffer into the bitmap's buffer.
159  *
160  * @param[in, out] data Struct which contains the glyph's data and the bitmap's data.
161  * @param[in] position The position of the glyph.
162  * @param[in] color The color of the glyph.
163  * @param[in] style The style of the text.
164  * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
165  */
166 void TypesetGlyph(GlyphData& __restrict__ data,
167                   const Vector2* const __restrict__ position,
168                   const Vector4* const __restrict__ color,
169                   const Typesetter::Style style,
170                   const Pixel::Format     pixelFormat)
171 {
172   if((0u == data.glyphBitmap.width) || (0u == data.glyphBitmap.height))
173   {
174     // Nothing to do if the width or height of the buffer is zero.
175     return;
176   }
177
178   // Initial vertical / horizontal offset.
179   const int32_t yOffset = data.verticalOffset + position->y;
180   const int32_t xOffset = data.horizontalOffset + position->x;
181
182   // Whether the given glyph is a color one.
183   const bool     isColorGlyph    = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
184   const uint32_t glyphPixelSize  = Pixel::GetBytesPerPixel(data.glyphBitmap.format);
185   const uint32_t glyphAlphaIndex = (glyphPixelSize > 0u) ? glyphPixelSize - 1u : 0u;
186
187   // Determinate iterator range.
188   const int32_t lineIndexRangeMin = std::max(0, -yOffset);
189   const int32_t lineIndexRangeMax = std::min(static_cast<int32_t>(data.glyphBitmap.height), static_cast<int32_t>(data.height) - yOffset);
190   const int32_t indexRangeMin     = std::max(0, -xOffset);
191   const int32_t indexRangeMax     = std::min(static_cast<int32_t>(data.glyphBitmap.width), static_cast<int32_t>(data.width) - xOffset);
192
193   // If current glyph don't need to be rendered, just ignore.
194   if(lineIndexRangeMax <= lineIndexRangeMin || indexRangeMax <= indexRangeMin)
195   {
196     return;
197   }
198
199   if(Pixel::RGBA8888 == pixelFormat)
200   {
201     uint32_t* __restrict__ bitmapBuffer = reinterpret_cast<uint32_t*>(data.bitmapBuffer.GetBuffer());
202     // Skip basic line.
203     bitmapBuffer += (lineIndexRangeMin + yOffset) * static_cast<int32_t>(data.width);
204
205     // Fast-cut if style is MASK or OUTLINE. Outline not shown for color glyph.
206     // Just overwrite transparent color and return.
207     if(isColorGlyph && (Typesetter::STYLE_MASK == style || Typesetter::STYLE_OUTLINE == style))
208     {
209       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
210       {
211         // We can use memset here.
212         memset(bitmapBuffer + xOffset + indexRangeMin, 0, (indexRangeMax - indexRangeMin) * sizeof(uint32_t));
213         bitmapBuffer += data.width;
214       }
215       return;
216     }
217
218     const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
219
220     // Precalculate input color's packed result.
221     uint32_t packedInputColor                    = 0u;
222     uint8_t* __restrict__ packedInputColorBuffer = reinterpret_cast<uint8_t*>(&packedInputColor);
223
224     *(packedInputColorBuffer + 3u) = static_cast<uint8_t>(color->a * 255);
225     *(packedInputColorBuffer + 2u) = static_cast<uint8_t>(color->b * 255);
226     *(packedInputColorBuffer + 1u) = static_cast<uint8_t>(color->g * 255);
227     *(packedInputColorBuffer)      = static_cast<uint8_t>(color->r * 255);
228
229     // Prepare glyph bitmap
230     BEGIN_GLYPH_BITMAP(data);
231
232     // Skip basic line of glyph.
233     SKIP_GLYPH_SCANLINE(lineIndexRangeMin);
234
235     // Traverse the pixels of the glyph line per line.
236     if(isColorGlyph)
237     {
238       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
239       {
240         BEGIN_GLYPH_SCANLINE_DECODE(data);
241
242         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
243         {
244           const int32_t xOffsetIndex = xOffset + index;
245
246           // Retrieves the color from the color glyph.
247           uint32_t packedColorGlyph                    = *(reinterpret_cast<const uint32_t*>(glyphScanline + (index << 2)));
248           uint8_t* __restrict__ packedColorGlyphBuffer = reinterpret_cast<uint8_t*>(&packedColorGlyph);
249
250           // Update the alpha channel.
251           const uint8_t colorAlpha       = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 3u), *(packedColorGlyphBuffer + 3u));
252           *(packedColorGlyphBuffer + 3u) = colorAlpha;
253
254           if(Typesetter::STYLE_SHADOW == style)
255           {
256             // The shadow of color glyph needs to have the shadow color.
257             *(packedColorGlyphBuffer + 2u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 2u), colorAlpha);
258             *(packedColorGlyphBuffer + 1u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 1u), colorAlpha);
259             *packedColorGlyphBuffer        = MultiplyAndNormalizeColor(*packedInputColorBuffer, colorAlpha);
260           }
261           else
262           {
263             if(swapChannelsBR)
264             {
265               std::swap(*packedColorGlyphBuffer, *(packedColorGlyphBuffer + 2u)); // Swap B and R.
266             }
267
268             *(packedColorGlyphBuffer + 2u) = MultiplyAndNormalizeColor(*(packedColorGlyphBuffer + 2u), colorAlpha);
269             *(packedColorGlyphBuffer + 1u) = MultiplyAndNormalizeColor(*(packedColorGlyphBuffer + 1u), colorAlpha);
270             *packedColorGlyphBuffer        = MultiplyAndNormalizeColor(*packedColorGlyphBuffer, colorAlpha);
271
272             if(data.glyphBitmap.isColorBitmap)
273             {
274               *(packedColorGlyphBuffer + 2u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 2u), *(packedColorGlyphBuffer + 2u));
275               *(packedColorGlyphBuffer + 1u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 1u), *(packedColorGlyphBuffer + 1u));
276               *packedColorGlyphBuffer        = MultiplyAndNormalizeColor(*packedInputColorBuffer, *packedColorGlyphBuffer);
277             }
278           }
279
280           // Set the color into the final pixel buffer.
281           *(bitmapBuffer + xOffsetIndex) = packedColorGlyph;
282         }
283
284         bitmapBuffer += data.width;
285
286         END_GLYPH_SCANLINE_DECODE(data);
287       }
288     }
289     else
290     {
291       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
292       {
293         BEGIN_GLYPH_SCANLINE_DECODE(data);
294
295         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
296         {
297           // Update the alpha channel.
298           const uint8_t alpha = *(glyphScanline + index * glyphPixelSize + glyphAlphaIndex);
299
300           // Copy non-transparent pixels only
301           if(alpha > 0u)
302           {
303             const int32_t xOffsetIndex = xOffset + index;
304
305             // Check alpha of overlapped pixels
306             uint32_t& currentColor             = *(bitmapBuffer + xOffsetIndex);
307             uint8_t*  packedCurrentColorBuffer = reinterpret_cast<uint8_t*>(&currentColor);
308
309             // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
310             // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
311             // semi-transparent gaps between joint glyphs with overlapped pixels, which could
312             // happen, for example, in the RTL text when we copy glyphs from right to left).
313             uint8_t currentAlpha = *(packedCurrentColorBuffer + 3u);
314             currentAlpha         = std::max(currentAlpha, alpha);
315             if(currentAlpha == 255)
316             {
317               // Fast-cut to avoid float type operation.
318               currentColor = packedInputColor;
319             }
320             else
321             {
322               // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
323               // The format is RGBA8888.
324               uint32_t packedColor                    = 0u;
325               uint8_t* __restrict__ packedColorBuffer = reinterpret_cast<uint8_t*>(&packedColor);
326
327               // Color is pre-muliplied with its alpha.
328               *(packedColorBuffer + 3u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 3u), currentAlpha);
329               *(packedColorBuffer + 2u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 2u), currentAlpha);
330               *(packedColorBuffer + 1u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 1u), currentAlpha);
331               *(packedColorBuffer)      = MultiplyAndNormalizeColor(*packedInputColorBuffer, currentAlpha);
332
333               // Set the color into the final pixel buffer.
334               currentColor = packedColor;
335             }
336           }
337         }
338
339         bitmapBuffer += data.width;
340
341         END_GLYPH_SCANLINE_DECODE(data);
342       }
343     }
344
345     END_GLYPH_BITMAP();
346   }
347   else // Pixel::L8
348   {
349     // Below codes required only if not color glyph.
350     if(!isColorGlyph)
351     {
352       uint8_t* __restrict__ bitmapBuffer = data.bitmapBuffer.GetBuffer();
353       // Skip basic line.
354       bitmapBuffer += (lineIndexRangeMin + yOffset) * static_cast<int32_t>(data.width);
355
356       // Prepare glyph bitmap
357       BEGIN_GLYPH_BITMAP(data);
358
359       // Skip basic line of glyph.
360       SKIP_GLYPH_SCANLINE(lineIndexRangeMin);
361
362       // Traverse the pixels of the glyph line per line.
363       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
364       {
365         BEGIN_GLYPH_SCANLINE_DECODE(data);
366
367         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
368         {
369           const int32_t xOffsetIndex = xOffset + index;
370
371           // Update the alpha channel.
372           const uint8_t alpha = *(glyphScanline + index * glyphPixelSize + glyphAlphaIndex);
373
374           // Copy non-transparent pixels only
375           if(alpha > 0u)
376           {
377             // Check alpha of overlapped pixels
378             uint8_t& currentAlpha = *(bitmapBuffer + xOffsetIndex);
379
380             // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
381             // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
382             // semi-transparent gaps between joint glyphs with overlapped pixels, which could
383             // happen, for example, in the RTL text when we copy glyphs from right to left).
384             currentAlpha = std::max(currentAlpha, alpha);
385           }
386         }
387
388         bitmapBuffer += data.width;
389
390         END_GLYPH_SCANLINE_DECODE(data);
391       }
392
393       END_GLYPH_BITMAP();
394     }
395   }
396 }
397
398 /// Draws the specified underline color to the buffer
399 void DrawUnderline(
400   const uint32_t                  bufferWidth,
401   const uint32_t                  bufferHeight,
402   GlyphData&                      glyphData,
403   const float                     baseline,
404   const float                     currentUnderlinePosition,
405   const float                     maxUnderlineHeight,
406   const float                     lineExtentLeft,
407   const float                     lineExtentRight,
408   const UnderlineStyleProperties& commonUnderlineProperties,
409   const UnderlineStyleProperties& currentUnderlineProperties,
410   const LineRun&                  line)
411 {
412   const Vector4&              underlineColor       = currentUnderlineProperties.colorDefined ? currentUnderlineProperties.color : commonUnderlineProperties.color;
413   const Text::Underline::Type underlineType        = currentUnderlineProperties.typeDefined ? currentUnderlineProperties.type : commonUnderlineProperties.type;
414   const float                 dashedUnderlineWidth = currentUnderlineProperties.dashWidthDefined ? currentUnderlineProperties.dashWidth : commonUnderlineProperties.dashWidth;
415   const float                 dashedUnderlineGap   = currentUnderlineProperties.dashGapDefined ? currentUnderlineProperties.dashGap : commonUnderlineProperties.dashGap;
416
417   int32_t underlineYOffset = glyphData.verticalOffset + baseline + currentUnderlinePosition;
418
419   const uint32_t yRangeMin = underlineYOffset;
420   const uint32_t yRangeMax = std::min(bufferHeight, underlineYOffset + static_cast<uint32_t>(maxUnderlineHeight));
421   const uint32_t xRangeMin = static_cast<uint32_t>(glyphData.horizontalOffset + lineExtentLeft);
422   const uint32_t xRangeMax = std::min(bufferWidth, static_cast<uint32_t>(glyphData.horizontalOffset + lineExtentRight + 1)); // Due to include last point, we add 1 here
423
424   // If current glyph don't need to be rendered, just ignore.
425   if((underlineType != Text::Underline::DOUBLE && yRangeMax <= yRangeMin) || xRangeMax <= xRangeMin)
426   {
427     return;
428   }
429
430   // We can optimize by memset when underlineColor.a is near zero
431   uint8_t underlineColorAlpha = static_cast<uint8_t>(underlineColor.a * 255.f);
432
433   uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
434
435   // Skip yRangeMin line.
436   bitmapBuffer += yRangeMin * glyphData.width;
437
438   // Note if underlineType is DASHED, we cannot setup color by memset.
439   if(underlineType != Text::Underline::DASHED && underlineColorAlpha == 0)
440   {
441     for(uint32_t y = yRangeMin; y < yRangeMax; y++)
442     {
443       // We can use memset.
444       memset(bitmapBuffer + xRangeMin, 0, (xRangeMax - xRangeMin) * sizeof(uint32_t));
445       bitmapBuffer += glyphData.width;
446     }
447     if(underlineType == Text::Underline::DOUBLE)
448     {
449       int32_t        secondUnderlineYOffset = underlineYOffset - ONE_AND_A_HALF * maxUnderlineHeight;
450       const uint32_t secondYRangeMin        = static_cast<uint32_t>(std::max(0, secondUnderlineYOffset));
451       const uint32_t secondYRangeMax        = static_cast<uint32_t>(std::max(0, std::min(static_cast<int32_t>(bufferHeight), secondUnderlineYOffset + static_cast<int32_t>(maxUnderlineHeight))));
452
453       // Rewind bitmapBuffer pointer, and skip secondYRangeMin line.
454       bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer()) + yRangeMin * glyphData.width;
455
456       for(uint32_t y = secondYRangeMin; y < secondYRangeMax; y++)
457       {
458         // We can use memset.
459         memset(bitmapBuffer + xRangeMin, 0, (xRangeMax - xRangeMin) * sizeof(uint32_t));
460         bitmapBuffer += glyphData.width;
461       }
462     }
463   }
464   else
465   {
466     uint32_t packedUnderlineColor       = 0u;
467     uint8_t* packedUnderlineColorBuffer = reinterpret_cast<uint8_t*>(&packedUnderlineColor);
468
469     // Write the color to the pixel buffer
470     *(packedUnderlineColorBuffer + 3u) = underlineColorAlpha;
471     *(packedUnderlineColorBuffer + 2u) = static_cast<uint8_t>(underlineColor.b * underlineColorAlpha);
472     *(packedUnderlineColorBuffer + 1u) = static_cast<uint8_t>(underlineColor.g * underlineColorAlpha);
473     *(packedUnderlineColorBuffer)      = static_cast<uint8_t>(underlineColor.r * underlineColorAlpha);
474
475     for(uint32_t y = yRangeMin; y < yRangeMax; y++)
476     {
477       if(underlineType == Text::Underline::DASHED)
478       {
479         float dashWidth = dashedUnderlineWidth;
480         float dashGap   = 0;
481
482         for(uint32_t x = xRangeMin; x < xRangeMax; x++)
483         {
484           if(Dali::EqualsZero(dashGap) && dashWidth > 0)
485           {
486             // Note : this is same logic as bitmap[y][x] = underlineColor;
487             *(bitmapBuffer + x) = packedUnderlineColor;
488             dashWidth--;
489           }
490           else if(dashGap < dashedUnderlineGap)
491           {
492             dashGap++;
493           }
494           else
495           {
496             //reset
497             dashWidth = dashedUnderlineWidth;
498             dashGap   = 0;
499           }
500         }
501       }
502       else
503       {
504         for(uint32_t x = xRangeMin; x < xRangeMax; x++)
505         {
506           // Note : this is same logic as bitmap[y][x] = underlineColor;
507           *(bitmapBuffer + x) = packedUnderlineColor;
508         }
509       }
510       bitmapBuffer += glyphData.width;
511     }
512     if(underlineType == Text::Underline::DOUBLE)
513     {
514       int32_t        secondUnderlineYOffset = underlineYOffset - ONE_AND_A_HALF * maxUnderlineHeight;
515       const uint32_t secondYRangeMin        = static_cast<uint32_t>(std::max(0, secondUnderlineYOffset));
516       const uint32_t secondYRangeMax        = static_cast<uint32_t>(std::max(0, std::min(static_cast<int32_t>(bufferHeight), secondUnderlineYOffset + static_cast<int32_t>(maxUnderlineHeight))));
517
518       // Rewind bitmapBuffer pointer, and skip secondYRangeMin line.
519       bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer()) + yRangeMin * glyphData.width;
520
521       for(uint32_t y = secondYRangeMin; y < secondYRangeMax; y++)
522       {
523         for(uint32_t x = xRangeMin; x < xRangeMax; x++)
524         {
525           // Note : this is same logic as bitmap[y][x] = underlineColor;
526           *(bitmapBuffer + x) = packedUnderlineColor;
527         }
528         bitmapBuffer += glyphData.width;
529       }
530     }
531   }
532 }
533
534 /// Draws the background color to the buffer
535 void DrawBackgroundColor(
536   Vector4        backgroundColor,
537   const uint32_t bufferWidth,
538   const uint32_t bufferHeight,
539   GlyphData&     glyphData,
540   const float    baseline,
541   const LineRun& line,
542   const float    lineExtentLeft,
543   const float    lineExtentRight)
544 {
545   const int32_t yRangeMin = std::max(0, static_cast<int32_t>(glyphData.verticalOffset + baseline - line.ascender));
546   const int32_t yRangeMax = std::min(static_cast<int32_t>(bufferHeight), static_cast<int32_t>(glyphData.verticalOffset + baseline - line.descender));
547   const int32_t xRangeMin = std::max(0, static_cast<int32_t>(glyphData.horizontalOffset + lineExtentLeft));
548   const int32_t xRangeMax = std::min(static_cast<int32_t>(bufferWidth), static_cast<int32_t>(glyphData.horizontalOffset + lineExtentRight + 1)); // Due to include last point, we add 1 here
549
550   // If current glyph don't need to be rendered, just ignore.
551   if(yRangeMax <= yRangeMin || xRangeMax <= xRangeMin)
552   {
553     return;
554   }
555
556   // We can optimize by memset when backgroundColor.a is near zero
557   uint8_t backgroundColorAlpha = static_cast<uint8_t>(backgroundColor.a * 255.f);
558
559   uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
560
561   // Skip yRangeMin line.
562   bitmapBuffer += yRangeMin * glyphData.width;
563
564   if(backgroundColorAlpha == 0)
565   {
566     for(int32_t y = yRangeMin; y < yRangeMax; y++)
567     {
568       // We can use memset.
569       memset(bitmapBuffer + xRangeMin, 0, (xRangeMax - xRangeMin) * sizeof(uint32_t));
570       bitmapBuffer += glyphData.width;
571     }
572   }
573   else
574   {
575     uint32_t packedBackgroundColor       = 0u;
576     uint8_t* packedBackgroundColorBuffer = reinterpret_cast<uint8_t*>(&packedBackgroundColor);
577
578     // Write the color to the pixel buffer
579     *(packedBackgroundColorBuffer + 3u) = backgroundColorAlpha;
580     *(packedBackgroundColorBuffer + 2u) = static_cast<uint8_t>(backgroundColor.b * backgroundColorAlpha);
581     *(packedBackgroundColorBuffer + 1u) = static_cast<uint8_t>(backgroundColor.g * backgroundColorAlpha);
582     *(packedBackgroundColorBuffer)      = static_cast<uint8_t>(backgroundColor.r * backgroundColorAlpha);
583
584     for(int32_t y = yRangeMin; y < yRangeMax; y++)
585     {
586       for(int32_t x = xRangeMin; x < xRangeMax; x++)
587       {
588         // Note : this is same logic as bitmap[y][x] = backgroundColor;
589         *(bitmapBuffer + x) = packedBackgroundColor;
590       }
591       bitmapBuffer += glyphData.width;
592     }
593   }
594 }
595
596 Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuffer& buffer, const uint32_t bufferWidth, const uint32_t bufferHeight, const bool ignoreHorizontalAlignment, const int32_t horizontalOffset, const int32_t verticalOffset)
597 {
598   // Retrieve lines, glyphs, positions and colors from the view model.
599   const Length            modelNumberOfLines           = model->GetNumberOfLines();
600   const LineRun* const    modelLinesBuffer             = model->GetLines();
601   const Length            numberOfGlyphs               = model->GetNumberOfGlyphs();
602   const GlyphInfo* const  glyphsBuffer                 = model->GetGlyphs();
603   const Vector2* const    positionBuffer               = model->GetLayout();
604   const Vector4* const    backgroundColorsBuffer       = model->GetBackgroundColors();
605   const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices();
606   const bool              removeFrontInset             = model->IsRemoveFrontInset();
607   const bool              removeBackInset              = model->IsRemoveBackInset();
608
609   const DevelText::VerticalLineAlignment::Type verLineAlign = model->GetVerticalLineAlignment();
610
611   // Create and initialize the pixel buffer.
612   GlyphData glyphData;
613   glyphData.verticalOffset   = verticalOffset;
614   glyphData.width            = bufferWidth;
615   glyphData.height           = bufferHeight;
616   glyphData.bitmapBuffer     = buffer;
617   glyphData.horizontalOffset = 0;
618
619   ColorIndex prevBackgroundColorIndex = 0;
620   ColorIndex backgroundColorIndex     = 0;
621
622   // Traverses the lines of the text.
623   for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
624   {
625     const LineRun& line = *(modelLinesBuffer + lineIndex);
626
627     // Sets the horizontal offset of the line.
628     glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int32_t>(line.alignmentOffset);
629     glyphData.horizontalOffset += horizontalOffset;
630
631     // Increases the vertical offset with the line's ascender.
632     glyphData.verticalOffset += static_cast<int32_t>(line.ascender + GetPreOffsetVerticalLineAlignment(line, verLineAlign));
633
634     float left     = bufferWidth;
635     float right    = 0.0f;
636     float baseline = 0.0f;
637
638     // Traverses the glyphs of the line.
639     const GlyphIndex endGlyphIndex = std::min(numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs);
640     for(GlyphIndex glyphIndex = line.glyphRun.glyphIndex; glyphIndex < endGlyphIndex; ++glyphIndex)
641     {
642       // Retrieve the glyph's info.
643       const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
644
645       if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
646          (glyphInfo->height < Math::MACHINE_EPSILON_1000))
647       {
648         // Nothing to do if default background color, the glyph's width or height is zero.
649         continue;
650       }
651
652       backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + glyphIndex);
653
654       if((backgroundColorIndex != prevBackgroundColorIndex) &&
655          (prevBackgroundColorIndex != 0u))
656       {
657         const Vector4& backgroundColor = *(backgroundColorsBuffer + prevBackgroundColorIndex - 1u);
658         DrawBackgroundColor(backgroundColor, bufferWidth, bufferHeight, glyphData, baseline, line, left, right);
659       }
660
661       if(backgroundColorIndex == 0u)
662       {
663         prevBackgroundColorIndex = backgroundColorIndex;
664         //if background color is the default do nothing
665         continue;
666       }
667
668       // Retrieves the glyph's position.
669       const Vector2* const position = positionBuffer + glyphIndex;
670
671       if(baseline < position->y + glyphInfo->yBearing)
672       {
673         baseline = position->y + glyphInfo->yBearing;
674       }
675
676       // Calculate the positions of leftmost and rightmost glyphs in the current line
677       if(removeFrontInset)
678       {
679         if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
680         {
681           left = position->x;
682         }
683       }
684       else
685       {
686         const float originPositionLeft = position->x - glyphInfo->xBearing;
687         if((originPositionLeft < left) || (backgroundColorIndex != prevBackgroundColorIndex))
688         {
689           left = originPositionLeft;
690         }
691       }
692
693       if(removeBackInset)
694       {
695         if(position->x + glyphInfo->width > right)
696         {
697           right = position->x - position->x + glyphInfo->width;
698         }
699       }
700       else
701       {
702         const float originPositionRight = position->x - glyphInfo->xBearing + glyphInfo->advance;
703         if(originPositionRight > right)
704         {
705           right = originPositionRight;
706         }
707       }
708
709       prevBackgroundColorIndex = backgroundColorIndex;
710     }
711
712     //draw last background at line end if not default
713     if(backgroundColorIndex != 0u)
714     {
715       const Vector4& backgroundColor = *(backgroundColorsBuffer + backgroundColorIndex - 1u);
716       DrawBackgroundColor(backgroundColor, bufferWidth, bufferHeight, glyphData, baseline, line, left, right);
717     }
718
719     // Increases the vertical offset with the line's descender.
720     glyphData.verticalOffset += static_cast<int32_t>(-line.descender + GetPostOffsetVerticalLineAlignment(line, verLineAlign));
721   }
722
723   return glyphData.bitmapBuffer;
724 }
725
726 /// Draws the specified strikethrough color to the buffer
727 void DrawStrikethrough(const uint32_t                      bufferWidth,
728                        const uint32_t                      bufferHeight,
729                        GlyphData&                          glyphData,
730                        const float                         baseline,
731                        const float                         strikethroughStartingYPosition,
732                        const float                         maxStrikethroughHeight,
733                        const float                         lineExtentLeft,
734                        const float                         lineExtentRight,
735                        const StrikethroughStyleProperties& commonStrikethroughProperties,
736                        const StrikethroughStyleProperties& currentStrikethroughProperties,
737                        const LineRun&                      line)
738 {
739   const Vector4& strikethroughColor = currentStrikethroughProperties.colorDefined ? currentStrikethroughProperties.color : commonStrikethroughProperties.color;
740
741   const uint32_t yRangeMin = static_cast<uint32_t>(strikethroughStartingYPosition);
742   const uint32_t yRangeMax = std::min(bufferHeight, static_cast<uint32_t>(strikethroughStartingYPosition + maxStrikethroughHeight));
743   const uint32_t xRangeMin = static_cast<uint32_t>(glyphData.horizontalOffset + lineExtentLeft);
744   const uint32_t xRangeMax = std::min(bufferWidth, static_cast<uint32_t>(glyphData.horizontalOffset + lineExtentRight + 1)); // Due to include last point, we add 1 here
745
746   // If current glyph don't need to be rendered, just ignore.
747   if(yRangeMax <= yRangeMin || xRangeMax <= xRangeMin)
748   {
749     return;
750   }
751
752   // We can optimize by memset when strikethroughColor.a is near zero
753   uint8_t strikethroughColorAlpha = static_cast<uint8_t>(strikethroughColor.a * 255.f);
754
755   uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
756
757   // Skip yRangeMin line.
758   bitmapBuffer += yRangeMin * glyphData.width;
759
760   if(strikethroughColorAlpha == 0)
761   {
762     for(uint32_t y = yRangeMin; y < yRangeMax; y++)
763     {
764       // We can use memset.
765       memset(bitmapBuffer + xRangeMin, 0, (xRangeMax - xRangeMin) * sizeof(uint32_t));
766       bitmapBuffer += glyphData.width;
767     }
768   }
769   else
770   {
771     uint32_t packedStrikethroughColor       = 0u;
772     uint8_t* packedStrikethroughColorBuffer = reinterpret_cast<uint8_t*>(&packedStrikethroughColor);
773
774     // Write the color to the pixel buffer
775     *(packedStrikethroughColorBuffer + 3u) = strikethroughColorAlpha;
776     *(packedStrikethroughColorBuffer + 2u) = static_cast<uint8_t>(strikethroughColor.b * strikethroughColorAlpha);
777     *(packedStrikethroughColorBuffer + 1u) = static_cast<uint8_t>(strikethroughColor.g * strikethroughColorAlpha);
778     *(packedStrikethroughColorBuffer)      = static_cast<uint8_t>(strikethroughColor.r * strikethroughColorAlpha);
779
780     for(uint32_t y = yRangeMin; y < yRangeMax; y++)
781     {
782       for(uint32_t x = xRangeMin; x < xRangeMax; x++)
783       {
784         // Note : this is same logic as bitmap[y][x] = strikethroughColor;
785         *(bitmapBuffer + x) = packedStrikethroughColor;
786       }
787       bitmapBuffer += glyphData.width;
788     }
789   }
790 }
791
792 /**
793  * @brief Create an initialized image buffer filled with transparent color.
794  *
795  * Creates the pixel data used to generate the final image with the given size.
796  *
797  * @param[in] bufferWidth The width of the image buffer.
798  * @param[in] bufferHeight The height of the image buffer.
799  * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
800  *
801  * @return An image buffer.
802  */
803 inline Devel::PixelBuffer CreateTransparentImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Pixel::Format pixelFormat)
804 {
805   Devel::PixelBuffer imageBuffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat);
806
807   if(Pixel::RGBA8888 == pixelFormat)
808   {
809     const uint32_t bufferSizeInt  = bufferWidth * bufferHeight;
810     const size_t   bufferSizeChar = sizeof(uint32_t) * static_cast<std::size_t>(bufferSizeInt);
811     memset(imageBuffer.GetBuffer(), 0, bufferSizeChar);
812   }
813   else
814   {
815     memset(imageBuffer.GetBuffer(), 0, static_cast<std::size_t>(bufferWidth * bufferHeight));
816   }
817
818   return imageBuffer;
819 }
820
821 /**
822  * @brief Combine the two RGBA image buffers together.
823  *
824  * The top layer buffer will blend over the bottom layer buffer:
825  * - If the pixel is not fully opaque from either buffer, it will be blended with
826  *   the pixel from the other buffer and copied to the combined buffer.
827  * - If the pixels from both buffers are fully opaque, the pixels from the top layer
828  *   buffer will be copied to the combined buffer.
829  *
830  * Due to the performance issue, We need to re-use input'ed pixelBuffer memory.
831  * We can determine which pixelBuffer's memory is destination
832  *
833  * @param[in, out] topPixelBuffer The top layer buffer.
834  * @param[in, out] bottomPixelBuffer The bottom layer buffer.
835  * @param[in] bufferWidth The width of the image buffer.
836  * @param[in] bufferHeight The height of the image buffer.
837  * @param[in] storeResultIntoTop True if we store the combined image buffer result into topPixelBuffer.
838  * False if we store the combined image buffer result into bottomPixelBuffer.
839  *
840  */
841 void CombineImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, bool storeResultIntoTop)
842 {
843   // Assume that we always combine two RGBA images
844   // Jump with 4bytes for optimize runtime.
845   uint32_t* topBuffer    = reinterpret_cast<uint32_t*>(topPixelBuffer.GetBuffer());
846   uint32_t* bottomBuffer = reinterpret_cast<uint32_t*>(bottomPixelBuffer.GetBuffer());
847
848   if(topBuffer == NULL && bottomBuffer == NULL)
849   {
850     // Nothing to do if both buffers are empty.
851     return;
852   }
853
854   if(topBuffer == NULL)
855   {
856     // Nothing to do if topBuffer is empty.
857     // If we need to store the result into top, change topPixelBuffer as bottomPixelBuffer.
858     if(storeResultIntoTop)
859     {
860       topPixelBuffer = bottomPixelBuffer;
861     }
862     return;
863   }
864
865   if(bottomBuffer == NULL)
866   {
867     // Nothing to do if bottomBuffer is empty.
868     // If we need to store the result into bottom, change bottomPixelBuffer as topPixelBuffer.
869     if(!storeResultIntoTop)
870     {
871       bottomPixelBuffer = topPixelBuffer;
872     }
873     return;
874   }
875
876   const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
877
878   uint32_t* __restrict__ combinedBuffer       = storeResultIntoTop ? topBuffer : bottomBuffer;
879   uint8_t* __restrict__ topAlphaBufferPointer = reinterpret_cast<uint8_t*>(topBuffer) + 3;
880
881   for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex)
882   {
883     // If the alpha of the pixel in either buffer is not fully opaque, blend the two pixels.
884     // Otherwise, copy pixel from topBuffer to combinedBuffer.
885     // Note : Be careful when we read & write into combinedBuffer. It can be write into same pointer.
886
887     uint8_t topAlpha = *topAlphaBufferPointer;
888
889     if(topAlpha == 0)
890     {
891       // Copy the pixel from bottomBuffer to combinedBuffer
892       if(storeResultIntoTop)
893       {
894         *(combinedBuffer) = *(bottomBuffer);
895       }
896     }
897     else if(topAlpha == 255)
898     {
899       // Copy the pixel from topBuffer to combinedBuffer
900       if(!storeResultIntoTop)
901       {
902         *(combinedBuffer) = *(topBuffer);
903       }
904     }
905     else
906     {
907       // At least one pixel is not fully opaque
908       // "Over" blend the the pixel from topBuffer with the pixel in bottomBuffer
909       uint32_t blendedBottomBufferColor                    = *(bottomBuffer);
910       uint8_t* __restrict__ blendedBottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&blendedBottomBufferColor);
911
912       blendedBottomBufferColorBuffer[0] = MultiplyAndNormalizeColor(blendedBottomBufferColorBuffer[0], 255 - topAlpha);
913       blendedBottomBufferColorBuffer[1] = MultiplyAndNormalizeColor(blendedBottomBufferColorBuffer[1], 255 - topAlpha);
914       blendedBottomBufferColorBuffer[2] = MultiplyAndNormalizeColor(blendedBottomBufferColorBuffer[2], 255 - topAlpha);
915       blendedBottomBufferColorBuffer[3] = MultiplyAndNormalizeColor(blendedBottomBufferColorBuffer[3], 255 - topAlpha);
916
917       *(combinedBuffer) = *(topBuffer) + blendedBottomBufferColor;
918     }
919
920     // Increase each buffer's pointer.
921     ++combinedBuffer;
922     ++topBuffer;
923     ++bottomBuffer;
924     topAlphaBufferPointer += sizeof(uint32_t) / sizeof(uint8_t);
925   }
926 }
927
928 } // namespace
929
930 TypesetterPtr Typesetter::New(const ModelInterface* const model)
931 {
932   return TypesetterPtr(new Typesetter(model));
933 }
934
935 ViewModel* Typesetter::GetViewModel()
936 {
937   return mModel;
938 }
939
940 PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
941 {
942   Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
943   PixelData pixelData = Devel::PixelBuffer::Convert(result);
944
945   return pixelData;
946 }
947
948 PixelData Typesetter::RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer mask, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, float originAlpha)
949 {
950   Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
951   SetMaskForImageBuffer(mask, result, size.width, size.height, originAlpha);
952
953   PixelData pixelData = Devel::PixelBuffer::Convert(result);
954
955   return pixelData;
956 }
957
958 Devel::PixelBuffer Typesetter::RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
959 {
960   DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_RENDERING_TYPESETTER");
961   // @todo. This initial implementation for a TextLabel has only one visible page.
962
963   // Elides the text if needed.
964   mModel->ElideGlyphs();
965
966   // Retrieves the layout size.
967   const Size& layoutSize = mModel->GetLayoutSize();
968   const int32_t outlineWidth = static_cast<int32_t>(mModel->GetOutlineWidth());
969
970   // Set the offset for the horizontal alignment according to the text direction and outline width.
971   int32_t penX = 0;
972   switch(mModel->GetHorizontalAlignment())
973   {
974     case HorizontalAlignment::BEGIN:
975     {
976       // No offset to add.
977       break;
978     }
979     case HorizontalAlignment::CENTER:
980     {
981       penX += (textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT) ? -outlineWidth : outlineWidth;
982       break;
983     }
984     case HorizontalAlignment::END:
985     {
986       penX += (textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT) ? -outlineWidth * 2 : outlineWidth * 2;
987       break;
988     }
989   }
990
991   // Set the offset for the vertical alignment.
992   int32_t penY = 0u;
993   switch(mModel->GetVerticalAlignment())
994   {
995     case VerticalAlignment::TOP:
996     {
997       // No offset to add.
998       break;
999     }
1000     case VerticalAlignment::CENTER:
1001     {
1002       penY = static_cast<int32_t>(std::round(0.5f * (size.height - layoutSize.height)));
1003       penY = penY < 0.f ? 0.f : penY;
1004
1005       break;
1006     }
1007     case VerticalAlignment::BOTTOM:
1008     {
1009       penY = static_cast<int32_t>(size.height - layoutSize.height);
1010       break;
1011     }
1012   }
1013
1014   // Generate the image buffers of the text for each different style first,
1015   // then combine all of them together as one final image buffer. We try to
1016   // do all of these in CPU only, so that once the final texture is generated,
1017   // no calculation is needed in GPU during each frame.
1018
1019   const uint32_t bufferWidth  = static_cast<uint32_t>(size.width);
1020   const uint32_t bufferHeight = static_cast<uint32_t>(size.height);
1021
1022   const uint32_t bufferSizeInt  = bufferWidth * bufferHeight;
1023   const size_t   bufferSizeChar = sizeof(uint32_t) * static_cast<std::size_t>(bufferSizeInt);
1024
1025   //Elided text in ellipsis at START could start on index greater than 0
1026   auto startIndexOfGlyphs = mModel->GetStartIndexOfElidedGlyphs();
1027   auto endIndexOfGlyphs   = mModel->GetEndIndexOfElidedGlyphs();
1028
1029   Devel::PixelBuffer imageBuffer;
1030
1031   if(RENDER_MASK == behaviour)
1032   {
1033     // Generate the image buffer as an alpha mask for color glyphs.
1034     imageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
1035   }
1036   else if(RENDER_NO_TEXT == behaviour || RENDER_OVERLAY_STYLE == behaviour)
1037   {
1038     // Generate an empty image buffer so that it can been combined with the image buffers for styles
1039     imageBuffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
1040     memset(imageBuffer.GetBuffer(), 0u, bufferSizeChar);
1041   }
1042   else
1043   {
1044     // Generate the image buffer for the text with no style.
1045     imageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
1046   }
1047
1048   if((RENDER_NO_STYLES != behaviour) && (RENDER_MASK != behaviour))
1049   {
1050     // Generate the outline if enabled
1051     const uint16_t outlineWidth = mModel->GetOutlineWidth();
1052     const float    outlineAlpha = mModel->GetOutlineColor().a;
1053     if(outlineWidth != 0u && fabsf(outlineAlpha) > Math::MACHINE_EPSILON_1 && RENDER_OVERLAY_STYLE != behaviour)
1054     {
1055       // Create the image buffer for outline
1056       Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
1057
1058       const float& blurRadius = mModel->GetOutlineBlurRadius();
1059
1060       if(blurRadius > Math::MACHINE_EPSILON_1)
1061       {
1062         outlineImageBuffer.ApplyGaussianBlur(blurRadius);
1063       }
1064
1065       // Combine the two buffers
1066       CombineImageBuffer(imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight, true);
1067     }
1068
1069     // @todo. Support shadow for partial text later on.
1070
1071     // Generate the shadow if enabled
1072     const Vector2& shadowOffset = mModel->GetShadowOffset();
1073     const float    shadowAlpha  = mModel->GetShadowColor().a;
1074     if(RENDER_OVERLAY_STYLE != behaviour && fabsf(shadowAlpha) > Math::MACHINE_EPSILON_1 && (fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1))
1075     {
1076       // Create the image buffer for shadow
1077       Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
1078
1079       // Check whether it will be a soft shadow
1080       const float& blurRadius = mModel->GetShadowBlurRadius();
1081
1082       if(blurRadius > Math::MACHINE_EPSILON_1)
1083       {
1084         shadowImageBuffer.ApplyGaussianBlur(blurRadius);
1085       }
1086
1087       // Combine the two buffers
1088       CombineImageBuffer(imageBuffer, shadowImageBuffer, bufferWidth, bufferHeight, true);
1089     }
1090
1091     // Generate the background if enabled
1092     const bool backgroundEnabled   = mModel->IsBackgroundEnabled();
1093     const bool backgroundMarkupSet = mModel->IsMarkupBackgroundColorSet();
1094     if((backgroundEnabled || backgroundMarkupSet) && RENDER_OVERLAY_STYLE != behaviour)
1095     {
1096       Devel::PixelBuffer backgroundImageBuffer;
1097
1098       if(backgroundEnabled)
1099       {
1100         backgroundImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_BACKGROUND, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
1101       }
1102       else
1103       {
1104         backgroundImageBuffer = CreateTransparentImageBuffer(bufferWidth, bufferHeight, pixelFormat);
1105       }
1106
1107       if(backgroundMarkupSet)
1108       {
1109         DrawGlyphsBackground(mModel, backgroundImageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, penX, penY);
1110       }
1111
1112       // Combine the two buffers
1113       CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
1114     }
1115
1116     // Generate the background_with_mask if enabled
1117     const bool backgroundWithCutoutEnabled   = mModel->IsBackgroundWithCutoutEnabled();
1118     if((backgroundWithCutoutEnabled) && RENDER_OVERLAY_STYLE != behaviour)
1119     {
1120       Devel::PixelBuffer backgroundImageBuffer;
1121
1122       backgroundImageBuffer = CreateFullBackgroundBuffer(bufferWidth, bufferHeight, mModel->GetBackgroundColorWithCutout());
1123
1124       // Combine the two buffers
1125       CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
1126     }
1127
1128     if(RENDER_OVERLAY_STYLE == behaviour)
1129     {
1130       if(mModel->IsUnderlineEnabled())
1131       {
1132         // Create the image buffer for underline
1133         Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
1134
1135         // Combine the two buffers
1136         CombineImageBuffer(imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight, true);
1137       }
1138
1139       if(mModel->IsStrikethroughEnabled())
1140       {
1141         // Create the image buffer for strikethrough
1142         Devel::PixelBuffer strikethroughImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_STRIKETHROUGH, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, endIndexOfGlyphs);
1143
1144         // Combine the two buffers
1145         CombineImageBuffer(imageBuffer, strikethroughImageBuffer, bufferWidth, bufferHeight, true);
1146       }
1147
1148       // Markup-Processor for overlay styles
1149       if(mModel->IsMarkupProcessorEnabled() || mModel->IsSpannedTextPlaced())
1150       {
1151         if(mModel->IsMarkupUnderlineSet())
1152         {
1153           imageBuffer = ApplyUnderlineMarkupImageBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
1154         }
1155
1156         if(mModel->IsMarkupStrikethroughSet())
1157         {
1158           imageBuffer = ApplyStrikethroughMarkupImageBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
1159         }
1160       }
1161     }
1162   }
1163
1164   return imageBuffer;
1165 }
1166
1167 Devel::PixelBuffer Typesetter::CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor)
1168 {
1169   const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
1170   uint8_t backgroundColorAlpha = static_cast<uint8_t>(backgroundColor.a * 255.f);
1171
1172   Devel::PixelBuffer buffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
1173
1174   uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(buffer.GetBuffer());
1175
1176   uint32_t packedBackgroundColor       = 0u;
1177   uint8_t* packedBackgroundColorBuffer = reinterpret_cast<uint8_t*>(&packedBackgroundColor);
1178
1179   // Write the color to the pixel buffer
1180   *(packedBackgroundColorBuffer + 3u) = backgroundColorAlpha;
1181   *(packedBackgroundColorBuffer + 2u) = static_cast<uint8_t>(backgroundColor.b * backgroundColorAlpha);
1182   *(packedBackgroundColorBuffer + 1u) = static_cast<uint8_t>(backgroundColor.g * backgroundColorAlpha);
1183   *(packedBackgroundColorBuffer)      = static_cast<uint8_t>(backgroundColor.r * backgroundColorAlpha);
1184
1185   std::fill(bitmapBuffer, bitmapBuffer + bufferSizeInt, packedBackgroundColor);
1186
1187   return buffer;
1188 }
1189
1190 Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Typesetter::Style style, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset, const GlyphIndex fromGlyphIndex, const GlyphIndex toGlyphIndex)
1191 {
1192   // Retrieve lines, glyphs, positions and colors from the view model.
1193   const Length modelNumberOfLines                       = mModel->GetNumberOfLines();
1194   const LineRun* const __restrict__ modelLinesBuffer    = mModel->GetLines();
1195   const GlyphInfo* const __restrict__ glyphsBuffer      = mModel->GetGlyphs();
1196   const Vector2* const __restrict__ positionBuffer      = mModel->GetLayout();
1197   const Vector4* const __restrict__ colorsBuffer        = mModel->GetColors();
1198   const ColorIndex* const __restrict__ colorIndexBuffer = mModel->GetColorIndices();
1199   const GlyphInfo* __restrict__ hyphens                 = mModel->GetHyphens();
1200   const Length* __restrict__ hyphenIndices              = mModel->GetHyphenIndices();
1201   const Length hyphensCount                             = mModel->GetHyphensCount();
1202   const bool removeFrontInset                           = mModel->IsRemoveFrontInset();
1203   const bool removeBackInset                            = mModel->IsRemoveBackInset();
1204   const bool cutoutEnabled                              = mModel->IsCutoutEnabled();
1205
1206   // Elided text info. Indices according to elided text and Ellipsis position.
1207   const auto startIndexOfGlyphs              = mModel->GetStartIndexOfElidedGlyphs();
1208   const auto endIndexOfGlyphs                = mModel->GetEndIndexOfElidedGlyphs();
1209   const auto firstMiddleIndexOfElidedGlyphs  = mModel->GetFirstMiddleIndexOfElidedGlyphs();
1210   const auto secondMiddleIndexOfElidedGlyphs = mModel->GetSecondMiddleIndexOfElidedGlyphs();
1211   const auto ellipsisPosition                = mModel->GetEllipsisPosition();
1212
1213   // Whether to use the default color.
1214   const bool     useDefaultColor = (NULL == colorsBuffer);
1215   const Vector4& defaultColor    = mModel->GetDefaultColor();
1216
1217   // Create and initialize the pixel buffer.
1218   GlyphData glyphData;
1219   glyphData.verticalOffset   = verticalOffset;
1220   glyphData.width            = bufferWidth;
1221   glyphData.height           = bufferHeight;
1222   glyphData.bitmapBuffer     = CreateTransparentImageBuffer(bufferWidth, bufferHeight, pixelFormat);
1223   glyphData.horizontalOffset = 0;
1224
1225   // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
1226   TextAbstraction::FontClient fontClient  = TextAbstraction::FontClient::Get();
1227   Length                      hyphenIndex = 0;
1228
1229   const Character* __restrict__ textBuffer                       = mModel->GetTextBuffer();
1230   float calculatedAdvance                                        = 0.f;
1231   const Vector<CharacterIndex>& __restrict__ glyphToCharacterMap = mModel->GetGlyphsToCharacters();
1232   const CharacterIndex* __restrict__ glyphToCharacterMapBuffer   = glyphToCharacterMap.Begin();
1233
1234   const DevelText::VerticalLineAlignment::Type verLineAlign = mModel->GetVerticalLineAlignment();
1235
1236   // Traverses the lines of the text.
1237   for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
1238   {
1239     const LineRun& line = *(modelLinesBuffer + lineIndex);
1240
1241     // Sets the horizontal offset of the line.
1242     glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int32_t>(line.alignmentOffset);
1243     glyphData.horizontalOffset += horizontalOffset;
1244
1245     // Increases the vertical offset with the line's ascender.
1246     glyphData.verticalOffset += static_cast<int32_t>(line.ascender + GetPreOffsetVerticalLineAlignment(line, verLineAlign));
1247
1248     // Retrieves the glyph's outline width
1249     float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
1250
1251     if(style == Typesetter::STYLE_OUTLINE)
1252     {
1253       const Vector2& outlineOffset = mModel->GetOutlineOffset();
1254
1255       glyphData.horizontalOffset -= outlineWidth;
1256       glyphData.horizontalOffset += outlineOffset.x;
1257       if(lineIndex == 0u)
1258       {
1259         // Only need to add the vertical outline offset for the first line
1260         glyphData.verticalOffset -= outlineWidth;
1261         glyphData.verticalOffset += outlineOffset.y;
1262       }
1263     }
1264     else if(style == Typesetter::STYLE_SHADOW)
1265     {
1266       const Vector2& shadowOffset = mModel->GetShadowOffset();
1267       glyphData.horizontalOffset += shadowOffset.x - outlineWidth; // if outline enabled then shadow should offset from outline
1268
1269       if(lineIndex == 0u)
1270       {
1271         // Only need to add the vertical shadow offset for first line
1272         glyphData.verticalOffset += shadowOffset.y - outlineWidth;
1273       }
1274     }
1275
1276     const bool  underlineEnabled      = mModel->IsUnderlineEnabled();
1277     const bool  strikethroughEnabled  = mModel->IsStrikethroughEnabled();
1278     const float modelCharacterSpacing = mModel->GetCharacterSpacing();
1279
1280     // Get the character-spacing runs.
1281     const Vector<CharacterSpacingGlyphRun>& __restrict__ characterSpacingGlyphRuns = mModel->GetCharacterSpacingGlyphRuns();
1282
1283     // Aggregate underline-style-properties from mModel
1284     const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
1285                                                             mModel->GetUnderlineColor(),
1286                                                             mModel->GetUnderlineHeight(),
1287                                                             mModel->GetDashedUnderlineGap(),
1288                                                             mModel->GetDashedUnderlineWidth(),
1289                                                             true,
1290                                                             true,
1291                                                             true,
1292                                                             true,
1293                                                             true};
1294
1295     // Aggregate strikethrough-style-properties from mModel
1296     const StrikethroughStyleProperties modelStrikethroughProperties{mModel->GetStrikethroughColor(),
1297                                                                     mModel->GetStrikethroughHeight(),
1298                                                                     true,
1299                                                                     true};
1300
1301     // Get the underline runs.
1302     const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
1303     Vector<UnderlinedGlyphRun> underlineRuns;
1304     underlineRuns.Resize(numberOfUnderlineRuns);
1305     mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
1306
1307     // Get the strikethrough runs.
1308     const Length                  numberOfStrikethroughRuns = mModel->GetNumberOfStrikethroughRuns();
1309     Vector<StrikethroughGlyphRun> strikethroughRuns;
1310     strikethroughRuns.Resize(numberOfStrikethroughRuns);
1311     mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
1312
1313     bool thereAreUnderlinedGlyphs    = false;
1314     bool thereAreStrikethroughGlyphs = false;
1315
1316     float currentUnderlinePosition   = 0.0f;
1317     float currentUnderlineHeight     = modelUnderlineProperties.height;
1318     float maxUnderlineHeight         = currentUnderlineHeight;
1319     auto  currentUnderlineProperties = modelUnderlineProperties;
1320
1321     float currentStrikethroughHeight     = modelStrikethroughProperties.height;
1322     float maxStrikethroughHeight         = currentStrikethroughHeight;
1323     auto  currentStrikethroughProperties = modelStrikethroughProperties;
1324     float strikethroughStartingYPosition = 0.0f;
1325
1326     FontId lastFontId = 0;
1327
1328     float lineExtentLeft  = bufferWidth;
1329     float lineExtentRight = 0.0f;
1330     float baseline        = 0.0f;
1331     bool  addHyphen       = false;
1332
1333     // Traverses the glyphs of the line.
1334     const GlyphIndex startGlyphIndex = std::max(std::max(line.glyphRun.glyphIndex, startIndexOfGlyphs), fromGlyphIndex);
1335     GlyphIndex       endGlyphIndex   = (line.isSplitToTwoHalves ? line.glyphRunSecondHalf.glyphIndex + line.glyphRunSecondHalf.numberOfGlyphs : line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs) - 1u;
1336     endGlyphIndex                    = std::min(std::min(endGlyphIndex, endIndexOfGlyphs), toGlyphIndex);
1337
1338     for(GlyphIndex glyphIndex = startGlyphIndex; glyphIndex <= endGlyphIndex; ++glyphIndex)
1339     {
1340       //To handle START case of ellipsis, the first glyph has been shifted
1341       //glyphIndex represent indices in whole glyphs but elidedGlyphIndex represents indices in elided Glyphs
1342       GlyphIndex elidedGlyphIndex = glyphIndex - startIndexOfGlyphs;
1343
1344       //To handle MIDDLE case of ellipsis, the first glyph in the second half of line has been shifted and skip the removed glyph from middle.
1345       if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
1346       {
1347         if(glyphIndex > firstMiddleIndexOfElidedGlyphs &&
1348            glyphIndex < secondMiddleIndexOfElidedGlyphs)
1349         {
1350           // Ignore any glyph that removed for MIDDLE ellipsis
1351           continue;
1352         }
1353         if(glyphIndex >= secondMiddleIndexOfElidedGlyphs)
1354         {
1355           elidedGlyphIndex -= (secondMiddleIndexOfElidedGlyphs - firstMiddleIndexOfElidedGlyphs - 1u);
1356         }
1357       }
1358
1359       // Retrieve the glyph's info.
1360       const GlyphInfo* glyphInfo;
1361
1362       if(addHyphen && hyphens)
1363       {
1364         glyphInfo = hyphens + hyphenIndex;
1365         hyphenIndex++;
1366       }
1367       else
1368       {
1369         glyphInfo = glyphsBuffer + elidedGlyphIndex;
1370       }
1371
1372       if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
1373          (glyphInfo->height < Math::MACHINE_EPSILON_1000))
1374       {
1375         // Nothing to do if the glyph's width or height is zero.
1376         continue;
1377       }
1378
1379       Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt = underlineRuns.End();
1380       const bool                                underlineGlyph              = underlineEnabled || IsGlyphUnderlined(glyphIndex, underlineRuns, currentUnderlinedGlyphRunIt);
1381       currentUnderlineProperties                                            = GetCurrentUnderlineProperties(glyphIndex, underlineGlyph, underlineRuns, currentUnderlinedGlyphRunIt, modelUnderlineProperties);
1382       currentUnderlineHeight                                                = currentUnderlineProperties.height;
1383       thereAreUnderlinedGlyphs                                              = thereAreUnderlinedGlyphs || underlineGlyph;
1384
1385       Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End();
1386       const bool                                   strikethroughGlyph             = strikethroughEnabled || IsGlyphStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughGlyphRunIt);
1387       currentStrikethroughProperties                                              = GetCurrentStrikethroughProperties(glyphIndex, strikethroughGlyph, strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties);
1388       currentStrikethroughHeight                                                  = currentStrikethroughProperties.height;
1389       thereAreStrikethroughGlyphs                                                 = thereAreStrikethroughGlyphs || strikethroughGlyph;
1390
1391       // Are we still using the same fontId as previous
1392       if((glyphInfo->fontId != lastFontId) && (strikethroughGlyph || underlineGlyph))
1393       {
1394         // We need to fetch fresh font underline metrics
1395         FontMetrics fontMetrics;
1396         fontClient.GetFontMetrics(glyphInfo->fontId, fontMetrics);
1397
1398         //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
1399         currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(fontMetrics);
1400
1401         if(underlineGlyph)
1402         {
1403           CalcualteUnderlineHeight(fontMetrics, currentUnderlineHeight, maxUnderlineHeight);
1404         }
1405
1406         if(strikethroughGlyph)
1407         {
1408           CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight);
1409         }
1410
1411         // Update lastFontId because fontId is changed
1412         lastFontId = glyphInfo->fontId; // Prevents searching for existing blocksizes when string of the same fontId.
1413       }
1414
1415       // Retrieves the glyph's position.
1416       Vector2 position = *(positionBuffer + elidedGlyphIndex);
1417
1418       if(addHyphen)
1419       {
1420         GlyphInfo   tempInfo         = *(glyphsBuffer + elidedGlyphIndex);
1421         const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
1422         calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + elidedGlyphIndex))), characterSpacing, tempInfo.advance);
1423         position.x                   = position.x + calculatedAdvance - tempInfo.xBearing + glyphInfo->xBearing;
1424         position.y                   = -glyphInfo->yBearing;
1425       }
1426
1427       if(baseline < position.y + glyphInfo->yBearing)
1428       {
1429         baseline = position.y + glyphInfo->yBearing;
1430       }
1431
1432       // Calculate the positions of leftmost and rightmost glyphs in the current line
1433       if(removeFrontInset)
1434       {
1435         if(position.x < lineExtentLeft)
1436         {
1437           lineExtentLeft = position.x;
1438         }
1439       }
1440       else
1441       {
1442         const float originPositionLeft = position.x - glyphInfo->xBearing;
1443         if(originPositionLeft < lineExtentLeft)
1444         {
1445           lineExtentLeft = originPositionLeft;
1446         }
1447       }
1448
1449       if(removeBackInset)
1450       {
1451         if(position.x + glyphInfo->width > lineExtentRight)
1452         {
1453           lineExtentRight = position.x + glyphInfo->width;
1454         }
1455       }
1456       else
1457       {
1458         const float originPositionRight = position.x - glyphInfo->xBearing + glyphInfo->advance;
1459         if(originPositionRight > lineExtentRight)
1460         {
1461           lineExtentRight = originPositionRight;
1462         }
1463       }
1464
1465       // Retrieves the glyph's color.
1466       const ColorIndex colorIndex = useDefaultColor ? 0u : *(colorIndexBuffer + glyphIndex);
1467
1468       Vector4 color;
1469       if(style == Typesetter::STYLE_SHADOW)
1470       {
1471         color = mModel->GetShadowColor();
1472       }
1473       else if(style == Typesetter::STYLE_OUTLINE)
1474       {
1475         color = mModel->GetOutlineColor();
1476       }
1477       else
1478       {
1479         color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + (colorIndex - 1u));
1480       }
1481
1482       if(style == Typesetter::STYLE_NONE && cutoutEnabled)
1483       {
1484         // Temporarily adjust the transparency to 1.f
1485         color.a = 1.f;
1486       }
1487
1488       // Premultiply alpha
1489       color.r *= color.a;
1490       color.g *= color.a;
1491       color.b *= color.a;
1492
1493       // Retrieves the glyph's bitmap.
1494       glyphData.glyphBitmap.buffer = NULL;
1495       glyphData.glyphBitmap.width  = glyphInfo->width; // Desired width and height.
1496       glyphData.glyphBitmap.height = glyphInfo->height;
1497
1498       if(style != Typesetter::STYLE_OUTLINE && style != Typesetter::STYLE_SHADOW)
1499       {
1500         // Don't render outline for other styles
1501         outlineWidth = 0.0f;
1502       }
1503
1504       if(style != Typesetter::STYLE_UNDERLINE && style != Typesetter::STYLE_STRIKETHROUGH)
1505       {
1506         fontClient.CreateBitmap(glyphInfo->fontId,
1507                                 glyphInfo->index,
1508                                 glyphInfo->isItalicRequired,
1509                                 glyphInfo->isBoldRequired,
1510                                 glyphData.glyphBitmap,
1511                                 static_cast<int32_t>(outlineWidth));
1512       }
1513
1514       // Sets the glyph's bitmap into the bitmap of the whole text.
1515       if(NULL != glyphData.glyphBitmap.buffer)
1516       {
1517         if(style == Typesetter::STYLE_OUTLINE)
1518         {
1519           // Set the position offset for the current glyph
1520           glyphData.horizontalOffset -= glyphData.glyphBitmap.outlineOffsetX;
1521           glyphData.verticalOffset -= glyphData.glyphBitmap.outlineOffsetY;
1522         }
1523
1524         // Set the buffer of the glyph's bitmap into the final bitmap's buffer
1525         TypesetGlyph(glyphData,
1526                      &position,
1527                      &color,
1528                      style,
1529                      pixelFormat);
1530
1531         if(style == Typesetter::STYLE_OUTLINE)
1532         {
1533           // Reset the position offset for the next glyph
1534           glyphData.horizontalOffset += glyphData.glyphBitmap.outlineOffsetX;
1535           glyphData.verticalOffset += glyphData.glyphBitmap.outlineOffsetY;
1536         }
1537
1538         // free the glyphBitmap.buffer if it is owner of buffer
1539         if(glyphData.glyphBitmap.isBufferOwned)
1540         {
1541           free(glyphData.glyphBitmap.buffer);
1542           glyphData.glyphBitmap.isBufferOwned = false;
1543         }
1544         glyphData.glyphBitmap.buffer = NULL;
1545       }
1546
1547       if(hyphenIndices)
1548       {
1549         while((hyphenIndex < hyphensCount) && (glyphIndex > hyphenIndices[hyphenIndex]))
1550         {
1551           hyphenIndex++;
1552         }
1553
1554         addHyphen = ((hyphenIndex < hyphensCount) && ((glyphIndex + 1) == hyphenIndices[hyphenIndex]));
1555         if(addHyphen)
1556         {
1557           glyphIndex--;
1558         }
1559       }
1560     }
1561
1562     // Draw the underline from the leftmost glyph to the rightmost glyph
1563     if(thereAreUnderlinedGlyphs && style == Typesetter::STYLE_UNDERLINE)
1564     {
1565       DrawUnderline(bufferWidth, bufferHeight, glyphData, baseline, currentUnderlinePosition, maxUnderlineHeight, lineExtentLeft, lineExtentRight, modelUnderlineProperties, currentUnderlineProperties, line);
1566     }
1567
1568     // Draw the background color from the leftmost glyph to the rightmost glyph
1569     if(style == Typesetter::STYLE_BACKGROUND)
1570     {
1571       DrawBackgroundColor(mModel->GetBackgroundColor(), bufferWidth, bufferHeight, glyphData, baseline, line, lineExtentLeft, lineExtentRight);
1572     }
1573
1574     // Draw the strikethrough from the leftmost glyph to the rightmost glyph
1575     if(thereAreStrikethroughGlyphs && style == Typesetter::STYLE_STRIKETHROUGH)
1576     {
1577       //TODO : The currently implemented strikethrough creates a strikethrough on the line level. We need to create different strikethroughs the case of glyphs with different sizes.
1578       strikethroughStartingYPosition = (glyphData.verticalOffset + baseline + currentUnderlinePosition) - ((line.ascender) * HALF); // Since Free Type font doesn't contain the strikethrough-position property, strikethrough position will be calculated by moving the underline position upwards by half the value of the line height.
1579       DrawStrikethrough(bufferWidth, bufferHeight, glyphData, baseline, strikethroughStartingYPosition, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, modelStrikethroughProperties, currentStrikethroughProperties, line);
1580     }
1581
1582     // Increases the vertical offset with the line's descender & line spacing.
1583     glyphData.verticalOffset += static_cast<int32_t>(-line.descender + GetPostOffsetVerticalLineAlignment(line, verLineAlign));
1584   }
1585
1586   return glyphData.bitmapBuffer;
1587 }
1588
1589 Devel::PixelBuffer Typesetter::ApplyUnderlineMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset)
1590 {
1591   // Underline-tags (this is for Markup case)
1592   // Get the underline runs.
1593   const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
1594   Vector<UnderlinedGlyphRun> underlineRuns;
1595   underlineRuns.Resize(numberOfUnderlineRuns);
1596   mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
1597
1598   // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
1599   Vector<UnderlinedGlyphRun>::ConstIterator itGlyphRun    = underlineRuns.Begin();
1600   Vector<UnderlinedGlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
1601   GlyphIndex                                startGlyphIndex, endGlyphIndex;
1602
1603   //The outer loop to iterate on the separated chunks of underlined glyph runs
1604   while(itGlyphRun != endItGlyphRun)
1605   {
1606     startGlyphIndex = itGlyphRun->glyphRun.glyphIndex;
1607     endGlyphIndex   = startGlyphIndex + itGlyphRun->glyphRun.numberOfGlyphs - 1;
1608
1609     // Create the image buffer for underline
1610     Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
1611     // Combine the two buffers
1612     // Result pixel buffer will be stored into topPixelBuffer.
1613     CombineImageBuffer(underlineImageBuffer, topPixelBuffer, bufferWidth, bufferHeight, false);
1614
1615     itGlyphRun++;
1616   }
1617
1618   return topPixelBuffer;
1619 }
1620
1621 Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset)
1622 {
1623   // strikethrough-tags (this is for Markup case)
1624   // Get the strikethrough runs.
1625   const Length                  numberOfStrikethroughRuns = mModel->GetNumberOfStrikethroughRuns();
1626   Vector<StrikethroughGlyphRun> strikethroughRuns;
1627   strikethroughRuns.Resize(numberOfStrikethroughRuns);
1628   mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
1629
1630   // Iterate on the consecutive strikethrough glyph run and connect them into one chunk of strikethrough characters.
1631   Vector<StrikethroughGlyphRun>::ConstIterator itGlyphRun    = strikethroughRuns.Begin();
1632   Vector<StrikethroughGlyphRun>::ConstIterator endItGlyphRun = strikethroughRuns.End();
1633   GlyphIndex                                   startGlyphIndex, endGlyphIndex;
1634
1635   //The outer loop to iterate on the separated chunks of strikethrough glyph runs
1636   while(itGlyphRun != endItGlyphRun)
1637   {
1638     startGlyphIndex = itGlyphRun->glyphRun.glyphIndex;
1639     endGlyphIndex   = startGlyphIndex + itGlyphRun->glyphRun.numberOfGlyphs - 1;
1640
1641     // Create the image buffer for strikethrough
1642     Devel::PixelBuffer strikethroughImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_STRIKETHROUGH, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
1643     // Combine the two buffers
1644     // Result pixel buffer will be stored into topPixelBuffer.
1645     CombineImageBuffer(strikethroughImageBuffer, topPixelBuffer, bufferWidth, bufferHeight, false);
1646
1647     itGlyphRun++;
1648   }
1649
1650   return topPixelBuffer;
1651 }
1652
1653 void Typesetter::SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha)
1654 {
1655   // Assume that we always combine two RGBA images
1656   // Jump with 4bytes for optimize runtime.
1657   uint32_t* topBuffer    = reinterpret_cast<uint32_t*>(topPixelBuffer.GetBuffer());
1658   uint32_t* bottomBuffer = reinterpret_cast<uint32_t*>(bottomPixelBuffer.GetBuffer());
1659
1660   if(topBuffer == NULL || bottomBuffer == NULL)
1661   {
1662     // Nothing to do if one of both buffers are empty.
1663     return;
1664   }
1665
1666   const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
1667
1668   for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex)
1669   {
1670     uint32_t topBufferColor = *(topBuffer);
1671     uint32_t bottomBufferColor = *(bottomBuffer);
1672     uint8_t* __restrict__ topBufferColorBuffer = reinterpret_cast<uint8_t*>(&topBufferColor);
1673     uint8_t* __restrict__ bottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&bottomBufferColor);
1674
1675     // Return the transparency of the text to original.
1676     uint8_t originAlphaInt = originAlpha * 255;
1677
1678     uint8_t topAlpha = topBufferColorBuffer[3];
1679     uint8_t bottomAlpha = 255 - topAlpha;
1680
1681     // Manual blending.
1682     bottomBufferColorBuffer[0] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[0], originAlphaInt, bottomBufferColorBuffer[0], bottomAlpha);
1683     bottomBufferColorBuffer[1] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[1], originAlphaInt, bottomBufferColorBuffer[1], bottomAlpha);
1684     bottomBufferColorBuffer[2] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[2], originAlphaInt, bottomBufferColorBuffer[2], bottomAlpha);
1685     bottomBufferColorBuffer[3] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[3], originAlphaInt, bottomBufferColorBuffer[3], bottomAlpha);
1686
1687     *(bottomBuffer) = bottomBufferColor;
1688
1689     // Increase each buffer's pointer.
1690     ++topBuffer;
1691     ++bottomBuffer;
1692   }
1693 }
1694
1695 Typesetter::Typesetter(const ModelInterface* const model)
1696 : mModel(new ViewModel(model))
1697 {
1698 }
1699
1700 Typesetter::~Typesetter()
1701 {
1702   delete mModel;
1703 }
1704
1705 } // namespace Text
1706
1707 } // namespace Toolkit
1708
1709 } // namespace Dali