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