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