2 * Copyright (c) 2014 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 <dali/internal/event/text/font-metrics.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/integration-api/glyph-set.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/integration-api/resource-cache.h>
28 #include <dali/internal/event/text/font-factory.h>
29 #include <dali/internal/event/text/utf8-impl.h>
30 #include <dali/internal/event/text/text-impl.h>
31 #include <dali/internal/event/text/character-impl.h>
32 #include <dali/internal/event/resources/resource-client.h>
33 #include <dali/internal/event/common/thread-local-storage.h>
40 namespace //unnamed namespace
43 const float DEFAULT_UNITS_PER_EM( 1.f );
45 const uint32_t FIRST_NON_CONTROL_CHAR( 0x20 ); // 0x20 is the white space which is the first non control character.
47 Integration::TextArray GetUniqueCharacters( const Integration::TextArray& text )
49 Integration::TextArray utfCodes = text;
50 std::sort( utfCodes.Begin(), utfCodes.End() );
51 Integration::TextArray::Iterator it = std::unique( utfCodes.Begin(), utfCodes.End() );
52 utfCodes.Resize( it - utfCodes.Begin() );
56 } // unnamed namespace
60 FontMetricsIntrusivePtr FontMetrics::New( const Vector2& dpi,
61 const std::size_t hashValue,
63 const std::string& fontFamily,
64 const std::string& fontStyle )
66 return new FontMetrics( dpi, hashValue, fontId, fontFamily, fontStyle );
69 void FontMetrics::LoadGlobalMetrics()
71 // Read global metrics synchronously.
72 bool success = ReadGlobalMetricsFromCache();
76 Dali::Integration::GlobalMetrics globalMetrics;
78 // Read global metrics from platform.
79 mPlatform.GetGlobalMetrics( mFontFamily, mFontStyle, globalMetrics );
81 // configure the metrics
82 mFontLayout.SetMetrics( globalMetrics );
84 // write the metrics to a cache
85 WriteGlobalMetricsToCache();
89 Vector3 FontMetrics::MeasureText( const Integration::TextArray& text )
91 if( 0u == text.Count() )
96 Integration::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( Integration::TextArray::ConstIterator 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 Integration::TextArray& text ) const
136 TCharMap::const_iterator endIter = mCharMap.end();
138 for( Integration::TextArray::ConstIterator 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 Integration::TextArray& text, CharacterList& missingText ) const
154 // sort and remove duplicate character codes
155 Integration::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( Integration::TextArray::ConstIterator 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 Integration::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 )
302 Integration::TextArray utfCodes;
303 utfCodes.PushBack( 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();
372 mMetricsLoaded = true;
375 bool FontMetrics::ReadGlobalMetricsFromCache( )
377 Integration::GlobalMetrics globalMetrics;
379 bool success = mPlatform.ReadGlobalMetricsFromCache( mFontFamily, mFontStyle, globalMetrics );
382 mFontLayout.SetMetrics( globalMetrics );
387 void FontMetrics::WriteGlobalMetricsToCache()
389 mPlatform.WriteGlobalMetricsToCache( mFontFamily, mFontStyle, mFontLayout.GetGlobalMetrics() );
393 bool FontMetrics::ReadMetricsFromCache()
395 std::vector<Integration::GlyphMetrics> glyphMetricsContainer;
397 bool success = mPlatform.ReadMetricsFromCache( mFontFamily, mFontStyle, glyphMetricsContainer );
400 for( std::size_t i=0, end=glyphMetricsContainer.size(); i<end; ++i )
402 AddGlyphMetricToCache( glyphMetricsContainer[i] );
408 void FontMetrics::WriteMetricsToCache( const Integration::GlyphSet& glyphSet )
410 mPlatform.WriteMetricsToCache( mFontFamily, mFontStyle, glyphSet );
413 FontMetrics::FontMetrics(const Vector2& dpi,
414 const std::size_t hashValue,
416 const std::string& fontFamily,
417 const std::string& fontStyle )
419 mFontFamily(fontFamily),
420 mFontStyle(fontStyle),
422 mFontLayout(DEFAULT_UNITS_PER_EM, dpi),
426 mMetricsLoaded( false ),
427 mPlatform( ThreadLocalStorage::Get().GetPlatformAbstraction() )
431 FontMetrics::~FontMetrics()
435 void FontMetrics::AddGlyphMetricToCache( const Integration::GlyphMetrics& glyphMetric )
437 DALI_ASSERT_DEBUG( mCharMap.find(glyphMetric.code) == mCharMap.end() );
439 // convert from an Dali::Integration metric to an internal metric.
440 // This is partly to avoid any classes that want to use FontMetricsInterface from
441 // having to include glyph-set integration header (which pull in boost / bitmaps etc).
443 GlyphMetric metric( glyphMetric.code,
448 glyphMetric.xAdvance);
450 mCharMap[glyphMetric.code] = metric; // copy by value
454 } // namespace Internal