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