Updated all code to new format
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / ubuntu / vector-font-cache.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
18 // CLASS HEADER
19 #include <third-party/glyphy/vector-font-cache.h>
20
21 // EXTERNAL INCLUDES
22 #include <math.h>
23 #include <vector>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/text/glyphy/glyphy-freetype.h>
27 #include <dali/internal/text/glyphy/glyphy.h>
28
29 using namespace std;
30
31 namespace
32 {
33 const unsigned int INITIAL_GLYPH_CAPACITY = 50;
34 const double       MIN_FONT_SIZE          = 10;
35
36 static glyphy_bool_t
37 accumulate_endpoint(glyphy_arc_endpoint_t*         endpoint,
38                     vector<glyphy_arc_endpoint_t>* endpoints)
39 {
40   endpoints->push_back(*endpoint);
41   return true;
42 }
43
44 } // unnamed namespace
45
46 namespace Dali
47 {
48 namespace TextAbstraction
49 {
50 namespace Internal
51 {
52 typedef vector<VectorBlob> BlobArray;
53
54 struct VectorGlyph
55 {
56   /**
57    * @brief Create a vector-based glyph.
58    */
59   static VectorGlyph* New(FT_Face                   face,
60                           FontId                    fontId,
61                           GlyphIndex                index,
62                           glyphy_arc_accumulator_t* accumulator)
63   {
64     VectorGlyph* newGlyph = new VectorGlyph();
65     newGlyph->blobData.resize(1024 * 16);
66
67     if(FT_Err_Ok != FT_Load_Glyph(face,
68                                   index,
69                                   FT_LOAD_NO_BITMAP |
70                                     FT_LOAD_NO_HINTING |
71                                     FT_LOAD_NO_AUTOHINT |
72                                     FT_LOAD_NO_SCALE |
73                                     FT_LOAD_LINEAR_DESIGN |
74                                     FT_LOAD_IGNORE_TRANSFORM))
75     {
76       DALI_LOG_ERROR("FT_Load_Glyph failed\n");
77       delete newGlyph;
78       return NULL;
79     }
80
81     const double upem      = static_cast<double>(face->units_per_EM);
82     const double tolerance = upem * 1.0f / 2048.0f;
83
84     glyphy_arc_accumulator_reset(accumulator);
85     glyphy_arc_accumulator_set_tolerance(accumulator, tolerance);
86
87     vector<glyphy_arc_endpoint_t> endpoints;
88     glyphy_arc_accumulator_set_callback(accumulator,
89                                         reinterpret_cast<glyphy_arc_endpoint_accumulator_callback_t>(accumulate_endpoint),
90                                         &endpoints);
91
92     if(FT_Err_Ok != glyphy_freetype_outline_decompose(&face->glyph->outline, accumulator))
93     {
94       DALI_LOG_ERROR("glyphy_freetype_outline_decompose failed\n");
95       delete newGlyph;
96       return NULL;
97     }
98
99     DALI_ASSERT_DEBUG(glyphy_arc_accumulator_get_error(accumulator) <= tolerance && "glyphy_arc_accumulator_get_error > tolerance");
100
101     if(endpoints.size())
102     {
103       glyphy_outline_winding_from_even_odd(&endpoints[0], endpoints.size(), false);
104     }
105
106     unsigned int blobLength(0);
107     double       averageFetchAchieved(0.0);
108     if(!glyphy_arc_list_encode_blob(endpoints.size() ? &endpoints[0] : NULL,
109                                     endpoints.size(),
110                                     &newGlyph->blobData[0],
111                                     newGlyph->blobData.capacity(),
112                                     upem / (MIN_FONT_SIZE * M_SQRT2),
113                                     4,
114                                     &averageFetchAchieved,
115                                     &blobLength,
116                                     &newGlyph->nominalWidth,
117                                     &newGlyph->nominalHeight,
118                                     &newGlyph->extents))
119     {
120       DALI_LOG_ERROR("glyphy_arc_list_encode_blob failed\n");
121       delete newGlyph;
122       return NULL;
123     }
124     newGlyph->blobData.resize(blobLength);
125
126     glyphy_extents_scale(&newGlyph->extents, 1.0 / upem, 1.0 / upem);
127
128     newGlyph->glyphInfo.fontId = fontId;
129     newGlyph->glyphInfo.index  = index;
130
131     if(glyphy_extents_is_empty(&newGlyph->extents))
132     {
133       newGlyph->glyphInfo.width  = 0.0f;
134       newGlyph->glyphInfo.height = 0.0f;
135
136       newGlyph->glyphInfo.xBearing = 0.0f;
137       newGlyph->glyphInfo.yBearing = 0.0f;
138     }
139     else
140     {
141       newGlyph->glyphInfo.width  = (newGlyph->extents.max_x - newGlyph->extents.min_x);
142       newGlyph->glyphInfo.height = (newGlyph->extents.max_y - newGlyph->extents.min_y);
143
144       newGlyph->glyphInfo.xBearing = newGlyph->extents.min_x;
145       newGlyph->glyphInfo.yBearing = newGlyph->glyphInfo.height + (newGlyph->extents.min_y);
146     }
147
148     newGlyph->glyphInfo.advance     = face->glyph->metrics.horiAdvance / upem;
149     newGlyph->glyphInfo.scaleFactor = 0.0f;
150
151     return newGlyph;
152   }
153
154   VectorGlyph()
155   : advance(0.0),
156     nominalWidth(0),
157     nominalHeight(0),
158     glyphInfo(),
159     blobData()
160   {
161     glyphy_extents_clear(&extents);
162   }
163
164   glyphy_extents_t extents;
165   double           advance;
166   unsigned int     nominalWidth;
167   unsigned int     nominalHeight;
168   GlyphInfo        glyphInfo;
169   BlobArray        blobData;
170 };
171
172 typedef vector<VectorGlyph*> GlyphCache;
173
174 struct VectorFont
175 {
176   VectorFont(FT_Face face)
177   : mFace(face),
178     mGlyphCache()
179   {
180     mGlyphCache.reserve(INITIAL_GLYPH_CAPACITY);
181   }
182
183   FT_Face    mFace;
184   GlyphCache mGlyphCache;
185 };
186
187 struct VectorFontCache::Impl
188 {
189   Impl(FT_Library freeTypeLibrary)
190   : mFreeTypeLibrary(freeTypeLibrary),
191     mIdLookup(),
192     mVectorFonts(),
193     mAccumulator(NULL)
194   {
195     mAccumulator = glyphy_arc_accumulator_create();
196   }
197
198   ~Impl()
199   {
200     glyphy_arc_accumulator_destroy(mAccumulator);
201   }
202
203 private:
204   // Declared private and left undefined to avoid copies.
205   Impl(const Impl&);
206   // Declared private and left undefined to avoid copies.
207   Impl& operator=(const Impl&);
208
209 public:
210   FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
211
212   vector<string> mIdLookup;
213
214   vector<VectorFont*> mVectorFonts;
215
216   glyphy_arc_accumulator_t* mAccumulator;
217 };
218
219 VectorFontCache::VectorFontCache(FT_Library freeTypeLibrary)
220 : mImpl(NULL)
221 {
222   mImpl = new Impl(freeTypeLibrary);
223 }
224
225 VectorFontCache::~VectorFontCache()
226 {
227   delete mImpl;
228 }
229
230 FontId VectorFontCache::GetFontId(const std::string& url)
231 {
232   FontId id(0);
233
234   if(mImpl)
235   {
236     if(!FindFont(url, id))
237     {
238       id = CreateFont(url);
239     }
240   }
241
242   return id;
243 }
244
245 void VectorFontCache::GetGlyphMetrics(FontId vectorFontId, GlyphInfo& glyphInfo)
246 {
247   if(mImpl)
248   {
249     if(vectorFontId > 0 &&
250        vectorFontId - 1 < mImpl->mVectorFonts.size())
251     {
252       VectorFont* font  = mImpl->mVectorFonts[vectorFontId - 1];
253       GlyphCache& cache = font->mGlyphCache;
254
255       bool         foundGlyph(false);
256       unsigned int foundIndex(0);
257       for(unsigned int i = 0; i < cache.size(); ++i)
258       {
259         VectorGlyph* glyph = cache[i];
260
261         if(glyph->glyphInfo.index == glyphInfo.index)
262         {
263           foundIndex = i;
264           foundGlyph = true;
265           break;
266         }
267       }
268
269       if(foundGlyph)
270       {
271         VectorGlyph* glyph = cache[foundIndex];
272         // Note - this clobbers the original fontId, but helps avoid duplicating identical blobs
273         // e.g. if when the same font family is requested in different point-sizes
274         glyphInfo = glyph->glyphInfo;
275       }
276       else
277       {
278         VectorGlyph* newGlyph = VectorGlyph::New(font->mFace,
279                                                  glyphInfo.fontId,
280                                                  glyphInfo.index,
281                                                  mImpl->mAccumulator);
282
283         if(newGlyph)
284         {
285           glyphInfo = newGlyph->glyphInfo;
286
287           cache.push_back(newGlyph);
288         }
289       }
290     }
291   }
292 }
293
294 void VectorFontCache::GetVectorBlob(FontId        vectorFontId,
295                                     FontId        fontId,
296                                     GlyphIndex    glyphIndex,
297                                     VectorBlob*&  blob,
298                                     unsigned int& blobLength,
299                                     unsigned int& nominalWidth,
300                                     unsigned int& nominalHeight)
301 {
302   if(mImpl)
303   {
304     if(vectorFontId > 0 &&
305        vectorFontId - 1 < mImpl->mVectorFonts.size())
306     {
307       VectorFont* font  = mImpl->mVectorFonts[vectorFontId - 1];
308       GlyphCache& cache = font->mGlyphCache;
309
310       bool         foundGlyph(false);
311       unsigned int foundIndex(0);
312       for(unsigned int i = 0; i < cache.size(); ++i)
313       {
314         VectorGlyph* glyph = cache[i];
315
316         if(glyph->glyphInfo.index == glyphIndex)
317         {
318           foundIndex = i;
319           foundGlyph = true;
320           break;
321         }
322       }
323
324       if(foundGlyph)
325       {
326         VectorGlyph* glyph = cache[foundIndex];
327
328         blob          = &glyph->blobData[0];
329         blobLength    = glyph->blobData.size();
330         nominalWidth  = glyph->nominalWidth;
331         nominalHeight = glyph->nominalHeight;
332       }
333       else
334       {
335         VectorGlyph* newGlyph = VectorGlyph::New(font->mFace, fontId, glyphIndex, mImpl->mAccumulator);
336
337         if(newGlyph)
338         {
339           blob          = &newGlyph->blobData[0];
340           blobLength    = newGlyph->blobData.size();
341           nominalWidth  = newGlyph->nominalWidth;
342           nominalHeight = newGlyph->nominalHeight;
343
344           cache.push_back(newGlyph);
345         }
346       }
347     }
348   }
349 }
350
351 bool VectorFontCache::FindFont(const string& url, FontId& vectorFontId) const
352 {
353   vectorFontId = 0u;
354
355   const vector<string>& idLookup = mImpl->mIdLookup;
356
357   for(unsigned int i = 0; i < idLookup.size(); ++i, ++vectorFontId)
358   {
359     if(url == idLookup[i])
360     {
361       ++vectorFontId;
362       return true;
363     }
364   }
365
366   return false;
367 }
368
369 FontId VectorFontCache::CreateFont(const string& url)
370 {
371   FontId id(0);
372
373   // Create & cache new font face
374   FT_Face face;
375   int     error = FT_New_Face(mImpl->mFreeTypeLibrary,
376                           url.c_str(),
377                           0,
378                           &face);
379
380   if(FT_Err_Ok == error)
381   {
382     mImpl->mIdLookup.push_back(url);
383     id = mImpl->mIdLookup.size();
384
385     VectorFont* newFont = new VectorFont(face);
386     mImpl->mVectorFonts.push_back(newFont);
387
388     DALI_ASSERT_DEBUG(mImpl->mIdLookup.size() == mImpl->mVectorFonts.size());
389   }
390
391   return id;
392 }
393
394 } // namespace Internal
395
396 } // namespace TextAbstraction
397
398 } // namespace Dali