[Text] Add some more trace marker for text
[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_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_BEGIN(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   DALI_TRACE_END(gTraceFilter, "DALI_TEXT_RENDERING_TYPESETTER");
1079
1080   return pixelData;
1081 }
1082
1083 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)
1084 {
1085   // Retrieve lines, glyphs, positions and colors from the view model.
1086   const Length modelNumberOfLines                       = mModel->GetNumberOfLines();
1087   const LineRun* const __restrict__ modelLinesBuffer    = mModel->GetLines();
1088   const GlyphInfo* const __restrict__ glyphsBuffer      = mModel->GetGlyphs();
1089   const Vector2* const __restrict__ positionBuffer      = mModel->GetLayout();
1090   const Vector4* const __restrict__ colorsBuffer        = mModel->GetColors();
1091   const ColorIndex* const __restrict__ colorIndexBuffer = mModel->GetColorIndices();
1092   const GlyphInfo* __restrict__ hyphens                 = mModel->GetHyphens();
1093   const Length* __restrict__ hyphenIndices              = mModel->GetHyphenIndices();
1094   const Length hyphensCount                             = mModel->GetHyphensCount();
1095
1096   // Elided text info. Indices according to elided text and Ellipsis position.
1097   const auto startIndexOfGlyphs              = mModel->GetStartIndexOfElidedGlyphs();
1098   const auto endIndexOfGlyphs                = mModel->GetEndIndexOfElidedGlyphs();
1099   const auto firstMiddleIndexOfElidedGlyphs  = mModel->GetFirstMiddleIndexOfElidedGlyphs();
1100   const auto secondMiddleIndexOfElidedGlyphs = mModel->GetSecondMiddleIndexOfElidedGlyphs();
1101   const auto ellipsisPosition                = mModel->GetEllipsisPosition();
1102
1103   // Whether to use the default color.
1104   const bool     useDefaultColor = (NULL == colorsBuffer);
1105   const Vector4& defaultColor    = mModel->GetDefaultColor();
1106
1107   // Create and initialize the pixel buffer.
1108   GlyphData glyphData;
1109   glyphData.verticalOffset   = verticalOffset;
1110   glyphData.width            = bufferWidth;
1111   glyphData.height           = bufferHeight;
1112   glyphData.bitmapBuffer     = CreateTransparentImageBuffer(bufferWidth, bufferHeight, pixelFormat);
1113   glyphData.horizontalOffset = 0;
1114
1115   // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
1116   TextAbstraction::FontClient fontClient  = TextAbstraction::FontClient::Get();
1117   Length                      hyphenIndex = 0;
1118
1119   const Character* __restrict__ textBuffer                       = mModel->GetTextBuffer();
1120   float calculatedAdvance                                        = 0.f;
1121   const Vector<CharacterIndex>& __restrict__ glyphToCharacterMap = mModel->GetGlyphsToCharacters();
1122   const CharacterIndex* __restrict__ glyphToCharacterMapBuffer   = glyphToCharacterMap.Begin();
1123
1124   const DevelText::VerticalLineAlignment::Type verLineAlign = mModel->GetVerticalLineAlignment();
1125
1126   // Traverses the lines of the text.
1127   for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
1128   {
1129     const LineRun& line = *(modelLinesBuffer + lineIndex);
1130
1131     // Sets the horizontal offset of the line.
1132     glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int32_t>(line.alignmentOffset);
1133     glyphData.horizontalOffset += horizontalOffset;
1134
1135     // Increases the vertical offset with the line's ascender.
1136     glyphData.verticalOffset += static_cast<int32_t>(line.ascender + GetPreOffsetVerticalLineAlignment(line, verLineAlign));
1137
1138     // Retrieves the glyph's outline width
1139     float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
1140
1141     if(style == Typesetter::STYLE_OUTLINE)
1142     {
1143       glyphData.horizontalOffset -= outlineWidth;
1144       if(lineIndex == 0u)
1145       {
1146         // Only need to add the vertical outline offset for the first line
1147         glyphData.verticalOffset -= outlineWidth;
1148       }
1149     }
1150     else if(style == Typesetter::STYLE_SHADOW)
1151     {
1152       const Vector2& shadowOffset = mModel->GetShadowOffset();
1153       glyphData.horizontalOffset += shadowOffset.x - outlineWidth; // if outline enabled then shadow should offset from outline
1154
1155       if(lineIndex == 0u)
1156       {
1157         // Only need to add the vertical shadow offset for first line
1158         glyphData.verticalOffset += shadowOffset.y - outlineWidth;
1159       }
1160     }
1161
1162     const bool  underlineEnabled      = mModel->IsUnderlineEnabled();
1163     const bool  strikethroughEnabled  = mModel->IsStrikethroughEnabled();
1164     const float modelCharacterSpacing = mModel->GetCharacterSpacing();
1165
1166     // Get the character-spacing runs.
1167     const Vector<CharacterSpacingGlyphRun>& __restrict__ characterSpacingGlyphRuns = mModel->GetCharacterSpacingGlyphRuns();
1168
1169     // Aggregate underline-style-properties from mModel
1170     const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
1171                                                             mModel->GetUnderlineColor(),
1172                                                             mModel->GetUnderlineHeight(),
1173                                                             mModel->GetDashedUnderlineGap(),
1174                                                             mModel->GetDashedUnderlineWidth(),
1175                                                             true,
1176                                                             true,
1177                                                             true,
1178                                                             true,
1179                                                             true};
1180
1181     // Aggregate strikethrough-style-properties from mModel
1182     const StrikethroughStyleProperties modelStrikethroughProperties{mModel->GetStrikethroughColor(),
1183                                                                     mModel->GetStrikethroughHeight(),
1184                                                                     true,
1185                                                                     true};
1186
1187     // Get the underline runs.
1188     const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
1189     Vector<UnderlinedGlyphRun> underlineRuns;
1190     underlineRuns.Resize(numberOfUnderlineRuns);
1191     mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
1192
1193     // Get the strikethrough runs.
1194     const Length                  numberOfStrikethroughRuns = mModel->GetNumberOfStrikethroughRuns();
1195     Vector<StrikethroughGlyphRun> strikethroughRuns;
1196     strikethroughRuns.Resize(numberOfStrikethroughRuns);
1197     mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
1198
1199     bool thereAreUnderlinedGlyphs    = false;
1200     bool thereAreStrikethroughGlyphs = false;
1201
1202     float currentUnderlinePosition   = 0.0f;
1203     float currentUnderlineHeight     = modelUnderlineProperties.height;
1204     float maxUnderlineHeight         = currentUnderlineHeight;
1205     auto  currentUnderlineProperties = modelUnderlineProperties;
1206
1207     float currentStrikethroughHeight     = modelStrikethroughProperties.height;
1208     float maxStrikethroughHeight         = currentStrikethroughHeight;
1209     auto  currentStrikethroughProperties = modelStrikethroughProperties;
1210     float strikethroughStartingYPosition = 0.0f;
1211
1212     FontId lastFontId = 0;
1213
1214     float lineExtentLeft  = bufferWidth;
1215     float lineExtentRight = 0.0f;
1216     float baseline        = 0.0f;
1217     bool  addHyphen       = false;
1218
1219     // Traverses the glyphs of the line.
1220     const GlyphIndex startGlyphIndex = std::max(std::max(line.glyphRun.glyphIndex, startIndexOfGlyphs), fromGlyphIndex);
1221     GlyphIndex       endGlyphIndex   = (line.isSplitToTwoHalves ? line.glyphRunSecondHalf.glyphIndex + line.glyphRunSecondHalf.numberOfGlyphs : line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs) - 1u;
1222     endGlyphIndex                    = std::min(std::min(endGlyphIndex, endIndexOfGlyphs), toGlyphIndex);
1223
1224     for(GlyphIndex glyphIndex = startGlyphIndex; glyphIndex <= endGlyphIndex; ++glyphIndex)
1225     {
1226       //To handle START case of ellipsis, the first glyph has been shifted
1227       //glyphIndex represent indices in whole glyphs but elidedGlyphIndex represents indices in elided Glyphs
1228       GlyphIndex elidedGlyphIndex = glyphIndex - startIndexOfGlyphs;
1229
1230       //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.
1231       if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
1232       {
1233         if(glyphIndex > firstMiddleIndexOfElidedGlyphs &&
1234            glyphIndex < secondMiddleIndexOfElidedGlyphs)
1235         {
1236           // Ignore any glyph that removed for MIDDLE ellipsis
1237           continue;
1238         }
1239         if(glyphIndex >= secondMiddleIndexOfElidedGlyphs)
1240         {
1241           elidedGlyphIndex -= (secondMiddleIndexOfElidedGlyphs - firstMiddleIndexOfElidedGlyphs - 1u);
1242         }
1243       }
1244
1245       // Retrieve the glyph's info.
1246       const GlyphInfo* glyphInfo;
1247
1248       if(addHyphen && hyphens)
1249       {
1250         glyphInfo = hyphens + hyphenIndex;
1251         hyphenIndex++;
1252       }
1253       else
1254       {
1255         glyphInfo = glyphsBuffer + elidedGlyphIndex;
1256       }
1257
1258       if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
1259          (glyphInfo->height < Math::MACHINE_EPSILON_1000))
1260       {
1261         // Nothing to do if the glyph's width or height is zero.
1262         continue;
1263       }
1264
1265       Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt = underlineRuns.End();
1266       const bool                                underlineGlyph              = underlineEnabled || IsGlyphUnderlined(glyphIndex, underlineRuns, currentUnderlinedGlyphRunIt);
1267       currentUnderlineProperties                                            = GetCurrentUnderlineProperties(glyphIndex, underlineGlyph, underlineRuns, currentUnderlinedGlyphRunIt, modelUnderlineProperties);
1268       currentUnderlineHeight                                                = currentUnderlineProperties.height;
1269       thereAreUnderlinedGlyphs                                              = thereAreUnderlinedGlyphs || underlineGlyph;
1270
1271       Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End();
1272       const bool                                   strikethroughGlyph             = strikethroughEnabled || IsGlyphStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughGlyphRunIt);
1273       currentStrikethroughProperties                                              = GetCurrentStrikethroughProperties(glyphIndex, strikethroughGlyph, strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties);
1274       currentStrikethroughHeight                                                  = currentStrikethroughProperties.height;
1275       thereAreStrikethroughGlyphs                                                 = thereAreStrikethroughGlyphs || strikethroughGlyph;
1276
1277       // Are we still using the same fontId as previous
1278       if((glyphInfo->fontId != lastFontId) && (strikethroughGlyph || underlineGlyph))
1279       {
1280         // We need to fetch fresh font underline metrics
1281         FontMetrics fontMetrics;
1282         fontClient.GetFontMetrics(glyphInfo->fontId, fontMetrics);
1283
1284         //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
1285         currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(fontMetrics);
1286
1287         if(underlineGlyph)
1288         {
1289           CalcualteUnderlineHeight(fontMetrics, currentUnderlineHeight, maxUnderlineHeight);
1290         }
1291
1292         if(strikethroughGlyph)
1293         {
1294           CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight);
1295         }
1296
1297         // Update lastFontId because fontId is changed
1298         lastFontId = glyphInfo->fontId; // Prevents searching for existing blocksizes when string of the same fontId.
1299       }
1300
1301       // Retrieves the glyph's position.
1302       Vector2 position = *(positionBuffer + elidedGlyphIndex);
1303
1304       if(addHyphen)
1305       {
1306         GlyphInfo   tempInfo         = *(glyphsBuffer + elidedGlyphIndex);
1307         const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
1308         calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + elidedGlyphIndex))), characterSpacing, tempInfo.advance);
1309         position.x                   = position.x + calculatedAdvance - tempInfo.xBearing + glyphInfo->xBearing;
1310         position.y                   = -glyphInfo->yBearing;
1311       }
1312
1313       if(baseline < position.y + glyphInfo->yBearing)
1314       {
1315         baseline = position.y + glyphInfo->yBearing;
1316       }
1317
1318       // Calculate the positions of leftmost and rightmost glyphs in the current line
1319       if(position.x < lineExtentLeft)
1320       {
1321         lineExtentLeft = position.x;
1322       }
1323
1324       if(position.x + glyphInfo->width > lineExtentRight)
1325       {
1326         lineExtentRight = position.x + glyphInfo->width;
1327       }
1328
1329       // Retrieves the glyph's color.
1330       const ColorIndex colorIndex = useDefaultColor ? 0u : *(colorIndexBuffer + glyphIndex);
1331
1332       Vector4 color;
1333       if(style == Typesetter::STYLE_SHADOW)
1334       {
1335         color = mModel->GetShadowColor();
1336       }
1337       else if(style == Typesetter::STYLE_OUTLINE)
1338       {
1339         color = mModel->GetOutlineColor();
1340       }
1341       else
1342       {
1343         color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + (colorIndex - 1u));
1344       }
1345
1346       // Premultiply alpha
1347       color.r *= color.a;
1348       color.g *= color.a;
1349       color.b *= color.a;
1350
1351       // Retrieves the glyph's bitmap.
1352       glyphData.glyphBitmap.buffer = NULL;
1353       glyphData.glyphBitmap.width  = glyphInfo->width; // Desired width and height.
1354       glyphData.glyphBitmap.height = glyphInfo->height;
1355
1356       if(style != Typesetter::STYLE_OUTLINE && style != Typesetter::STYLE_SHADOW)
1357       {
1358         // Don't render outline for other styles
1359         outlineWidth = 0.0f;
1360       }
1361
1362       if(style != Typesetter::STYLE_UNDERLINE && style != Typesetter::STYLE_STRIKETHROUGH)
1363       {
1364         fontClient.CreateBitmap(glyphInfo->fontId,
1365                                 glyphInfo->index,
1366                                 glyphInfo->isItalicRequired,
1367                                 glyphInfo->isBoldRequired,
1368                                 glyphData.glyphBitmap,
1369                                 static_cast<int32_t>(outlineWidth));
1370       }
1371
1372       // Sets the glyph's bitmap into the bitmap of the whole text.
1373       if(NULL != glyphData.glyphBitmap.buffer)
1374       {
1375         if(style == Typesetter::STYLE_OUTLINE)
1376         {
1377           // Set the position offset for the current glyph
1378           glyphData.horizontalOffset -= glyphData.glyphBitmap.outlineOffsetX;
1379           glyphData.verticalOffset -= glyphData.glyphBitmap.outlineOffsetY;
1380         }
1381
1382         // Set the buffer of the glyph's bitmap into the final bitmap's buffer
1383         TypesetGlyph(glyphData,
1384                      &position,
1385                      &color,
1386                      style,
1387                      pixelFormat);
1388
1389         if(style == Typesetter::STYLE_OUTLINE)
1390         {
1391           // Reset the position offset for the next glyph
1392           glyphData.horizontalOffset += glyphData.glyphBitmap.outlineOffsetX;
1393           glyphData.verticalOffset += glyphData.glyphBitmap.outlineOffsetY;
1394         }
1395
1396         // free the glyphBitmap.buffer if it is owner of buffer
1397         if(glyphData.glyphBitmap.isBufferOwned)
1398         {
1399           free(glyphData.glyphBitmap.buffer);
1400           glyphData.glyphBitmap.isBufferOwned = false;
1401         }
1402         glyphData.glyphBitmap.buffer = NULL;
1403       }
1404
1405       if(hyphenIndices)
1406       {
1407         while((hyphenIndex < hyphensCount) && (glyphIndex > hyphenIndices[hyphenIndex]))
1408         {
1409           hyphenIndex++;
1410         }
1411
1412         addHyphen = ((hyphenIndex < hyphensCount) && ((glyphIndex + 1) == hyphenIndices[hyphenIndex]));
1413         if(addHyphen)
1414         {
1415           glyphIndex--;
1416         }
1417       }
1418     }
1419
1420     // Draw the underline from the leftmost glyph to the rightmost glyph
1421     if(thereAreUnderlinedGlyphs && style == Typesetter::STYLE_UNDERLINE)
1422     {
1423       DrawUnderline(bufferWidth, bufferHeight, glyphData, baseline, currentUnderlinePosition, maxUnderlineHeight, lineExtentLeft, lineExtentRight, modelUnderlineProperties, currentUnderlineProperties, line);
1424     }
1425
1426     // Draw the background color from the leftmost glyph to the rightmost glyph
1427     if(style == Typesetter::STYLE_BACKGROUND)
1428     {
1429       DrawBackgroundColor(mModel->GetBackgroundColor(), bufferWidth, bufferHeight, glyphData, baseline, line, lineExtentLeft, lineExtentRight);
1430     }
1431
1432     // Draw the strikethrough from the leftmost glyph to the rightmost glyph
1433     if(thereAreStrikethroughGlyphs && style == Typesetter::STYLE_STRIKETHROUGH)
1434     {
1435       //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.
1436       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.
1437       DrawStrikethrough(bufferWidth, bufferHeight, glyphData, baseline, strikethroughStartingYPosition, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, modelStrikethroughProperties, currentStrikethroughProperties, line);
1438     }
1439
1440     // Increases the vertical offset with the line's descender & line spacing.
1441     glyphData.verticalOffset += static_cast<int32_t>(-line.descender + GetPostOffsetVerticalLineAlignment(line, verLineAlign));
1442   }
1443
1444   return glyphData.bitmapBuffer;
1445 }
1446
1447 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)
1448 {
1449   // Underline-tags (this is for Markup case)
1450   // Get the underline runs.
1451   const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
1452   Vector<UnderlinedGlyphRun> underlineRuns;
1453   underlineRuns.Resize(numberOfUnderlineRuns);
1454   mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
1455
1456   // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
1457   Vector<UnderlinedGlyphRun>::ConstIterator itGlyphRun    = underlineRuns.Begin();
1458   Vector<UnderlinedGlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
1459   GlyphIndex                                startGlyphIndex, endGlyphIndex;
1460
1461   //The outer loop to iterate on the separated chunks of underlined glyph runs
1462   while(itGlyphRun != endItGlyphRun)
1463   {
1464     startGlyphIndex = itGlyphRun->glyphRun.glyphIndex;
1465     endGlyphIndex   = startGlyphIndex + itGlyphRun->glyphRun.numberOfGlyphs - 1;
1466
1467     // Create the image buffer for underline
1468     Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
1469     // Combine the two buffers
1470     // Result pixel buffer will be stored into topPixelBuffer.
1471     CombineImageBuffer(underlineImageBuffer, topPixelBuffer, bufferWidth, bufferHeight, false);
1472
1473     itGlyphRun++;
1474   }
1475
1476   return topPixelBuffer;
1477 }
1478
1479 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)
1480 {
1481   // strikethrough-tags (this is for Markup case)
1482   // Get the strikethrough runs.
1483   const Length                  numberOfStrikethroughRuns = mModel->GetNumberOfStrikethroughRuns();
1484   Vector<StrikethroughGlyphRun> strikethroughRuns;
1485   strikethroughRuns.Resize(numberOfStrikethroughRuns);
1486   mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
1487
1488   // Iterate on the consecutive strikethrough glyph run and connect them into one chunk of strikethrough characters.
1489   Vector<StrikethroughGlyphRun>::ConstIterator itGlyphRun    = strikethroughRuns.Begin();
1490   Vector<StrikethroughGlyphRun>::ConstIterator endItGlyphRun = strikethroughRuns.End();
1491   GlyphIndex                                   startGlyphIndex, endGlyphIndex;
1492
1493   //The outer loop to iterate on the separated chunks of strikethrough glyph runs
1494   while(itGlyphRun != endItGlyphRun)
1495   {
1496     startGlyphIndex = itGlyphRun->glyphRun.glyphIndex;
1497     endGlyphIndex   = startGlyphIndex + itGlyphRun->glyphRun.numberOfGlyphs - 1;
1498
1499     // Create the image buffer for strikethrough
1500     Devel::PixelBuffer strikethroughImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_STRIKETHROUGH, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
1501     // Combine the two buffers
1502     // Result pixel buffer will be stored into topPixelBuffer.
1503     CombineImageBuffer(strikethroughImageBuffer, topPixelBuffer, bufferWidth, bufferHeight, false);
1504
1505     itGlyphRun++;
1506   }
1507
1508   return topPixelBuffer;
1509 }
1510
1511 Typesetter::Typesetter(const ModelInterface* const model)
1512 : mModel(new ViewModel(model))
1513 {
1514 }
1515
1516 Typesetter::~Typesetter()
1517 {
1518   delete mModel;
1519 }
1520
1521 } // namespace Text
1522
1523 } // namespace Toolkit
1524
1525 } // namespace Dali