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