2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <third-party/glyphy/vector-font-cache.h>
26 #include <dali/internal/text/glyphy/glyphy-freetype.h>
27 #include <dali/internal/text/glyphy/glyphy.h>
33 const unsigned int INITIAL_GLYPH_CAPACITY = 50;
34 const double MIN_FONT_SIZE = 10;
37 accumulate_endpoint(glyphy_arc_endpoint_t* endpoint,
38 vector<glyphy_arc_endpoint_t>* endpoints)
40 endpoints->push_back(*endpoint);
44 } // unnamed namespace
48 namespace TextAbstraction
52 typedef vector<VectorBlob> BlobArray;
57 * @brief Create a vector-based glyph.
59 static VectorGlyph* New(FT_Face face,
62 glyphy_arc_accumulator_t* accumulator)
64 VectorGlyph* newGlyph = new VectorGlyph();
65 newGlyph->blobData.resize(1024 * 16);
67 if(FT_Err_Ok != FT_Load_Glyph(face,
73 FT_LOAD_LINEAR_DESIGN |
74 FT_LOAD_IGNORE_TRANSFORM))
76 DALI_LOG_ERROR("FT_Load_Glyph failed\n");
81 const double upem = static_cast<double>(face->units_per_EM);
82 const double tolerance = upem * 1.0f / 2048.0f;
84 glyphy_arc_accumulator_reset(accumulator);
85 glyphy_arc_accumulator_set_tolerance(accumulator, tolerance);
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),
92 if(FT_Err_Ok != glyphy_freetype_outline_decompose(&face->glyph->outline, accumulator))
94 DALI_LOG_ERROR("glyphy_freetype_outline_decompose failed\n");
99 DALI_ASSERT_DEBUG(glyphy_arc_accumulator_get_error(accumulator) <= tolerance && "glyphy_arc_accumulator_get_error > tolerance");
103 glyphy_outline_winding_from_even_odd(&endpoints[0], endpoints.size(), false);
106 unsigned int blobLength(0);
107 double averageFetchAchieved(0.0);
108 if(!glyphy_arc_list_encode_blob(endpoints.size() ? &endpoints[0] : NULL,
110 &newGlyph->blobData[0],
111 newGlyph->blobData.capacity(),
112 upem / (MIN_FONT_SIZE * M_SQRT2),
114 &averageFetchAchieved,
116 &newGlyph->nominalWidth,
117 &newGlyph->nominalHeight,
120 DALI_LOG_ERROR("glyphy_arc_list_encode_blob failed\n");
124 newGlyph->blobData.resize(blobLength);
126 glyphy_extents_scale(&newGlyph->extents, 1.0 / upem, 1.0 / upem);
128 newGlyph->glyphInfo.fontId = fontId;
129 newGlyph->glyphInfo.index = index;
131 if(glyphy_extents_is_empty(&newGlyph->extents))
133 newGlyph->glyphInfo.width = 0.0f;
134 newGlyph->glyphInfo.height = 0.0f;
136 newGlyph->glyphInfo.xBearing = 0.0f;
137 newGlyph->glyphInfo.yBearing = 0.0f;
141 newGlyph->glyphInfo.width = (newGlyph->extents.max_x - newGlyph->extents.min_x);
142 newGlyph->glyphInfo.height = (newGlyph->extents.max_y - newGlyph->extents.min_y);
144 newGlyph->glyphInfo.xBearing = newGlyph->extents.min_x;
145 newGlyph->glyphInfo.yBearing = newGlyph->glyphInfo.height + (newGlyph->extents.min_y);
148 newGlyph->glyphInfo.advance = face->glyph->metrics.horiAdvance / upem;
149 newGlyph->glyphInfo.scaleFactor = 0.0f;
161 glyphy_extents_clear(&extents);
164 glyphy_extents_t extents;
166 unsigned int nominalWidth;
167 unsigned int nominalHeight;
172 typedef vector<VectorGlyph*> GlyphCache;
176 VectorFont(FT_Face face)
180 mGlyphCache.reserve(INITIAL_GLYPH_CAPACITY);
184 GlyphCache mGlyphCache;
187 struct VectorFontCache::Impl
189 Impl(FT_Library freeTypeLibrary)
190 : mFreeTypeLibrary(freeTypeLibrary),
195 mAccumulator = glyphy_arc_accumulator_create();
200 glyphy_arc_accumulator_destroy(mAccumulator);
204 // Declared private and left undefined to avoid copies.
206 // Declared private and left undefined to avoid copies.
207 Impl& operator=(const Impl&);
210 FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
212 vector<string> mIdLookup;
214 vector<VectorFont*> mVectorFonts;
216 glyphy_arc_accumulator_t* mAccumulator;
219 VectorFontCache::VectorFontCache(FT_Library freeTypeLibrary)
222 mImpl = new Impl(freeTypeLibrary);
225 VectorFontCache::~VectorFontCache()
230 FontId VectorFontCache::GetFontId(const std::string& url)
236 if(!FindFont(url, id))
238 id = CreateFont(url);
245 void VectorFontCache::GetGlyphMetrics(FontId vectorFontId, GlyphInfo& glyphInfo)
249 if(vectorFontId > 0 &&
250 vectorFontId - 1 < mImpl->mVectorFonts.size())
252 VectorFont* font = mImpl->mVectorFonts[vectorFontId - 1];
253 GlyphCache& cache = font->mGlyphCache;
255 bool foundGlyph(false);
256 unsigned int foundIndex(0);
257 for(unsigned int i = 0; i < cache.size(); ++i)
259 VectorGlyph* glyph = cache[i];
261 if(glyph->glyphInfo.index == glyphInfo.index)
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;
278 VectorGlyph* newGlyph = VectorGlyph::New(font->mFace,
281 mImpl->mAccumulator);
285 glyphInfo = newGlyph->glyphInfo;
287 cache.push_back(newGlyph);
294 void VectorFontCache::GetVectorBlob(FontId vectorFontId,
296 GlyphIndex glyphIndex,
298 unsigned int& blobLength,
299 unsigned int& nominalWidth,
300 unsigned int& nominalHeight)
304 if(vectorFontId > 0 &&
305 vectorFontId - 1 < mImpl->mVectorFonts.size())
307 VectorFont* font = mImpl->mVectorFonts[vectorFontId - 1];
308 GlyphCache& cache = font->mGlyphCache;
310 bool foundGlyph(false);
311 unsigned int foundIndex(0);
312 for(unsigned int i = 0; i < cache.size(); ++i)
314 VectorGlyph* glyph = cache[i];
316 if(glyph->glyphInfo.index == glyphIndex)
326 VectorGlyph* glyph = cache[foundIndex];
328 blob = &glyph->blobData[0];
329 blobLength = glyph->blobData.size();
330 nominalWidth = glyph->nominalWidth;
331 nominalHeight = glyph->nominalHeight;
335 VectorGlyph* newGlyph = VectorGlyph::New(font->mFace, fontId, glyphIndex, mImpl->mAccumulator);
339 blob = &newGlyph->blobData[0];
340 blobLength = newGlyph->blobData.size();
341 nominalWidth = newGlyph->nominalWidth;
342 nominalHeight = newGlyph->nominalHeight;
344 cache.push_back(newGlyph);
351 bool VectorFontCache::FindFont(const string& url, FontId& vectorFontId) const
355 const vector<string>& idLookup = mImpl->mIdLookup;
357 for(unsigned int i = 0; i < idLookup.size(); ++i, ++vectorFontId)
359 if(url == idLookup[i])
369 FontId VectorFontCache::CreateFont(const string& url)
373 // Create & cache new font face
375 int error = FT_New_Face(mImpl->mFreeTypeLibrary,
380 if(FT_Err_Ok == error)
382 mImpl->mIdLookup.push_back(url);
383 id = mImpl->mIdLookup.size();
385 VectorFont* newFont = new VectorFont(face);
386 mImpl->mVectorFonts.push_back(newFont);
388 DALI_ASSERT_DEBUG(mImpl->mIdLookup.size() == mImpl->mVectorFonts.size());
394 } // namespace Internal
396 } // namespace TextAbstraction