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