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