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