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,
66 ResourceClient& resourceClient )
68 return new FontMetrics( dpi, hashValue, fontId, fontFamily, fontStyle, resourceClient);
71 void FontMetrics::LoadGlobalMetrics()
73 // Read global metrics synchronously.
74 bool success = ReadGlobalMetricsFromCache();
78 Dali::Integration::GlobalMetrics globalMetrics;
80 // Read global metrics from platform.
81 mPlatform.GetGlobalMetrics( mFontFamily, mFontStyle, globalMetrics );
83 // configure the metrics
84 mFontLayout.SetMetrics( globalMetrics );
86 // write the metrics to a cache
87 WriteGlobalMetricsToCache();
91 Vector3 FontMetrics::MeasureText( const TextArray& text )
97 TextArray utfCodes = GetUniqueCharacters( text );
99 // ensure all the metrics are loaded for the characters
100 LoadMetricsSynchronously( utfCodes ) ;
103 // Calculate the natural size of text for the font
104 Vector3 measurement(Vector3::ZERO);
105 const GlyphMetric* glyphMetric(NULL);
109 for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
111 const uint32_t utfCode( *it );
113 glyphMetric = GetGlyph( utfCode );
115 xPos += glyphMetric->GetXAdvance();
117 measurement.x = std::max(measurement.x, xPos);
122 // The glyphs may be wider than their advance, so increase measurement
123 // by the difference between the width and advance of the last glyph
124 if (glyphMetric->GetWidth() > glyphMetric->GetXAdvance() )
126 measurement.x += glyphMetric->GetWidth() - glyphMetric->GetXAdvance();
130 measurement.y = mFontLayout.GetLineHeight();
135 bool FontMetrics::TextAvailable( const TextArray& text ) const
137 TCharMap::const_iterator endIter = mCharMap.end();
139 for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
141 const uint32_t utfCode( *it );
143 TCharMap::const_iterator iter = mCharMap.find( utfCode );
144 if( iter == endIter )
153 unsigned int FontMetrics::GetMissingText( const TextArray& text, CharacterList& missingText ) const
155 // sort and remove duplicate character codes
156 TextArray utfCodes( GetUniqueCharacters(text) );
158 // scan through the metrics cache, making a list of characters that are missing
159 TCharMap::const_iterator endIter = mCharMap.end();
160 for( TextArray::const_iterator it = utfCodes.begin(), endIt = utfCodes.end(); it != endIt; ++it )
162 const uint32_t utfCode( *it );
164 TCharMap::const_iterator iter = mCharMap.find( utfCode );
165 if( iter == endIter )
167 missingText.push_back( Integration::TextResourceType::GlyphPosition(utfCode, 0, 0) );
170 return missingText.size();
173 void FontMetrics::LoadMetricsSynchronously( const TextArray& text )
175 // check to make sure the metrics cache has loaded
176 CheckMetricsLoaded();
178 // check if all the characters are cached in memory
179 bool textCached = TextAvailable( text );
183 const Vector2 maxGlyphCell( GetMaxWidth(), GetMaxHeight() );
185 Integration::TextResourceType::CharacterList missingText;
187 // find out which characters aren't cached
188 GetMissingText( text, missingText );
190 if( !missingText.empty() )
192 // some character metrics aren't cached, so load them now
194 // TODO - ADD NEW METRICS RESOURCE TYPE
195 Integration::TextResourceType resourceType( mHash, mFontStyle, missingText, 0, Integration::TextResourceType::TextQualityHigh, maxGlyphCell, Integration::TextResourceType::GLYPH_CACHE_READ);
196 // this is a synchronous request
197 Integration::GlyphSetPointer glyphs = mPlatform.GetGlyphData( resourceType, mFontFamily, false );
201 DALI_LOG_WARNING("Font or glyph data not found for font %s-%s !\n", mFontFamily.c_str(), mFontStyle.c_str() );
205 // cache the metrics to a cache
206 WriteMetricsToCache( *glyphs.Get() );
208 // cache the metrics in memory
209 AddGlyphSet( 0, *glyphs.Get() );
214 const GlyphMetric* FontMetrics::GetGlyph( uint32_t characterCode) const
216 TCharMap::const_iterator iter = mCharMap.find( characterCode );
218 if( iter != mCharMap.end())
220 return &iter->second;
224 // can and will happen if a glyph doesn't exist for the
225 // given character code
226 if( characterCode >= FIRST_NON_CONTROL_CHAR )
228 DALI_LOG_ERROR("failed to find character %lu\n", characterCode );
234 FontId FontMetrics::GetFontId() const
239 const std::string& FontMetrics::GetFontFamilyName() const
244 const std::string& FontMetrics::GetFontStyleName() const
249 void FontMetrics::GetMaximumGylphSize( float& width, float& height ) const
251 width = GetMaxWidth();
252 height = GetMaxHeight();
255 float FontMetrics::GetUnitsToPixels( const float pointSize ) const
257 return mFontLayout.GetUnitsToPixels( pointSize );
260 float FontMetrics::GetLineHeight() const
262 return mFontLayout.GetLineHeight();
265 float FontMetrics::GetAscender() const
267 return mFontLayout.GetAscender();
270 float FontMetrics::GetUnderlinePosition() const
272 return mFontLayout.GetUnderlinePosition();
275 float FontMetrics::GetUnderlineThickness() const
277 return mFontLayout.GetUnderlineThickness();
280 float FontMetrics::GetMaxWidth() const
282 return mFontLayout.GetMaxWidth();
285 float FontMetrics::GetMaxHeight() const
287 return mFontLayout.GetMaxHeight();
290 float FontMetrics::GetPadAdjustX() const
292 return mFontLayout.GetPadAdjustX();
295 float FontMetrics::GetPadAdjustY() const
297 return mFontLayout.GetPadAdjustY();
301 void FontMetrics::GetMetrics( const Dali::Character& character, Dali::Font::Metrics::Impl& metrics )
304 utfCodes.push_back( character.GetImplementation().GetCharacter() );
306 LoadMetricsSynchronously( utfCodes ) ;
308 const GlyphMetric* glyph;
310 glyph = GetGlyph( character.GetImplementation().GetCharacter() );
315 metrics.advance = glyph->GetXAdvance();
316 metrics.bearing = glyph->GetTop();
317 metrics.width = std::max( glyph->GetWidth(), glyph->GetXAdvance() );
318 metrics.height = glyph->GetHeight();
322 metrics.advance = 0.0f;
323 metrics.bearing = 0.0f;
324 metrics.width = 0.0f;
325 metrics.height = 0.0f;
329 void FontMetrics::IncreaseFontCount()
334 void FontMetrics::DecreaseFontCount()
336 DALI_ASSERT_DEBUG( mFontCount != 0 );
340 unsigned int FontMetrics::GetFontUsageCount() const
345 // Called when a metric is loaded
346 void FontMetrics::AddGlyphSet( Integration::ResourceId id, const Integration::GlyphSet& glyphSet )
348 const Integration::GlyphSet::CharacterList& characterList = glyphSet.GetCharacterList();
350 for( Integration::GlyphSet::CharacterConstIter it = characterList.begin(), endIt = characterList.end(); it != endIt; ++it )
352 Integration::GlyphMetrics glyphMetrics( it->second );
353 // the map is used to retrieve character information when measuring a string
354 AddGlyphMetricToCache( glyphMetrics );
358 void FontMetrics::CheckMetricsLoaded()
365 // read the metrics from the cache
366 bool success = ReadMetricsFromCache();
370 WriteGlobalMetricsToCache();
372 DALI_LOG_ERROR("metrics cache corrupted or older version found. New cache created. \n");
375 mMetricsLoaded = true;
378 bool FontMetrics::ReadGlobalMetricsFromCache( )
380 Integration::GlobalMetrics globalMetrics;
382 bool success = mPlatform.ReadGlobalMetricsFromCache( mFontFamily, mFontStyle, globalMetrics );
385 mFontLayout.SetMetrics( globalMetrics );
390 void FontMetrics::WriteGlobalMetricsToCache()
392 mPlatform.WriteGlobalMetricsToCache( mFontFamily, mFontStyle, mFontLayout.GetGlobalMetrics() );
396 bool FontMetrics::ReadMetricsFromCache()
398 std::vector<Integration::GlyphMetrics> glyphMetricsContainer;
400 bool success = mPlatform.ReadMetricsFromCache( mFontFamily, mFontStyle, glyphMetricsContainer );
403 for( std::size_t i=0, end=glyphMetricsContainer.size(); i<end; ++i )
405 AddGlyphMetricToCache( glyphMetricsContainer[i] );
411 void FontMetrics::WriteMetricsToCache( const Integration::GlyphSet& glyphSet )
413 mPlatform.WriteMetricsToCache( mFontFamily, mFontStyle, glyphSet );
416 FontMetrics::FontMetrics(const Vector2& dpi,
417 const std::size_t hashValue,
419 const std::string& fontFamily,
420 const std::string& fontStyle,
421 ResourceClient& resourceClient )
423 mFontFamily(fontFamily),
424 mFontStyle(fontStyle),
426 mFontLayout(DEFAULT_UNITS_PER_EM, dpi),
430 mMetricsLoaded( false ),
431 mPlatform( ThreadLocalStorage::Get().GetPlatformAbstraction() ),
432 mResourceClient( resourceClient )
436 FontMetrics::~FontMetrics()
440 void FontMetrics::AddGlyphMetricToCache( const Integration::GlyphMetrics& glyphMetric )
442 DALI_ASSERT_DEBUG( mCharMap.find(glyphMetric.code) == mCharMap.end() );
444 // convert from an Dali::Integration metric to an internal metric.
445 // This is partly to avoid any classes that want to use FontMetricsInterface from
446 // having to include glyph-set integration header (which pull in boost / bitmaps etc).
448 GlyphMetric metric( glyphMetric.code,
453 glyphMetric.xAdvance);
455 mCharMap[glyphMetric.code] = metric; // copy by value
459 } // namespace Internal