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