Revert "License conversion from Flora to Apache 2.0"
[platform/core/uifw/dali-core.git] / dali / internal / event / text / font-metrics.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 //     http://floralicense.org/license/
9 //
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.
15 //
16
17 // CLASS HEADER
18 #include <dali/internal/event/text/font-metrics.h>
19
20 // EXTERNAL HEADERS
21
22 // INTERNAL INCLUDES
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>
33
34 namespace Dali
35 {
36 namespace Internal
37 {
38
39 namespace  //unnamed namespace
40 {
41
42 const float DEFAULT_UNITS_PER_EM( 1.f );
43
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' );
46
47
48 TextArray GetUniqueCharacters( const TextArray &text )
49 {
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());
54   return utfCodes;
55 }
56
57 } // unnamed namespace
58
59
60
61 FontMetricsIntrusivePtr FontMetrics::New( const Vector2& dpi,
62                                           const std::size_t hashValue,
63                                           const FontId fontId,
64                                           const std::string& fontFamily,
65                                           const std::string& fontStyle )
66 {
67   return new FontMetrics( dpi, hashValue, fontId, fontFamily, fontStyle );
68 }
69
70 void FontMetrics::LoadGlobalMetrics()
71 {
72   // Read global metrics synchronously.
73   bool success = ReadGlobalMetricsFromCache();
74
75   if( !success )
76   {
77     Dali::Integration::GlobalMetrics globalMetrics;
78
79     // Read global metrics from platform.
80     mPlatform.GetGlobalMetrics( mFontFamily, mFontStyle, globalMetrics );
81
82     // configure the metrics
83     mFontLayout.SetMetrics( globalMetrics );
84
85     // write the metrics to a cache
86     WriteGlobalMetricsToCache();
87   }
88 }
89
90 Vector3 FontMetrics::MeasureText( const TextArray& text )
91 {
92   if( text.empty() )
93   {
94     return  Vector3::ZERO;
95   }
96   TextArray  utfCodes = GetUniqueCharacters( text );
97
98   // ensure all the metrics are loaded for the characters
99   LoadMetricsSynchronously( utfCodes );
100
101   // Measure text
102   // Calculate the natural size of text for the font
103   Vector3 measurement(Vector3::ZERO);
104   const GlyphMetric* glyphMetric(NULL);
105
106   float xPos = 0.0f;
107
108   for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
109   {
110     const uint32_t utfCode( *it );
111
112     glyphMetric = GetGlyph( utfCode );
113
114     xPos += glyphMetric->GetXAdvance();
115
116     measurement.x = std::max(measurement.x, xPos);
117   }
118
119   if (glyphMetric )
120   {
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() )
124       {
125         measurement.x += glyphMetric->GetWidth() - glyphMetric->GetXAdvance();
126       }
127   }
128
129   measurement.y = mFontLayout.GetLineHeight();
130
131   return measurement;
132 }
133
134 bool FontMetrics::TextAvailable( const TextArray& text ) const
135 {
136   TCharMap::const_iterator endIter = mCharMap.end();
137
138   for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
139   {
140     const uint32_t utfCode( *it );
141
142     TCharMap::const_iterator iter = mCharMap.find( utfCode );
143     if( iter == endIter )
144     {
145       return false;
146     }
147   }
148
149   return true;
150 }
151
152 unsigned int FontMetrics::GetMissingText( const TextArray& text, CharacterList& missingText ) const
153 {
154   // sort and remove duplicate character codes
155   TextArray utfCodes( GetUniqueCharacters(text) );
156
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 )
160   {
161     const uint32_t utfCode( *it );
162
163     TCharMap::const_iterator iter = mCharMap.find( utfCode );
164     if( iter == endIter )
165     {
166       missingText.push_back( Integration::TextResourceType::GlyphPosition(utfCode, 0, 0) );
167     }
168   }
169   return missingText.size();
170 }
171
172 void FontMetrics::LoadMetricsSynchronously( const TextArray& text )
173 {
174   // check to make sure the metrics cache has loaded
175   CheckMetricsLoaded();
176
177   // check if all the characters are cached in memory
178   bool textCached = TextAvailable( text );
179
180   if( !textCached )
181   {
182     const Vector2 maxGlyphCell( GetMaxWidth(), GetMaxHeight() );
183
184     Integration::TextResourceType::CharacterList missingText;
185
186     // find out which characters aren't cached
187     GetMissingText( text, missingText );
188
189     if( !missingText.empty() )
190     {
191       // some character metrics aren't cached, so load them now
192
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 );
197
198       if (!glyphs)
199       {
200         DALI_LOG_WARNING("Font or glyph data not found for font %s-%s !\n", mFontFamily.c_str(), mFontStyle.c_str() );
201         return;
202       }
203
204       // cache the metrics to a cache
205       WriteMetricsToCache( *glyphs.Get() );
206
207       // cache the metrics in memory
208       AddGlyphSet( 0, *glyphs.Get() );
209     }
210   }
211 }
212
213 const GlyphMetric* FontMetrics::GetGlyph( uint32_t characterCode) const
214 {
215   TCharMap::const_iterator iter = mCharMap.find( characterCode );
216
217   if( iter != mCharMap.end())
218   {
219     return &iter->second;
220   }
221   else
222   {
223     // can and will happen if a glyph doesn't exist for the
224     // given character code
225     if(  characterCode  >= FIRST_NON_CONTROL_CHAR )
226     {
227         DALI_LOG_ERROR("failed to find character %lu\n", characterCode );
228     }
229     return NULL;
230   }
231 }
232
233 FontId FontMetrics::GetFontId() const
234 {
235   return mFontId;
236 }
237
238 const std::string& FontMetrics::GetFontFamilyName() const
239 {
240   return mFontFamily;
241 }
242
243 const std::string&  FontMetrics::GetFontStyleName() const
244 {
245   return mFontStyle;
246 }
247
248 void FontMetrics::GetMaximumGylphSize( float& width, float& height ) const
249 {
250   width = GetMaxWidth();
251   height = GetMaxHeight();
252 }
253
254 float FontMetrics::GetUnitsToPixels( const float pointSize ) const
255 {
256   return mFontLayout.GetUnitsToPixels( pointSize );
257 }
258
259 float FontMetrics::GetLineHeight() const
260 {
261   return mFontLayout.GetLineHeight();
262 }
263
264 float FontMetrics::GetAscender() const
265 {
266   return mFontLayout.GetAscender();
267 }
268
269 float FontMetrics::GetUnderlinePosition() const
270 {
271   return mFontLayout.GetUnderlinePosition();
272 }
273
274 float FontMetrics::GetUnderlineThickness() const
275 {
276   return mFontLayout.GetUnderlineThickness();
277 }
278
279 float FontMetrics::GetMaxWidth() const
280 {
281   return mFontLayout.GetMaxWidth();
282 }
283
284 float FontMetrics::GetMaxHeight() const
285 {
286   return mFontLayout.GetMaxHeight();
287 }
288
289 float FontMetrics::GetPadAdjustX() const
290 {
291   return mFontLayout.GetPadAdjustX();
292 }
293
294 float FontMetrics::GetPadAdjustY() const
295 {
296   return mFontLayout.GetPadAdjustY();
297 }
298
299
300 void FontMetrics::GetMetrics( const Dali::Character& character, Dali::Font::Metrics::Impl& metrics )
301 {
302   TextArray utfCodes;
303   utfCodes.push_back( character.GetImplementation().GetCharacter() );
304
305   LoadMetricsSynchronously( utfCodes );
306
307   const GlyphMetric* glyph;
308
309   glyph = GetGlyph( character.GetImplementation().GetCharacter() );
310
311   if( glyph )
312   {
313
314     metrics.advance = glyph->GetXAdvance();
315     metrics.bearing = glyph->GetTop();
316     metrics.width = std::max( glyph->GetWidth(), glyph->GetXAdvance() );
317     metrics.height = glyph->GetHeight();
318   }
319   else
320   {
321     metrics.advance = 0.0f;
322     metrics.bearing = 0.0f;
323     metrics.width = 0.0f;
324     metrics.height = 0.0f;
325   }
326 }
327
328 void FontMetrics::IncreaseFontCount()
329 {
330   mFontCount++;
331 }
332
333 void FontMetrics::DecreaseFontCount()
334 {
335   DALI_ASSERT_DEBUG( mFontCount != 0 );
336   mFontCount--;
337 }
338
339 unsigned int FontMetrics::GetFontUsageCount() const
340 {
341   return mFontCount;
342 }
343
344 // Called when a metric is loaded
345 void FontMetrics::AddGlyphSet( Integration::ResourceId id, const Integration::GlyphSet& glyphSet )
346 {
347   const Integration::GlyphSet::CharacterList& characterList = glyphSet.GetCharacterList();
348
349   for( Integration::GlyphSet::CharacterConstIter it = characterList.begin(), endIt = characterList.end(); it != endIt; ++it )
350   {
351     Integration::GlyphMetrics glyphMetrics( it->second );
352     // the map is used to retrieve character information when measuring a string
353     AddGlyphMetricToCache( glyphMetrics );
354   }
355 }
356
357 void FontMetrics::CheckMetricsLoaded()
358 {
359   if( mMetricsLoaded )
360   {
361     return;
362   }
363
364   // read the metrics from the cache
365   bool success = ReadMetricsFromCache();
366   if( !success )
367   {
368     // Create a new one
369     WriteGlobalMetricsToCache();
370
371     DALI_LOG_ERROR("metrics cache corrupted or older version found. New cache created. \n");
372   }
373
374   mMetricsLoaded = true;
375 }
376
377 bool FontMetrics::ReadGlobalMetricsFromCache( )
378 {
379   Integration::GlobalMetrics globalMetrics;
380
381   bool success = mPlatform.ReadGlobalMetricsFromCache( mFontFamily, mFontStyle, globalMetrics );
382   if( success )
383   {
384     mFontLayout.SetMetrics( globalMetrics );
385   }
386   return success;
387 }
388
389 void FontMetrics::WriteGlobalMetricsToCache()
390 {
391   mPlatform.WriteGlobalMetricsToCache( mFontFamily, mFontStyle, mFontLayout.GetGlobalMetrics() );
392 }
393
394
395 bool FontMetrics::ReadMetricsFromCache()
396 {
397   std::vector<Integration::GlyphMetrics> glyphMetricsContainer;
398
399   bool success = mPlatform.ReadMetricsFromCache( mFontFamily, mFontStyle, glyphMetricsContainer );
400   if( success )
401   {
402     for( std::size_t i=0, end=glyphMetricsContainer.size(); i<end; ++i )
403     {
404       AddGlyphMetricToCache( glyphMetricsContainer[i] );
405     }
406   }
407   return success;
408 }
409
410 void FontMetrics::WriteMetricsToCache( const Integration::GlyphSet& glyphSet )
411 {
412   mPlatform.WriteMetricsToCache( mFontFamily, mFontStyle, glyphSet );
413 }
414
415 FontMetrics::FontMetrics(const Vector2& dpi,
416                          const std::size_t hashValue,
417                          const FontId fontId,
418                          const std::string& fontFamily,
419                          const std::string& fontStyle )
420 :
421   mFontFamily(fontFamily),
422   mFontStyle(fontStyle),
423   mCharMap(),
424   mFontLayout(DEFAULT_UNITS_PER_EM, dpi),
425   mHash(hashValue),
426   mFontId(fontId),
427   mFontCount( 0 ),
428   mMetricsLoaded( false ),
429   mPlatform( ThreadLocalStorage::Get().GetPlatformAbstraction() )
430 {
431 }
432
433 FontMetrics::~FontMetrics()
434 {
435 }
436
437 void FontMetrics::AddGlyphMetricToCache( const Integration::GlyphMetrics& glyphMetric )
438 {
439   DALI_ASSERT_DEBUG( mCharMap.find(glyphMetric.code) == mCharMap.end() );
440
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).
444
445   GlyphMetric metric( glyphMetric.code,
446                       glyphMetric.width,
447                       glyphMetric.height,
448                       glyphMetric.top,
449                       glyphMetric.left,
450                       glyphMetric.xAdvance);
451
452   mCharMap[glyphMetric.code] = metric; // copy by value
453
454 }
455
456 } // namespace Internal
457
458 } // namespace Dali