Merge "Add InterceptKeyEvent" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / text-abstraction / font-client.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/devel-api/text-abstraction/font-client.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/imaging/common/image-operations.h>
23 #include <dali/internal/text/text-abstraction/font-client-impl.h>
24
25 namespace Dali
26 {
27 namespace TextAbstraction
28 {
29 const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE   = 768u;                           // 12*64
30 const float           FontClient::DEFAULT_ITALIC_ANGLE = 12.f * Dali::Math::PI_OVER_180; // FreeType documentation states the software italic is done by doing a horizontal shear of 12 degrees (file ftsynth.h).
31
32 //Default atlas block
33 const bool     FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED = true;
34 const uint32_t FontClient::DEFAULT_TEXT_ATLAS_WIDTH         = 512u;
35 const uint32_t FontClient::DEFAULT_TEXT_ATLAS_HEIGHT        = 512u;
36 const Size     FontClient::DEFAULT_TEXT_ATLAS_SIZE(DEFAULT_TEXT_ATLAS_WIDTH, DEFAULT_TEXT_ATLAS_HEIGHT);
37
38 //Maximum atlas block
39 const uint32_t FontClient::MAX_TEXT_ATLAS_WIDTH  = 1024u;
40 const uint32_t FontClient::MAX_TEXT_ATLAS_HEIGHT = 1024u;
41 const Size     FontClient::MAX_TEXT_ATLAS_SIZE(MAX_TEXT_ATLAS_WIDTH, MAX_TEXT_ATLAS_HEIGHT);
42
43 //MAX_WIDTH_FIT_IN_ATLAS: blockWidth + 2 * DOUBLE_PIXEL_PADDING + 1u <= atlasWidth
44 //MAX_HEIGHT_FIT_IN_ATLAS: blockHeight + 2 * DOUBLE_PIXEL_PADDING + 1u <= atlasHeight
45 const uint16_t FontClient::PADDING_TEXT_ATLAS_BLOCK = 5u; // 2 * DOUBLE_PIXEL_PADDING + 1u
46
47 //Maximum block size to fit into atlas block
48 const Size FontClient::MAX_SIZE_FIT_IN_ATLAS(MAX_TEXT_ATLAS_WIDTH - PADDING_TEXT_ATLAS_BLOCK, MAX_TEXT_ATLAS_HEIGHT - PADDING_TEXT_ATLAS_BLOCK);
49
50 const uint32_t FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE = 64u; //Found this value from toolkit
51
52 // FontClient::GlyphBufferData
53
54 FontClient::GlyphBufferData::GlyphBufferData()
55 : buffer{nullptr},
56   width{0u},
57   height{0u},
58   outlineOffsetX{0},
59   outlineOffsetY{0},
60   format{Pixel::A8},
61   compressType(CompressType::NO_COMPRESS),
62   isColorEmoji{false},
63   isColorBitmap{false},
64   isBufferOwned{false}
65 {
66 }
67
68 FontClient::GlyphBufferData::~GlyphBufferData()
69 {
70   if(isBufferOwned)
71   {
72     free(buffer);
73   }
74 }
75
76 size_t FontClient::GlyphBufferData::Compress(const uint8_t* const __restrict__ inBuffer, GlyphBufferData& __restrict__ outBufferData)
77 {
78   size_t bufferSize                       = 0u;
79   uint8_t*& __restrict__ compressedBuffer = outBufferData.buffer;
80   switch(outBufferData.compressType)
81   {
82     case TextAbstraction::FontClient::GlyphBufferData::CompressType::NO_COMPRESS:
83     {
84       bufferSize = outBufferData.width * outBufferData.height * Pixel::GetBytesPerPixel(outBufferData.format);
85
86       compressedBuffer = (uint8_t*)malloc(bufferSize);
87       if(DALI_UNLIKELY(compressedBuffer == nullptr))
88       {
89         return 0u;
90       }
91       outBufferData.isBufferOwned = true;
92
93       // Copy buffer without compress
94       memcpy(compressedBuffer, inBuffer, bufferSize);
95       break;
96     }
97     case TextAbstraction::FontClient::GlyphBufferData::CompressType::BIT_PER_PIXEL_4:
98     {
99       const uint32_t widthByte       = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
100       const uint32_t componentCount  = (widthByte >> 1);
101       const bool     considerPadding = (widthByte & 1) ? true : false;
102
103       // For BIT_PER_PIXEL_4 type, we can know final compressed buffer size immediatly.
104       bufferSize       = outBufferData.height * (componentCount + (considerPadding ? 1 : 0));
105       compressedBuffer = (uint8_t*)malloc(bufferSize);
106       if(DALI_UNLIKELY(compressedBuffer == nullptr))
107       {
108         return 0u;
109       }
110       outBufferData.isBufferOwned = true;
111
112       uint8_t* __restrict__ outBufferPtr      = compressedBuffer;
113       const uint8_t* __restrict__ inBufferPtr = inBuffer;
114
115       // Compress for each line
116       for(uint32_t y = 0; y < outBufferData.height; ++y)
117       {
118         for(uint32_t x = 0; x < componentCount; ++x)
119         {
120           const uint8_t v0 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
121           const uint8_t v1 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
122
123           *(outBufferPtr++) = (v0 << 4) | v1;
124         }
125         if(considerPadding)
126         {
127           *(outBufferPtr++) = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
128         }
129       }
130       break;
131     }
132     case TextAbstraction::FontClient::GlyphBufferData::CompressType::COMPRESS_RLE4:
133     {
134       const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
135
136       // Allocate temperal buffer. Note that RLE4 can be bigger than original buffer.
137       uint8_t* __restrict__ tempBuffer = (uint8_t*)malloc(outBufferData.height * (widthByte + 1));
138       if(DALI_UNLIKELY(tempBuffer == nullptr))
139       {
140         return 0u;
141       }
142
143       uint8_t* __restrict__ outBufferPtr      = tempBuffer;
144       const uint8_t* __restrict__ inBufferPtr = inBuffer;
145
146       bufferSize = 0u;
147
148       // Compress for each line
149       for(uint32_t y = 0; y < outBufferData.height; ++y)
150       {
151         uint32_t encodedByte = 0;
152         while(encodedByte < widthByte)
153         {
154           // Case 1 : Remain only 1 byte
155           if(DALI_UNLIKELY(encodedByte + 1 == widthByte))
156           {
157             const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
158             const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
159             *(outBufferPtr++)   = v0;
160             ++encodedByte;
161             ++bufferSize;
162           }
163           // Case 2 : Remain only 2 byte
164           else if(DALI_UNLIKELY(encodedByte + 2 == widthByte))
165           {
166             const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
167             const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
168             const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
169             const uint8_t v1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
170             encodedByte += 2;
171             if(v0 == v1)
172             {
173               *(outBufferPtr++) = 0x80 | v0;
174               ++bufferSize;
175             }
176             else
177             {
178               *(outBufferPtr++) = 0x10 | v0;
179               *(outBufferPtr++) = v1 << 4;
180               bufferSize += 2;
181             }
182           }
183           // Case 3 : Normal case. Remain byte bigger or equal than 3.
184           else
185           {
186             // Compress rule -
187             // Read 2 byte as v0 and v1.
188             // - If v0 == v1, We can compress. mark the first bit as 1. and remain 3 bit mark as the "runLength - 2".
189             //   runLength can be maximum 9.
190             // - If v0 != v1, We cannot compress. mark the first bit as 0. and remain 3 bit mark as the "(nonRunLength - 1) / 2"
191             //   Due to the BitPerPixel is 4, nonRunLength should be odd value.
192             //   nonRunLength cutted if v0 == v1.
193             //   nonRunLength can be maximum 15.
194
195             const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
196             const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
197             const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
198             const uint8_t v1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
199             encodedByte += 2;
200             // We can compress by RLE
201             if(v0 == v1)
202             {
203               uint8_t runLength = 2;
204               while(encodedByte < widthByte && runLength < 9)
205               {
206                 const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
207                 const uint8_t v2    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prev2) & 0x0f; // Intented underflow
208                 if(v2 == v0)
209                 {
210                   ++inBufferPtr;
211                   ++encodedByte;
212                   ++runLength;
213                 }
214                 else
215                 {
216                   break;
217                 }
218               }
219
220               // Update (runLength - 2) result.
221               *(outBufferPtr++) = ((0x8 | (runLength - 2)) << 4) | v0;
222               ++bufferSize;
223             }
224             // We cannot compress by RLE.
225             else
226             {
227               // Read one more value.
228               const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
229               const uint8_t v2    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev2) & 0x0f; // Intented underflow
230               ++encodedByte;
231
232               uint8_t  nonRunLength          = 3;
233               uint8_t* nonRunLengthHeaderPtr = outBufferPtr;
234               *(outBufferPtr++)              = v0;
235               *(outBufferPtr++)              = (v1 << 4) | v2;
236               bufferSize += 2;
237               while(encodedByte < widthByte && nonRunLength < 15)
238               {
239                 if(DALI_LIKELY(encodedByte + 1 < widthByte))
240                 {
241                   const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
242                   const uint8_t w0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
243                   const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1 - widthByte));
244                   const uint8_t w1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1)) - prew1) & 0x0f; // Intented underflow
245                   if(w0 == w1)
246                   {
247                     // Stop non-compress logic.
248                     break;
249                   }
250                   else
251                   {
252                     ++bufferSize;
253                     *(outBufferPtr++) = (w0 << 4) | w1;
254                     inBufferPtr += 2;
255                     encodedByte += 2;
256                     nonRunLength += 2;
257                   }
258                 }
259                 else
260                 {
261                   // Edge case. There is only one pixel remained.
262                   const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
263                   const uint8_t w0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
264                   {
265                     ++bufferSize;
266                     *(outBufferPtr++) = (w0 << 4);
267                     ++encodedByte;
268                     ++inBufferPtr;
269                     // Increase nonRunLength 2 even latest value is invalid.
270                     nonRunLength += 2;
271                   }
272                 }
273               }
274
275               // Update (nonRunLength-1)/2 result into header.
276               *(nonRunLengthHeaderPtr) |= (nonRunLength >> 1) << 4;
277             }
278           }
279         }
280       }
281
282       // Allocate and copy data
283       compressedBuffer = (uint8_t*)malloc(bufferSize);
284       if(DALI_UNLIKELY(compressedBuffer == nullptr))
285       {
286         free(tempBuffer);
287         return 0u;
288       }
289       outBufferData.isBufferOwned = true;
290
291       memcpy(compressedBuffer, tempBuffer, bufferSize);
292       free(tempBuffer);
293
294       break;
295     }
296     default:
297     {
298       break;
299     }
300   }
301
302   return bufferSize;
303 }
304
305 void FontClient::GlyphBufferData::Decompress(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer)
306 {
307   if(DALI_UNLIKELY(outBuffer == nullptr))
308   {
309     return;
310   }
311
312   switch(inBufferData.compressType)
313   {
314     case TextAbstraction::FontClient::GlyphBufferData::CompressType::NO_COMPRESS:
315     {
316       const auto bufferSize = inBufferData.width * inBufferData.height * Pixel::GetBytesPerPixel(inBufferData.format);
317
318       // Copy buffer without compress
319       memcpy(outBuffer, inBufferData.buffer, bufferSize);
320       break;
321     }
322     case TextAbstraction::FontClient::GlyphBufferData::CompressType::BIT_PER_PIXEL_4:
323     {
324       const uint32_t widthByte       = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
325       const uint32_t componentCount  = (widthByte >> 1);
326       const bool     considerPadding = (widthByte & 1) ? true : false;
327
328       uint8_t* __restrict__ outBufferPtr      = outBuffer;
329       const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
330
331       // Compress for each line
332       for(uint32_t y = 0; y < inBufferData.height; ++y)
333       {
334         for(uint32_t x = 0; x < componentCount; ++x)
335         {
336           const uint8_t v  = *(inBufferPtr++);
337           const uint8_t v0 = (v >> 4) & 0x0f;
338           const uint8_t v1 = v & 0x0f;
339
340           *(outBufferPtr++) = (v0 << 4) | v0;
341           *(outBufferPtr++) = (v1 << 4) | v1;
342         }
343         if(considerPadding)
344         {
345           const uint8_t v   = *(inBufferPtr++);
346           *(outBufferPtr++) = (v << 4) | v;
347         }
348       }
349       break;
350     }
351     case TextAbstraction::FontClient::GlyphBufferData::CompressType::COMPRESS_RLE4:
352     {
353       const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
354
355       uint8_t* __restrict__ outBufferPtr      = outBuffer;
356       const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
357       // Compress for each line
358       for(uint32_t y = 0; y < inBufferData.height; ++y)
359       {
360         uint32_t x           = 0;
361         uint32_t decodedByte = 0;
362         while(decodedByte < widthByte)
363         {
364           const uint8_t v = *(inBufferPtr++);
365           ++x;
366           // Compress by RLE
367           if(v & 0x80)
368           {
369             const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
370             decodedByte += runLength;
371             const uint8_t repeatValue = v & 0x0f;
372             for(uint8_t iter = 0; iter < runLength; ++iter)
373             {
374               const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
375               const uint8_t v0    = (prev0 + repeatValue) & 0x0f;
376               *(outBufferPtr++)   = (v0 << 4) | v0;
377             }
378           }
379           // Not compress by RLE
380           else
381           {
382             const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
383             decodedByte += nonRunLength;
384             // First value.
385             const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
386             const uint8_t v0    = (prev0 + (v & 0x0f)) & 0x0f;
387             *(outBufferPtr++)   = (v0 << 4) | v0;
388
389             const bool ignoreLastValue = decodedByte > widthByte ? true : false;
390             if(DALI_UNLIKELY(ignoreLastValue))
391             {
392               --decodedByte;
393               for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
394               {
395                 const uint8_t w     = *(inBufferPtr++);
396                 const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
397                 const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
398                 const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
399                 const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
400                 ++x;
401
402                 *(outBufferPtr++) = (w0 << 4) | w0;
403                 *(outBufferPtr++) = (w1 << 4) | w1;
404               }
405               // Last value.
406               {
407                 const uint8_t w     = ((*(inBufferPtr++)) >> 4) & 0x0f;
408                 const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
409                 const uint8_t w0    = (prew0 + w) & 0x0f;
410                 ++x;
411
412                 *(outBufferPtr++) = (w0 << 4) | w0;
413               }
414             }
415             else
416             {
417               for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
418               {
419                 const uint8_t w     = *(inBufferPtr++);
420                 const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
421                 const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
422                 const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
423                 const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
424                 ++x;
425
426                 *(outBufferPtr++) = (w0 << 4) | w0;
427                 *(outBufferPtr++) = (w1 << 4) | w1;
428               }
429             }
430           }
431         }
432       }
433       break;
434     }
435     default:
436     {
437       break;
438     }
439   }
440 }
441
442 void FontClient::GlyphBufferData::DecompressScanline(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer, uint32_t& __restrict__ offset)
443 {
444   switch(inBufferData.compressType)
445   {
446     case TextAbstraction::FontClient::GlyphBufferData::CompressType::NO_COMPRESS:
447     {
448       const auto bufferSize = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
449
450       // Copy buffer without compress
451       memcpy(outBuffer, inBufferData.buffer + offset, bufferSize);
452
453       // Update offset
454       offset += bufferSize;
455       break;
456     }
457     case TextAbstraction::FontClient::GlyphBufferData::CompressType::BIT_PER_PIXEL_4:
458     {
459       const uint32_t widthByte       = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
460       const uint32_t componentCount  = (widthByte >> 1);
461       const bool     considerPadding = (widthByte & 1) ? true : false;
462
463       uint8_t* __restrict__ outBufferPtr      = outBuffer;
464       const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
465
466       // Decompress scanline
467       for(uint32_t x = 0; x < componentCount; ++x)
468       {
469         const uint8_t v  = *(inBufferPtr++);
470         const uint8_t v0 = (v >> 4) & 0x0f;
471         const uint8_t v1 = v & 0x0f;
472
473         *(outBufferPtr++) = (v0 << 4) | v0;
474         *(outBufferPtr++) = (v1 << 4) | v1;
475       }
476       if(considerPadding)
477       {
478         const uint8_t v   = *(inBufferPtr++);
479         *(outBufferPtr++) = (v << 4) | v;
480       }
481
482       // Update offset
483       offset += (widthByte + 1u) >> 1u;
484       break;
485     }
486     case TextAbstraction::FontClient::GlyphBufferData::CompressType::COMPRESS_RLE4:
487     {
488       const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
489
490       uint8_t* __restrict__ outBufferPtr      = outBuffer;
491       const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
492
493       // If offset is zero, fill outBuffer as 0 first.
494       if(DALI_UNLIKELY(offset == 0))
495       {
496         memset(outBufferPtr, 0, widthByte);
497       }
498
499       // Decompress scanline
500       uint32_t decodedByte = 0;
501       while(decodedByte < widthByte)
502       {
503         const uint8_t v = *(inBufferPtr++);
504         ++offset;
505         // Compress by RLE
506         if(v & 0x80)
507         {
508           const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
509           decodedByte += runLength;
510           const uint8_t repeatValue = (v & 0x0f);
511           for(uint8_t iter = 0; iter < runLength; ++iter)
512           {
513             const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
514             const uint8_t v0    = (prev0 + repeatValue) & 0x0f;
515             *(outBufferPtr++)   = (v0 << 4) | v0;
516           }
517         }
518         // Not compress by RLE
519         else
520         {
521           const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
522           decodedByte += nonRunLength;
523           // First value.
524           const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
525           const uint8_t v0    = (prev0 + (v & 0x0f)) & 0x0f;
526           *(outBufferPtr++)   = (v0 << 4) | v0;
527
528           const bool ignoreLastValue = decodedByte > widthByte ? true : false;
529           if(DALI_UNLIKELY(ignoreLastValue))
530           {
531             --decodedByte;
532             for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
533             {
534               const uint8_t w     = *(inBufferPtr++);
535               const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
536               const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
537               const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
538               const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
539               ++offset;
540
541               *(outBufferPtr++) = (w0 << 4) | w0;
542               *(outBufferPtr++) = (w1 << 4) | w1;
543             }
544             // Last value.
545             {
546               const uint8_t w     = ((*(inBufferPtr++)) >> 4) & 0x0f;
547               const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
548               const uint8_t w0    = (prew0 + w) & 0x0f;
549               ++offset;
550
551               *(outBufferPtr++) = (w0 << 4) | w0;
552             }
553           }
554           else
555           {
556             for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
557             {
558               const uint8_t w     = *(inBufferPtr++);
559               const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
560               const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
561               const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
562               const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
563               ++offset;
564
565               *(outBufferPtr++) = (w0 << 4) | w0;
566               *(outBufferPtr++) = (w1 << 4) | w1;
567             }
568           }
569         }
570       }
571       break;
572     }
573     default:
574     {
575       break;
576     }
577   }
578 }
579
580 // FontClient
581
582 FontClient FontClient::Get()
583 {
584   return Internal::FontClient::Get();
585 }
586
587 FontClient::FontClient()
588 {
589 }
590
591 FontClient::~FontClient()
592 {
593 }
594
595 FontClient::FontClient(const FontClient& handle)
596 : BaseHandle(handle)
597 {
598 }
599
600 FontClient& FontClient::operator=(const FontClient& handle)
601 {
602   BaseHandle::operator=(handle);
603   return *this;
604 }
605
606 void FontClient::ClearCache()
607 {
608   GetImplementation(*this).ClearCache();
609 }
610
611 void FontClient::SetDpi(unsigned int horizontalDpi, unsigned int verticalDpi)
612 {
613   GetImplementation(*this).SetDpi(horizontalDpi, verticalDpi);
614 }
615
616 void FontClient::GetDpi(unsigned int& horizontalDpi, unsigned int& verticalDpi)
617 {
618   GetImplementation(*this).GetDpi(horizontalDpi, verticalDpi);
619 }
620
621 int FontClient::GetDefaultFontSize()
622 {
623   return GetImplementation(*this).GetDefaultFontSize();
624 }
625
626 void FontClient::ResetSystemDefaults()
627 {
628   GetImplementation(*this).ResetSystemDefaults();
629 }
630
631 void FontClient::GetDefaultFonts(FontList& defaultFonts)
632 {
633   GetImplementation(*this).GetDefaultFonts(defaultFonts);
634 }
635
636 void FontClient::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
637 {
638   GetImplementation(*this).GetDefaultPlatformFontDescription(fontDescription);
639 }
640
641 void FontClient::GetSystemFonts(FontList& systemFonts)
642 {
643   GetImplementation(*this).GetSystemFonts(systemFonts);
644 }
645
646 void FontClient::GetDescription(FontId id, FontDescription& fontDescription)
647 {
648   GetImplementation(*this).GetDescription(id, fontDescription);
649 }
650
651 PointSize26Dot6 FontClient::GetPointSize(FontId id)
652 {
653   return GetImplementation(*this).GetPointSize(id);
654 }
655
656 bool FontClient::IsCharacterSupportedByFont(FontId fontId, Character character)
657 {
658   return GetImplementation(*this).IsCharacterSupportedByFont(fontId, character);
659 }
660
661 FontId FontClient::FindDefaultFont(Character       charcode,
662                                    PointSize26Dot6 requestedPointSize,
663                                    bool            preferColor)
664 {
665   return GetImplementation(*this).FindDefaultFont(charcode,
666                                                   requestedPointSize,
667                                                   preferColor);
668 }
669
670 FontId FontClient::FindFallbackFont(Character              charcode,
671                                     const FontDescription& preferredFontDescription,
672                                     PointSize26Dot6        requestedPointSize,
673                                     bool                   preferColor)
674 {
675   return GetImplementation(*this).FindFallbackFont(charcode, preferredFontDescription, requestedPointSize, preferColor);
676 }
677
678 FontId FontClient::GetFontId(const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex)
679 {
680   return GetImplementation(*this).GetFontId(path, requestedPointSize, faceIndex);
681 }
682
683 FontId FontClient::GetFontId(const FontDescription& fontDescription,
684                              PointSize26Dot6        requestedPointSize,
685                              FaceIndex              faceIndex)
686 {
687   return GetImplementation(*this).GetFontId(fontDescription,
688                                             requestedPointSize,
689                                             faceIndex);
690 }
691
692 FontId FontClient::GetFontId(const BitmapFont& bitmapFont)
693 {
694   return GetImplementation(*this).GetFontId(bitmapFont);
695 }
696
697 bool FontClient::IsScalable(const FontPath& path)
698 {
699   return GetImplementation(*this).IsScalable(path);
700 }
701
702 bool FontClient::IsScalable(const FontDescription& fontDescription)
703 {
704   return GetImplementation(*this).IsScalable(fontDescription);
705 }
706
707 void FontClient::GetFixedSizes(const FontPath& path, Dali::Vector<PointSize26Dot6>& sizes)
708 {
709   GetImplementation(*this).GetFixedSizes(path, sizes);
710 }
711
712 void FontClient::GetFixedSizes(const FontDescription&         fontDescription,
713                                Dali::Vector<PointSize26Dot6>& sizes)
714 {
715   GetImplementation(*this).GetFixedSizes(fontDescription, sizes);
716 }
717
718 bool FontClient::HasItalicStyle(FontId fontId) const
719 {
720   return GetImplementation(*this).HasItalicStyle(fontId);
721 }
722
723 void FontClient::GetFontMetrics(FontId fontId, FontMetrics& metrics)
724 {
725   GetImplementation(*this).GetFontMetrics(fontId, metrics);
726 }
727
728 GlyphIndex FontClient::GetGlyphIndex(FontId fontId, Character charcode)
729 {
730   return GetImplementation(*this).GetGlyphIndex(fontId, charcode);
731 }
732
733 GlyphIndex FontClient::GetGlyphIndex(FontId fontId, Character charcode, Character variantSelector)
734 {
735   return GetImplementation(*this).GetGlyphIndex(fontId, charcode, variantSelector);
736 }
737
738 bool FontClient::GetGlyphMetrics(GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal)
739 {
740   return GetImplementation(*this).GetGlyphMetrics(array, size, type, horizontal);
741 }
742
743 void FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, GlyphBufferData& data, int outlineWidth)
744 {
745   GetImplementation(*this).CreateBitmap(fontId, glyphIndex, isItalicRequired, isBoldRequired, data, outlineWidth);
746 }
747
748 PixelData FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, int outlineWidth)
749 {
750   return GetImplementation(*this).CreateBitmap(fontId, glyphIndex, outlineWidth);
751 }
752
753 void FontClient::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight)
754 {
755   GetImplementation(*this).CreateVectorBlob(fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight);
756 }
757
758 const GlyphInfo& FontClient::GetEllipsisGlyph(PointSize26Dot6 requestedPointSize)
759 {
760   return GetImplementation(*this).GetEllipsisGlyph(requestedPointSize);
761 }
762
763 bool FontClient::IsColorGlyph(FontId fontId, GlyphIndex glyphIndex)
764 {
765   return GetImplementation(*this).IsColorGlyph(fontId, glyphIndex);
766 }
767
768 bool FontClient::AddCustomFontDirectory(const FontPath& path)
769 {
770   return GetImplementation(*this).AddCustomFontDirectory(path);
771 }
772
773 GlyphIndex FontClient::CreateEmbeddedItem(const EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
774 {
775   return GetImplementation(*this).CreateEmbeddedItem(description, pixelFormat);
776 }
777
778 void FontClient::EnableAtlasLimitation(bool enabled)
779 {
780   return GetImplementation(*this).EnableAtlasLimitation(enabled);
781 }
782
783 bool FontClient::IsAtlasLimitationEnabled() const
784 {
785   return GetImplementation(*this).IsAtlasLimitationEnabled();
786 }
787
788 Size FontClient::GetMaximumTextAtlasSize() const
789 {
790   return GetImplementation(*this).GetMaximumTextAtlasSize();
791 }
792
793 Size FontClient::GetDefaultTextAtlasSize() const
794 {
795   return GetImplementation(*this).GetDefaultTextAtlasSize();
796 }
797
798 Size FontClient::GetCurrentMaximumBlockSizeFitInAtlas() const
799 {
800   return GetImplementation(*this).GetCurrentMaximumBlockSizeFitInAtlas();
801 }
802
803 bool FontClient::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas)
804 {
805   return GetImplementation(*this).SetCurrentMaximumBlockSizeFitInAtlas(currentMaximumBlockSizeFitInAtlas);
806 }
807
808 uint32_t FontClient::GetNumberOfPointsPerOneUnitOfPointSize() const
809 {
810   return GetImplementation(*this).GetNumberOfPointsPerOneUnitOfPointSize();
811 }
812
813 FontClient::FontClient(Internal::FontClient* internal)
814 : BaseHandle(internal)
815 {
816 }
817
818 FontClient FontClientPreInitialize()
819 {
820   return Internal::FontClient::PreInitialize();
821 }
822
823 } // namespace TextAbstraction
824
825 } // namespace Dali