2 * Copyright (c) 2019 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 <third-party/glyphy/glyphy.h>
27 #include <third-party/glyphy/glyphy-freetype.h>
34 const unsigned int INITIAL_GLYPH_CAPACITY = 50;
35 const double MIN_FONT_SIZE = 10;
38 accumulate_endpoint( glyphy_arc_endpoint_t* endpoint,
39 vector<glyphy_arc_endpoint_t>* endpoints )
41 endpoints->push_back( *endpoint );
45 } // unnamed namespace
50 namespace TextAbstraction
56 typedef vector<VectorBlob> BlobArray;
61 * @brief Create a vector-based glyph.
63 static VectorGlyph* New( FT_Face face,
66 glyphy_arc_accumulator_t* accumulator )
68 VectorGlyph* newGlyph = new VectorGlyph();
69 newGlyph->blobData.resize( 1024 * 16 );
71 if( FT_Err_Ok != FT_Load_Glyph( face,
77 FT_LOAD_LINEAR_DESIGN |
78 FT_LOAD_IGNORE_TRANSFORM))
80 DALI_LOG_ERROR( "FT_Load_Glyph failed\n" );
85 const double upem = static_cast<double>( face->units_per_EM );
86 const double tolerance = upem * 1.0f/2048.0f;
88 glyphy_arc_accumulator_reset( accumulator);
89 glyphy_arc_accumulator_set_tolerance( accumulator, tolerance );
91 vector<glyphy_arc_endpoint_t> endpoints;
92 glyphy_arc_accumulator_set_callback( accumulator,
93 reinterpret_cast<glyphy_arc_endpoint_accumulator_callback_t>( accumulate_endpoint ),
96 if( FT_Err_Ok != glyphy_freetype_outline_decompose( &face->glyph->outline, accumulator ) )
98 DALI_LOG_ERROR( "glyphy_freetype_outline_decompose failed\n" );
103 DALI_ASSERT_DEBUG( glyphy_arc_accumulator_get_error(accumulator) <= tolerance && "glyphy_arc_accumulator_get_error > tolerance" );
105 if( endpoints.size() )
107 glyphy_outline_winding_from_even_odd( &endpoints[0], static_cast<unsigned int>( endpoints.size() ), false );
110 unsigned int blobLength( 0 );
111 double averageFetchAchieved( 0.0 );
112 if (!glyphy_arc_list_encode_blob( endpoints.size() ? &endpoints[0] : NULL,
113 static_cast<unsigned int>( endpoints.size() ),
114 &newGlyph->blobData[0],
115 static_cast<unsigned int>( newGlyph->blobData.capacity() ),
116 upem / ( MIN_FONT_SIZE * M_SQRT2 ),
118 &averageFetchAchieved,
120 &newGlyph->nominalWidth,
121 &newGlyph->nominalHeight,
122 &newGlyph->extents ) )
124 DALI_LOG_ERROR( "glyphy_arc_list_encode_blob failed\n" );
128 newGlyph->blobData.resize( blobLength );
130 glyphy_extents_scale( &newGlyph->extents, 1.0/upem, 1.0/upem );
132 newGlyph->glyphInfo.fontId = fontId;
133 newGlyph->glyphInfo.index = index;
135 if( glyphy_extents_is_empty( &newGlyph->extents ) )
137 newGlyph->glyphInfo.width = 0.0f;
138 newGlyph->glyphInfo.height = 0.0f;
140 newGlyph->glyphInfo.xBearing = 0.0f;
141 newGlyph->glyphInfo.yBearing = 0.0f;
145 newGlyph->glyphInfo.width = static_cast<float>( newGlyph->extents.max_x - newGlyph->extents.min_x );
146 newGlyph->glyphInfo.height = static_cast<float>( newGlyph->extents.max_y - newGlyph->extents.min_y );
148 newGlyph->glyphInfo.xBearing = static_cast<float>( newGlyph->extents.min_x );
149 newGlyph->glyphInfo.yBearing = newGlyph->glyphInfo.height + static_cast<float>( newGlyph->extents.min_y );
152 newGlyph->glyphInfo.advance = static_cast<float>( static_cast<double>( face->glyph->metrics.horiAdvance ) / upem );
153 newGlyph->glyphInfo.scaleFactor = 0.0f;
165 glyphy_extents_clear( &extents );
168 glyphy_extents_t extents;
170 unsigned int nominalWidth;
171 unsigned int nominalHeight;
176 typedef vector<VectorGlyph*> GlyphCache;
180 VectorFont( FT_Face face )
184 mGlyphCache.reserve( INITIAL_GLYPH_CAPACITY );
188 GlyphCache mGlyphCache;
191 struct VectorFontCache::Impl
193 Impl( FT_Library freeTypeLibrary )
194 : mFreeTypeLibrary( freeTypeLibrary ),
199 mAccumulator = glyphy_arc_accumulator_create();
204 glyphy_arc_accumulator_destroy( mAccumulator );
209 // Declared private and left undefined to avoid copies.
211 // Declared private and left undefined to avoid copies.
212 Impl& operator=( const Impl& );
216 FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
218 vector<string> mIdLookup;
220 vector<VectorFont*> mVectorFonts;
222 glyphy_arc_accumulator_t* mAccumulator;
225 VectorFontCache::VectorFontCache( FT_Library freeTypeLibrary )
228 mImpl = new Impl( freeTypeLibrary );
231 VectorFontCache::~VectorFontCache()
236 FontId VectorFontCache::GetFontId( const std::string& url )
242 if( ! FindFont( url, id ) )
244 id = CreateFont( url );
251 void VectorFontCache::GetGlyphMetrics( FontId vectorFontId, GlyphInfo& glyphInfo )
255 if( vectorFontId > 0 &&
256 vectorFontId-1 < mImpl->mVectorFonts.size() )
258 VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
259 GlyphCache& cache = font->mGlyphCache;
261 bool foundGlyph( false );
262 unsigned int foundIndex( 0 );
263 for( unsigned int i=0; i<cache.size(); ++i )
265 VectorGlyph* glyph = cache[i];
267 if( glyph->glyphInfo.index == glyphInfo.index )
277 VectorGlyph* glyph = cache[foundIndex];
278 // Note - this clobbers the original fontId, but helps avoid duplicating identical blobs
279 // e.g. if when the same font family is requested in different point-sizes
280 glyphInfo = glyph->glyphInfo;
284 VectorGlyph* newGlyph = VectorGlyph::New( font->mFace,
287 mImpl->mAccumulator );
291 glyphInfo = newGlyph->glyphInfo;
293 cache.push_back( newGlyph );
300 void VectorFontCache::GetVectorBlob( FontId vectorFontId,
302 GlyphIndex glyphIndex,
304 unsigned int& blobLength,
305 unsigned int& nominalWidth,
306 unsigned int& nominalHeight )
310 if( vectorFontId > 0 &&
311 vectorFontId-1 < mImpl->mVectorFonts.size() )
313 VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
314 GlyphCache& cache = font->mGlyphCache;
316 bool foundGlyph( false );
317 unsigned int foundIndex( 0 );
318 for( unsigned int i=0; i<cache.size(); ++i )
320 VectorGlyph* glyph = cache[i];
322 if( glyph->glyphInfo.index == glyphIndex )
332 VectorGlyph* glyph = cache[foundIndex];
334 blob = &glyph->blobData[0];
335 blobLength = static_cast<unsigned int>( glyph->blobData.size() );
336 nominalWidth = glyph->nominalWidth;
337 nominalHeight = glyph->nominalHeight;
341 VectorGlyph* newGlyph = VectorGlyph::New( font->mFace, fontId, glyphIndex, mImpl->mAccumulator );
345 blob = &newGlyph->blobData[0];
346 blobLength = static_cast<unsigned int>( newGlyph->blobData.size() );
347 nominalWidth = newGlyph->nominalWidth;
348 nominalHeight = newGlyph->nominalHeight;
350 cache.push_back( newGlyph );
357 bool VectorFontCache::FindFont( const string& url, FontId& vectorFontId ) const
361 const vector<string>& idLookup = mImpl->mIdLookup;
363 for( unsigned int i=0; i<idLookup.size(); ++i, ++vectorFontId )
365 if( url == idLookup[i] )
375 FontId VectorFontCache::CreateFont( const string& url )
379 // Create & cache new font face
381 int error = FT_New_Face( mImpl->mFreeTypeLibrary,
386 if( FT_Err_Ok == error )
388 mImpl->mIdLookup.push_back( url );
389 id = static_cast<FontId>( mImpl->mIdLookup.size() );
391 VectorFont* newFont = new VectorFont( face );
392 mImpl->mVectorFonts.push_back( newFont );
394 DALI_ASSERT_DEBUG( mImpl->mIdLookup.size() == mImpl->mVectorFonts.size() );
400 } // namespace Internal
402 } // namespace TextAbstraction