Moved font client plugin to new folder
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / text-abstraction / plugin / font-client-utils.cpp
1 /*
2  * Copyright (c) 2021 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 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
18
19 #include <dali/integration-api/debug.h>
20 #include <dali/internal/imaging/common/image-operations.h>
21
22 #include <memory>
23
24 extern Dali::Integration::Log::Filter* gFontClientLogFilter;
25
26 namespace Dali::TextAbstraction::Internal
27 {
28 namespace
29 {
30 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
31
32 // NONE            -1  --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
33 // ULTRA_CONDENSED 50
34 // EXTRA_CONDENSED 63
35 // CONDENSED       75
36 // SEMI_CONDENSED  87
37 // NORMAL         100
38 // SEMI_EXPANDED  113
39 // EXPANDED       125
40 // EXTRA_EXPANDED 150
41 // ULTRA_EXPANDED 200
42 const int          FONT_WIDTH_TYPE_TO_INT[] = {-1, 50, 63, 75, 87, 100, 113, 125, 150, 200};
43 const unsigned int NUM_FONT_WIDTH_TYPE      = sizeof(FONT_WIDTH_TYPE_TO_INT) / sizeof(int);
44
45 // NONE                       -1  --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
46 // THIN                        0
47 // ULTRA_LIGHT, EXTRA_LIGHT   40
48 // LIGHT                      50
49 // DEMI_LIGHT, SEMI_LIGHT     55
50 // BOOK                       75
51 // NORMAL, REGULAR            80
52 // MEDIUM                    100
53 // DEMI_BOLD, SEMI_BOLD      180
54 // BOLD                      200
55 // ULTRA_BOLD, EXTRA_BOLD    205
56 // BLACK, HEAVY, EXTRA_BLACK 210
57 const int          FONT_WEIGHT_TYPE_TO_INT[] = {-1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210};
58 const unsigned int NUM_FONT_WEIGHT_TYPE      = sizeof(FONT_WEIGHT_TYPE_TO_INT) / sizeof(int);
59
60 // NONE             -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
61 // NORMAL, ROMAN     0
62 // ITALIC          100
63 // OBLIQUE         110
64 const int          FONT_SLANT_TYPE_TO_INT[] = {-1, 0, 100, 110};
65 const unsigned int NUM_FONT_SLANT_TYPE      = sizeof(FONT_SLANT_TYPE_TO_INT) / sizeof(int);
66
67 } // namespace
68
69 /**
70  * @brief Returns the FontWidth's enum index for the given width value.
71  *
72  * @param[in] width The width value.
73  *
74  * @return The FontWidth's enum index.
75  */
76 const FontWidth::Type IntToWidthType(int width)
77 {
78   return static_cast<FontWidth::Type>(ValueToIndex(width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u));
79 }
80
81 /**
82  * @brief Returns the FontWeight's enum index for the given weight value.
83  *
84  * @param[in] weight The weight value.
85  *
86  * @return The FontWeight's enum index.
87  */
88 const FontWeight::Type IntToWeightType(int weight)
89 {
90   return static_cast<FontWeight::Type>(ValueToIndex(weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u));
91 }
92
93 /**
94  * @brief Returns the FontSlant's enum index for the given slant value.
95  *
96  * @param[in] slant The slant value.
97  *
98  * @return The FontSlant's enum index.
99  */
100 const FontSlant::Type IntToSlantType(int slant)
101 {
102   return static_cast<FontSlant::Type>(ValueToIndex(slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u));
103 }
104
105 const int DEFAULT_FONT_WIDTH(100);
106 const int DEFAULT_FONT_WEIGHT(80);
107 const int DEFAULT_FONT_SLANT(0);
108
109 const FontWidth::Type DefaultFontWidth()
110 {
111   return IntToWidthType(DEFAULT_FONT_WIDTH);
112 }
113 const FontWeight::Type DefaultFontWeight()
114 {
115   return IntToWeightType(DEFAULT_FONT_WEIGHT);
116 }
117 const FontSlant::Type DefaultFontSlant()
118 {
119   return IntToSlantType(DEFAULT_FONT_SLANT);
120 }
121
122 /**
123  * @brief Copy the color bitmap given in @p srcBuffer to @p data.
124  *
125  * @param[out] data The bitmap data.
126  * @param[in] srcWidth The width of the bitmap.
127  * @param[in] srcHeight The height of the bitmap.
128  * @param[in] srcBuffer The buffer of the bitmap.
129  */
130 void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer)
131 {
132   // Set the input dimensions.
133   const ImageDimensions inputDimensions(srcWidth, srcHeight);
134
135   // Set the output dimensions.
136   // If the output dimension is not given, the input dimension is set
137   // and won't be downscaling.
138   data.width  = (data.width == 0) ? srcWidth : data.width;
139   data.height = (data.height == 0) ? srcHeight : data.height;
140   const ImageDimensions desiredDimensions(data.width, data.height);
141
142   // Creates the output buffer
143   const unsigned int bufferSize = data.width * data.height * 4u;
144   data.buffer                   = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
145
146   if(inputDimensions == desiredDimensions)
147   {
148     // There isn't downscaling.
149     memcpy(data.buffer, srcBuffer, bufferSize);
150   }
151   else
152   {
153     Dali::Internal::Platform::LanczosSample4BPP(srcBuffer,
154                                                 inputDimensions,
155                                                 data.buffer,
156                                                 desiredDimensions);
157   }
158 }
159
160 /**
161  * @brief Copy the FreeType bitmap to the given buffer.
162  *
163  * @param[out] data The bitmap data.
164  * @param[in] srcBitmap The FreeType bitmap.
165  * @param[in] isShearRequired Whether the bitmap needs a shear transform (for software italics).
166  */
167 void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired)
168 {
169   if(srcBitmap.width * srcBitmap.rows > 0)
170   {
171     switch(srcBitmap.pixel_mode)
172     {
173       case FT_PIXEL_MODE_GRAY:
174       {
175         if(srcBitmap.pitch == static_cast<int>(srcBitmap.width))
176         {
177           uint8_t*     pixelsIn = srcBitmap.buffer;
178           unsigned int width    = srcBitmap.width;
179           unsigned     height   = srcBitmap.rows;
180
181           std::unique_ptr<uint8_t, void (*)(void*)> pixelsOutPtr(nullptr, free);
182
183           if(isShearRequired)
184           {
185             /**
186              * Glyphs' bitmaps with no slant retrieved from FreeType:
187              * __________     ____
188              * |XXXXXXXX|     |XX|
189              * |   XX   |     |XX|
190              * |   XX   |     |XX|
191              * |   XX   |     |XX|
192              * |   XX   |     |XX|
193              * |   XX   |     |XX|
194              * ----------     ----
195              *
196              * Expected glyphs' bitmaps with italic slant:
197              * ____________   ______
198              * |  XXXXXXXX|   |  XX|
199              * |     XX   |   |  XX|
200              * |    XX    |   | XX |
201              * |    XX    |   | XX |
202              * |   XX     |   |XX  |
203              * |   XX     |   |XX  |
204              * ------------   ------
205              *
206              * Glyphs' bitmaps with software italic slant retrieved from FreeType:
207              * __________     ______
208              * |XXXXXXXX|     |  XX|
209              * |   XX   |     |  XX|
210              * |  XX    |     | XX |
211              * |  XX    |     | XX |
212              * | XX     |     |XX  |
213              * | XX     |     |XX  |
214              * ----------     ------
215              *
216              * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
217              */
218             unsigned int widthOut  = 0u;
219             unsigned int heightOut = 0u;
220             uint8_t*     pixelsOut = nullptr;
221
222             Dali::Internal::Platform::HorizontalShear(pixelsIn,
223                                                       width,
224                                                       height,
225                                                       1u,
226                                                       -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
227                                                       pixelsOut,
228                                                       widthOut,
229                                                       heightOut);
230
231             width    = widthOut;
232             height   = heightOut;
233             pixelsIn = pixelsOut;
234             pixelsOutPtr.reset(pixelsOut);
235           }
236
237           const unsigned int bufferSize = width * height;
238           data.buffer                   = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
239           data.width                    = width;
240           data.height                   = height;
241           data.format                   = Pixel::L8; // Sets the pixel format.
242           memcpy(data.buffer, pixelsIn, bufferSize);
243         }
244         break;
245       }
246
247 #ifdef FREETYPE_BITMAP_SUPPORT
248       case FT_PIXEL_MODE_BGRA:
249       {
250         if(srcBitmap.pitch == static_cast<int>(srcBitmap.width << 2u))
251         {
252           ConvertBitmap(data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer);
253
254           // Sets the pixel format.
255           data.format = Pixel::BGRA8888;
256         }
257         break;
258       }
259 #endif
260       default:
261       {
262         DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n");
263         break;
264       }
265     }
266   }
267 }
268
269 FcPattern* CreateFontFamilyPattern(const FontDescription& fontDescription)
270 {
271   // create the cached font family lookup pattern
272   // a pattern holds a set of names, each name refers to a property of the font
273   FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
274
275   if(!fontFamilyPattern)
276   {
277     return nullptr;
278   }
279
280   // add a property to the pattern for the font family
281   FcPatternAddString(fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fontDescription.family.c_str()));
282
283   // add a property to the pattern for local setting.
284   const char* locale = setlocale(LC_MESSAGES, nullptr);
285   if(locale != nullptr)
286   {
287     FcPatternAddString(fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>(locale));
288   }
289
290   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
291   if(width < 0)
292   {
293     // Use default.
294     width = DEFAULT_FONT_WIDTH;
295   }
296
297   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
298   if(weight < 0)
299   {
300     // Use default.
301     weight = DEFAULT_FONT_WEIGHT;
302   }
303
304   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
305   if(slant < 0)
306   {
307     // Use default.
308     slant = DEFAULT_FONT_SLANT;
309   }
310
311   FcPatternAddInteger(fontFamilyPattern, FC_WIDTH, width);
312   FcPatternAddInteger(fontFamilyPattern, FC_WEIGHT, weight);
313   FcPatternAddInteger(fontFamilyPattern, FC_SLANT, slant);
314
315   // modify the config, with the mFontFamilyPatterm
316   FcConfigSubstitute(nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern);
317
318   // provide default values for unspecified properties in the font pattern
319   // e.g. patterns without a specified style or weight are set to Medium
320   FcDefaultSubstitute(fontFamilyPattern);
321
322   return fontFamilyPattern;
323 }
324
325 FcCharSet* CreateCharacterSetFromDescription(const FontDescription& description)
326 {
327   FcCharSet* characterSet = nullptr;
328
329   FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
330
331   if(nullptr != pattern)
332   {
333     FcResult   result = FcResultMatch;
334     FcPattern* match  = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
335
336     FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
337
338     // Destroys the created patterns.
339     FcPatternDestroy(match);
340     FcPatternDestroy(pattern);
341   }
342
343   return characterSet;
344 }
345
346 } // namespace Dali::TextAbstraction::Internal