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