2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include <dali/internal/event/text/font-metrics.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/integration-api/glyph-set.h>
25 #include <dali/integration-api/platform-abstraction.h>
26 #include <dali/integration-api/resource-cache.h>
27 #include <dali/internal/event/text/font-factory.h>
28 #include <dali/internal/event/text/utf8-impl.h>
29 #include <dali/internal/event/text/text-impl.h>
30 #include <dali/internal/event/text/character-impl.h>
31 #include <dali/internal/event/resources/resource-client.h>
32 #include <dali/internal/event/common/thread-local-storage.h>
39 namespace //unnamed namespace
42 const float DEFAULT_UNITS_PER_EM( 1.f );
44 const uint32_t FIRST_NON_CONTROL_CHAR( 0x20 ); // 0x20 is the white space which is the first non control character.
45 const uint32_t LINE_SEPARATOR( '\n' );
48 TextArray GetUniqueCharacters( const TextArray &text )
50 TextArray utfCodes(text.begin(), text.end());
51 std::sort( utfCodes.begin(), utfCodes.end() );
52 TextArray::iterator it = std::unique( utfCodes.begin(), utfCodes.end() );
53 utfCodes.resize(it - utfCodes.begin());
57 } // unnamed namespace
61 FontMetricsIntrusivePtr FontMetrics::New( const Vector2& dpi,
62 const std::size_t hashValue,
64 const std::string& fontFamily,
65 const std::string& fontStyle )
67 return new FontMetrics( dpi, hashValue, fontId, fontFamily, fontStyle );
70 void FontMetrics::LoadGlobalMetrics()
72 // Read global metrics synchronously.
73 bool success = ReadGlobalMetricsFromCache();
77 Dali::Integration::GlobalMetrics globalMetrics;
79 // Read global metrics from platform.
80 mPlatform.GetGlobalMetrics( mFontFamily, mFontStyle, globalMetrics );
82 // configure the metrics
83 mFontLayout.SetMetrics( globalMetrics );
85 // write the metrics to a cache
86 WriteGlobalMetricsToCache();
90 Vector3 FontMetrics::MeasureText( const TextArray& text )
96 TextArray utfCodes = GetUniqueCharacters( text );
98 // ensure all the metrics are loaded for the characters
99 LoadMetricsSynchronously( utfCodes );
102 // Calculate the natural size of text for the font
103 Vector3 measurement(Vector3::ZERO);
104 const GlyphMetric* glyphMetric(NULL);
108 for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
110 const uint32_t utfCode( *it );
112 glyphMetric = GetGlyph( utfCode );
114 xPos += glyphMetric->GetXAdvance();
116 measurement.x = std::max(measurement.x, xPos);
121 // The glyphs may be wider than their advance, so increase measurement
122 // by the difference between the width and advance of the last glyph
123 if (glyphMetric->GetWidth() > glyphMetric->GetXAdvance() )
125 measurement.x += glyphMetric->GetWidth() - glyphMetric->GetXAdvance();
129 measurement.y = mFontLayout.GetLineHeight();
134 bool FontMetrics::TextAvailable( const TextArray& text ) const
136 TCharMap::const_iterator endIter = mCharMap.end();
138 for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
140 const uint32_t utfCode( *it );
142 TCharMap::const_iterator iter = mCharMap.find( utfCode );
143 if( iter == endIter )
152 unsigned int FontMetrics::GetMissingText( const TextArray& text, CharacterList& missingText ) const
154 // sort and remove duplicate character codes
155 TextArray utfCodes( GetUniqueCharacters(text) );
157 // scan through the metrics cache, making a list of characters that are missing
158 TCharMap::const_iterator endIter = mCharMap.end();
159 for( TextArray::const_iterator it = utfCodes.begin(), endIt = utfCodes.end(); it != endIt; ++it )
161 const uint32_t utfCode( *it );
163 TCharMap::const_iterator iter = mCharMap.find( utfCode );
164 if( iter == endIter )
166 missingText.push_back( Integration::TextResourceType::GlyphPosition(utfCode, 0, 0) );
169 return missingText.size();
172 void FontMetrics::LoadMetricsSynchronously( const TextArray& text )
174 // check to make sure the metrics cache has loaded
175 CheckMetricsLoaded();
177 // check if all the characters are cached in memory
178 bool textCached = TextAvailable( text );
182 const Vector2 maxGlyphCell( GetMaxWidth(), GetMaxHeight() );
184 Integration::TextResourceType::CharacterList missingText;
186 // find out which characters aren't cached
187 GetMissingText( text, missingText );
189 if( !missingText.empty() )
191 // some character metrics aren't cached, so load them now
193 // TODO - ADD NEW METRICS RESOURCE TYPE
194 Integration::TextResourceType resourceType( mHash, mFontStyle, missingText, 0, Integration::TextResourceType::TextQualityHigh, maxGlyphCell, Integration::TextResourceType::GLYPH_CACHE_READ);
195 // this is a synchronous request
196 Integration::GlyphSetPointer glyphs = mPlatform.GetGlyphData( resourceType, mFontFamily, false );
200 DALI_LOG_WARNING("Font or glyph data not found for font %s-%s !\n", mFontFamily.c_str(), mFontStyle.c_str() );
204 // cache the metrics to a cache
205 WriteMetricsToCache( *glyphs.Get() );
207 // cache the metrics in memory
208 AddGlyphSet( 0, *glyphs.Get() );
213 const GlyphMetric* FontMetrics::GetGlyph( uint32_t characterCode) const
215 TCharMap::const_iterator iter = mCharMap.find( characterCode );
217 if( iter != mCharMap.end())
219 return &iter->second;
223 // can and will happen if a glyph doesn't exist for the
224 // given character code
225 if( characterCode >= FIRST_NON_CONTROL_CHAR )
227 DALI_LOG_ERROR("failed to find character %lu\n", characterCode );
233 FontId FontMetrics::GetFontId() const
238 const std::string& FontMetrics::GetFontFamilyName() const
243 const std::string& FontMetrics::GetFontStyleName() const
248 void FontMetrics::GetMaximumGylphSize( float& width, float& height ) const
250 width = GetMaxWidth();
251 height = GetMaxHeight();
254 float FontMetrics::GetUnitsToPixels( const float pointSize ) const
256 return mFontLayout.GetUnitsToPixels( pointSize );
259 float FontMetrics::GetLineHeight() const
261 return mFontLayout.GetLineHeight();
264 float FontMetrics::GetAscender() const
266 return mFontLayout.GetAscender();
269 float FontMetrics::GetUnderlinePosition() const
271 return mFontLayout.GetUnderlinePosition();
274 float FontMetrics::GetUnderlineThickness() const
276 return mFontLayout.GetUnderlineThickness();
279 float FontMetrics::GetMaxWidth() const
281 return mFontLayout.GetMaxWidth();
284 float FontMetrics::GetMaxHeight() const
286 return mFontLayout.GetMaxHeight();
289 float FontMetrics::GetPadAdjustX() const
291 return mFontLayout.GetPadAdjustX();
294 float FontMetrics::GetPadAdjustY() const
296 return mFontLayout.GetPadAdjustY();
300 void FontMetrics::GetMetrics( const Dali::Character& character, Dali::Font::Metrics::Impl& metrics )
303 utfCodes.push_back( character.GetImplementation().GetCharacter() );
305 LoadMetricsSynchronously( utfCodes );
307 const GlyphMetric* glyph;
309 glyph = GetGlyph( character.GetImplementation().GetCharacter() );
314 metrics.advance = glyph->GetXAdvance();
315 metrics.bearing = glyph->GetTop();
316 metrics.width = std::max( glyph->GetWidth(), glyph->GetXAdvance() );
317 metrics.height = glyph->GetHeight();
321 metrics.advance = 0.0f;
322 metrics.bearing = 0.0f;
323 metrics.width = 0.0f;
324 metrics.height = 0.0f;
328 void FontMetrics::IncreaseFontCount()
333 void FontMetrics::DecreaseFontCount()
335 DALI_ASSERT_DEBUG( mFontCount != 0 );
339 unsigned int FontMetrics::GetFontUsageCount() const
344 // Called when a metric is loaded
345 void FontMetrics::AddGlyphSet( Integration::ResourceId id, const Integration::GlyphSet& glyphSet )
347 const Integration::GlyphSet::CharacterList& characterList = glyphSet.GetCharacterList();
349 for( Integration::GlyphSet::CharacterConstIter it = characterList.begin(), endIt = characterList.end(); it != endIt; ++it )
351 Integration::GlyphMetrics glyphMetrics( it->second );
352 // the map is used to retrieve character information when measuring a string
353 AddGlyphMetricToCache( glyphMetrics );
357 void FontMetrics::CheckMetricsLoaded()
364 // read the metrics from the cache
365 bool success = ReadMetricsFromCache();
369 WriteGlobalMetricsToCache();
371 DALI_LOG_ERROR("metrics cache corrupted or older version found. New cache created. \n");
374 mMetricsLoaded = true;
377 bool FontMetrics::ReadGlobalMetricsFromCache( )
379 Integration::GlobalMetrics globalMetrics;
381 bool success = mPlatform.ReadGlobalMetricsFromCache( mFontFamily, mFontStyle, globalMetrics );
384 mFontLayout.SetMetrics( globalMetrics );
389 void FontMetrics::WriteGlobalMetricsToCache()
391 mPlatform.WriteGlobalMetricsToCache( mFontFamily, mFontStyle, mFontLayout.GetGlobalMetrics() );
395 bool FontMetrics::ReadMetricsFromCache()
397 std::vector<Integration::GlyphMetrics> glyphMetricsContainer;
399 bool success = mPlatform.ReadMetricsFromCache( mFontFamily, mFontStyle, glyphMetricsContainer );
402 for( std::size_t i=0, end=glyphMetricsContainer.size(); i<end; ++i )
404 AddGlyphMetricToCache( glyphMetricsContainer[i] );
410 void FontMetrics::WriteMetricsToCache( const Integration::GlyphSet& glyphSet )
412 mPlatform.WriteMetricsToCache( mFontFamily, mFontStyle, glyphSet );
415 FontMetrics::FontMetrics(const Vector2& dpi,
416 const std::size_t hashValue,
418 const std::string& fontFamily,
419 const std::string& fontStyle )
421 mFontFamily(fontFamily),
422 mFontStyle(fontStyle),
424 mFontLayout(DEFAULT_UNITS_PER_EM, dpi),
428 mMetricsLoaded( false ),
429 mPlatform( ThreadLocalStorage::Get().GetPlatformAbstraction() )
433 FontMetrics::~FontMetrics()
437 void FontMetrics::AddGlyphMetricToCache( const Integration::GlyphMetrics& glyphMetric )
439 DALI_ASSERT_DEBUG( mCharMap.find(glyphMetric.code) == mCharMap.end() );
441 // convert from an Dali::Integration metric to an internal metric.
442 // This is partly to avoid any classes that want to use FontMetricsInterface from
443 // having to include glyph-set integration header (which pull in boost / bitmaps etc).
445 GlyphMetric metric( glyphMetric.code,
450 glyphMetric.xAdvance);
452 mCharMap[glyphMetric.code] = metric; // copy by value
456 } // namespace Internal