Merge "Combine Internal::ProxyObject & Internal::Object" into tizen
[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 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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
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
18 // CLASS HEADER
19 #include <dali/internal/event/text/font-metrics.h>
20
21 // EXTERNAL HEADERS
22
23 // INTERNAL INCLUDES
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>
34
35 namespace Dali
36 {
37 namespace Internal
38 {
39
40 namespace  //unnamed namespace
41 {
42
43 const float DEFAULT_UNITS_PER_EM( 1.f );
44
45 const uint32_t FIRST_NON_CONTROL_CHAR( 0x20 ); // 0x20 is the white space which is the first non control character.
46
47 Integration::TextArray GetUniqueCharacters( const Integration::TextArray& text )
48 {
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() );
53   return utfCodes;
54 }
55
56 } // unnamed namespace
57
58
59
60 FontMetricsIntrusivePtr FontMetrics::New( const Vector2& dpi,
61                                           const std::size_t hashValue,
62                                           const FontId fontId,
63                                           const std::string& fontFamily,
64                                           const std::string& fontStyle )
65 {
66   return new FontMetrics( dpi, hashValue, fontId, fontFamily, fontStyle );
67 }
68
69 void FontMetrics::LoadGlobalMetrics()
70 {
71   // Read global metrics synchronously.
72   bool success = ReadGlobalMetricsFromCache();
73
74   if( !success )
75   {
76     Dali::Integration::GlobalMetrics globalMetrics;
77
78     // Read global metrics from platform.
79     mPlatform.GetGlobalMetrics( mFontFamily, mFontStyle, globalMetrics );
80
81     // configure the metrics
82     mFontLayout.SetMetrics( globalMetrics );
83
84     // write the metrics to a cache
85     WriteGlobalMetricsToCache();
86   }
87 }
88
89 Vector3 FontMetrics::MeasureText( const Integration::TextArray& text )
90 {
91   if( 0u == text.Count() )
92   {
93     return  Vector3::ZERO;
94   }
95
96   Integration::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( Integration::TextArray::ConstIterator 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 Integration::TextArray& text ) const
135 {
136   TCharMap::const_iterator endIter = mCharMap.end();
137
138   for( Integration::TextArray::ConstIterator 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 Integration::TextArray& text, CharacterList& missingText ) const
153 {
154   // sort and remove duplicate character codes
155   Integration::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( Integration::TextArray::ConstIterator 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 Integration::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   Integration::TextArray utfCodes;
303   utfCodes.PushBack( 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
372   mMetricsLoaded = true;
373 }
374
375 bool FontMetrics::ReadGlobalMetricsFromCache( )
376 {
377   Integration::GlobalMetrics globalMetrics;
378
379   bool success = mPlatform.ReadGlobalMetricsFromCache( mFontFamily, mFontStyle, globalMetrics );
380   if( success )
381   {
382     mFontLayout.SetMetrics( globalMetrics );
383   }
384   return success;
385 }
386
387 void FontMetrics::WriteGlobalMetricsToCache()
388 {
389   mPlatform.WriteGlobalMetricsToCache( mFontFamily, mFontStyle, mFontLayout.GetGlobalMetrics() );
390 }
391
392
393 bool FontMetrics::ReadMetricsFromCache()
394 {
395   std::vector<Integration::GlyphMetrics> glyphMetricsContainer;
396
397   bool success = mPlatform.ReadMetricsFromCache( mFontFamily, mFontStyle, glyphMetricsContainer );
398   if( success )
399   {
400     for( std::size_t i=0, end=glyphMetricsContainer.size(); i<end; ++i )
401     {
402       AddGlyphMetricToCache( glyphMetricsContainer[i] );
403     }
404   }
405   return success;
406 }
407
408 void FontMetrics::WriteMetricsToCache( const Integration::GlyphSet& glyphSet )
409 {
410   mPlatform.WriteMetricsToCache( mFontFamily, mFontStyle, glyphSet );
411 }
412
413 FontMetrics::FontMetrics(const Vector2& dpi,
414                          const std::size_t hashValue,
415                          const FontId fontId,
416                          const std::string& fontFamily,
417                          const std::string& fontStyle )
418 :
419   mFontFamily(fontFamily),
420   mFontStyle(fontStyle),
421   mCharMap(),
422   mFontLayout(DEFAULT_UNITS_PER_EM, dpi),
423   mHash(hashValue),
424   mFontId(fontId),
425   mFontCount( 0 ),
426   mMetricsLoaded( false ),
427   mPlatform( ThreadLocalStorage::Get().GetPlatformAbstraction() )
428 {
429 }
430
431 FontMetrics::~FontMetrics()
432 {
433 }
434
435 void FontMetrics::AddGlyphMetricToCache( const Integration::GlyphMetrics& glyphMetric )
436 {
437   DALI_ASSERT_DEBUG( mCharMap.find(glyphMetric.code) == mCharMap.end() );
438
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).
442
443   GlyphMetric metric( glyphMetric.code,
444                       glyphMetric.width,
445                       glyphMetric.height,
446                       glyphMetric.top,
447                       glyphMetric.left,
448                       glyphMetric.xAdvance);
449
450   mCharMap[glyphMetric.code] = metric; // copy by value
451
452 }
453
454 } // namespace Internal
455
456 } // namespace Dali