License conversion from Flora to Apache 2.0
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / slp / data-cache / metrics-cache.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 "metrics-cache.h"
20
21 // EXTERNAL HEADERS
22 #include <iostream>
23 #include <fstream>
24 #include <string>
25 #include <algorithm>
26 #include <boost/functional/hash.hpp>
27 #include <string.h>
28
29 // INTERNAL HEADERS
30 #include <dali/integration-api/glyph-set.h>
31
32
33 namespace Dali
34 {
35
36 namespace // Anonymous namespace
37 {
38
39 const std::size_t VERSION_SIZE( sizeof(__DATE__ "-" __TIME__) );  // (date-time)
40 const char FILE_VERSION[ VERSION_SIZE ] =  __DATE__ "-" __TIME__; // Updates with each build
41
42 const size_t CHECKSUM_SIZE( sizeof( size_t ) );
43 const size_t NUMBER_GLOBAL_METRICS( 9 ); // line height, ascender, unitsPerEM, underlinePosition, underlineThickness, maxWidth, maxHeight, padAdjustX, padAdjustY
44 const size_t GLOBAL_METRICS_SIZE( NUMBER_GLOBAL_METRICS * sizeof( float ) );
45 const size_t GLOBAL_METRIC_HEADER_SIZE( GLOBAL_METRICS_SIZE + CHECKSUM_SIZE + VERSION_SIZE );
46 const std::string DALI_DEFAULT_FONT_CACHE_PATH( DALI_USER_FONT_CACHE_DIR );
47 const std::string METRICS_EXTENSION( ".metrics" );
48
49
50 std::string CreateFileName(std::string fontFamily, std::string fontStyle)
51 {
52   std::string cacheFileName(DALI_DEFAULT_FONT_CACHE_PATH + fontFamily + "-" + fontStyle + METRICS_EXTENSION);
53
54   std::replace(cacheFileName.begin(), cacheFileName.end(), ' ', '-' );
55   return cacheFileName;
56 }
57
58 std::size_t CalculateGlobalMetricCheckSum( const Integration::GlobalMetrics& globalMetrics )
59 {
60   int checksum = static_cast<int>( globalMetrics.lineHeight ) +
61                  static_cast<int>( globalMetrics.ascender )   +
62                  static_cast<int>( globalMetrics.unitsPerEM ) +
63                  static_cast<int>( globalMetrics.underlinePosition ) +
64                  static_cast<int>( globalMetrics.underlineThickness ) +
65                  static_cast<int>( globalMetrics.maxWidth ) +
66                  static_cast<int>( globalMetrics.maxHeight ) +
67                  static_cast<int>( globalMetrics.padAdjustX ) +
68                  static_cast<int>( globalMetrics.padAdjustY );
69
70
71   return boost::hash_value( checksum );
72
73 }
74
75 std::size_t CalculateGlyphCheckSum( const Integration::GlyphMetrics& metrics )
76 {
77   int checksum =  static_cast<int>( metrics.code )    +
78                   static_cast<int>( metrics.width )   +
79                   static_cast<int>( metrics.height )  +
80                   static_cast<int>( metrics.top )     +
81                   static_cast<int>( metrics.left )    +
82                   static_cast<int>( metrics.xAdvance);
83
84   return boost::hash_value( checksum );
85 }
86
87 bool ReadGlyphMetrics( std::ifstream& file,  Integration::GlyphMetrics& metrics )
88 {
89   std::size_t checkSumRead;
90   uint32_t code;
91
92   file.read( reinterpret_cast<char*>( &code ),         sizeof( uint32_t ) );
93   file.read( reinterpret_cast<char*>( &metrics.width ),   sizeof( float ) );
94   file.read( reinterpret_cast<char*>( &metrics.height ),  sizeof( float ) );
95   file.read( reinterpret_cast<char*>( &metrics.top ),     sizeof( float ) );
96   file.read( reinterpret_cast<char*>( &metrics.left ),    sizeof( float ) );
97   file.read( reinterpret_cast<char*>( &metrics.xAdvance), sizeof( float ) );
98   file.read( reinterpret_cast<char*>( &checkSumRead ),    sizeof( std::size_t ) );
99
100   metrics.code = code;  // code is now stored as a bit mask so we can't read directly in to it
101   metrics.quality = Integration::GlyphMetrics::LOW_QUALITY;
102
103   const std::size_t calcCheckSum = CalculateGlyphCheckSum( metrics );
104
105   return ( calcCheckSum == checkSumRead );
106 }
107
108 void WriteGlyphMetrics( std::ofstream& file, const Integration::GlyphMetrics& metrics )
109 {
110   uint32_t code = metrics.code; // code is stored as a bitmask so we can't write directly from it
111   file.write( reinterpret_cast<const char*>( &code ),     sizeof( uint32_t ) );
112   file.write( reinterpret_cast<const char*>( &metrics.width ),    sizeof( float ) );
113   file.write( reinterpret_cast<const char*>( &metrics.height ),   sizeof( float ) );
114   file.write( reinterpret_cast<const char*>( &metrics.top ),      sizeof( float ) );
115   file.write( reinterpret_cast<const char*>( &metrics.left ),     sizeof( float ) );
116   file.write( reinterpret_cast<const char*>( &metrics.xAdvance ), sizeof( float ) );
117
118   const std::size_t calcCheckSum = CalculateGlyphCheckSum( metrics );
119
120   file.write( reinterpret_cast<const char*>( &calcCheckSum ), sizeof( std::size_t ) );
121 }
122
123 bool ReadGlyphGlobalMetrics( std::ifstream& file, Integration::GlobalMetrics& globalMetrics )
124 {
125   char version_string[ VERSION_SIZE ];
126
127   // Check file version
128   file.read( version_string, VERSION_SIZE );
129   if( strncmp( version_string, FILE_VERSION, VERSION_SIZE ) != 0 )
130   {
131     return false;
132   }
133
134   std::size_t checkSumRead;
135
136   file.read( reinterpret_cast<char*>( &globalMetrics.lineHeight ), sizeof( float ) );
137   file.read( reinterpret_cast<char*>( &globalMetrics.ascender ), sizeof( float ) );
138   file.read( reinterpret_cast<char*>( &globalMetrics.unitsPerEM ), sizeof( float ) );
139   file.read( reinterpret_cast<char*>( &globalMetrics.underlinePosition ), sizeof( float ) );
140   file.read( reinterpret_cast<char*>( &globalMetrics.underlineThickness), sizeof( float ) );
141   file.read( reinterpret_cast<char*>( &globalMetrics.maxWidth), sizeof( float ) );
142   file.read( reinterpret_cast<char*>( &globalMetrics.maxHeight), sizeof( float ) );
143   file.read( reinterpret_cast<char*>( &globalMetrics.padAdjustX), sizeof( float ) );
144   file.read( reinterpret_cast<char*>( &globalMetrics.padAdjustY), sizeof( float ) );
145   file.read( reinterpret_cast<char*>( &checkSumRead ), sizeof( std::size_t ) );
146
147   const std::size_t calcCheckSum = CalculateGlobalMetricCheckSum( globalMetrics );
148
149   return (calcCheckSum == checkSumRead);
150 }
151
152 void WriteGlyphGlobalMetrics( std::ofstream &file, const Integration::GlobalMetrics& globalMetrics )
153 {
154   file.write( FILE_VERSION, VERSION_SIZE );
155
156   file.write( reinterpret_cast<const char*>( &globalMetrics.lineHeight ), sizeof( float ) );
157   file.write( reinterpret_cast<const char*>( &globalMetrics.ascender ), sizeof( float ) );
158   file.write( reinterpret_cast<const char*>( &globalMetrics.unitsPerEM ), sizeof( float ) );
159   file.write( reinterpret_cast<const char*>( &globalMetrics.underlinePosition ), sizeof( float ) );
160   file.write( reinterpret_cast<const char*>( &globalMetrics.underlineThickness), sizeof( float ) );
161   file.write( reinterpret_cast<const char*>( &globalMetrics.maxWidth), sizeof( float ) );
162   file.write( reinterpret_cast<const char*>( &globalMetrics.maxHeight), sizeof( float ) );
163   file.write( reinterpret_cast<const char*>( &globalMetrics.padAdjustX ), sizeof( float ) );
164   file.write( reinterpret_cast<const char*>( &globalMetrics.padAdjustY ), sizeof( float ) );
165
166   const std::size_t calcCheckSum = CalculateGlobalMetricCheckSum( globalMetrics );
167
168   file.write( reinterpret_cast<const char*>( &calcCheckSum ), sizeof( std::size_t ) );
169 }
170
171 } // Anonymous namespace
172
173 namespace SlpPlatform
174 {
175 namespace MetricsCache
176 {
177
178 bool ReadGlobal( std::string fontFamily, std::string fontStyle, Integration::GlobalMetrics& globalMetrics)
179 {
180   bool success = false;
181
182   std::string fileName = CreateFileName( fontFamily, fontStyle );
183
184   std::ifstream file( fileName.c_str(), std::ios::in | std::ios::binary );
185
186   if( file.good() )
187   {
188     file.seekg( std::ios::beg );
189
190     success = ReadGlyphGlobalMetrics( file, globalMetrics );
191
192     // check the metrics had the correct size.
193     // this is just incase the metrics file is the wrong size, but the checksum magically worked.
194     if( file.eof() )
195     {
196       // file.eof is true only after an invalid read
197       success = false;
198     }
199
200     file.close();
201   }
202
203   return success;
204 }
205
206 void WriteGlobal( std::string fontFamily, std::string fontStyle, const Integration::GlobalMetrics& globalMetrics)
207 {
208   std::string fileName = CreateFileName( fontFamily, fontStyle );
209   std::ios_base::openmode mode = ( std::ios::out | std::ios::binary | std::ios::trunc );
210
211   std::ofstream file( fileName.c_str(), mode );
212
213   if( file.good() )
214   {
215     WriteGlyphGlobalMetrics( file, globalMetrics );
216
217     file.close();
218   }
219 }
220
221 bool Read( std::string fontFamily, std::string fontStyle, std::vector<Integration::GlyphMetrics>& glyphMetricsContainer )
222 {
223   std::string fileName = CreateFileName( fontFamily, fontStyle );
224   bool success( false );
225
226   // Read from default glyph cache only when there is any metric loaded.
227   std::ifstream file( fileName.c_str(), std::ios::in | std::ios::binary );
228
229   if( file.good() )
230   {
231     // skip over the gobal metrics
232     file.seekg( GLOBAL_METRIC_HEADER_SIZE , std::ios::beg );
233
234     bool checkSumPassed(true);
235
236     // file.good() is set to false if end of file is reached, or an error occurred
237     while( checkSumPassed && file.good() )
238     {
239       Integration::GlyphMetrics glyphMetrics;
240
241       checkSumPassed = ReadGlyphMetrics( file, glyphMetrics );
242
243       // eof only returns true after a failed read
244       if( file.eof() )
245       {
246         // this will occur when we hit the end of the file.
247         checkSumPassed = true;
248         break;
249       }
250
251       if( checkSumPassed )
252       {
253         // fill the map with cached metrics.
254         glyphMetricsContainer.push_back(glyphMetrics);
255       }
256       else
257       {
258         DALI_LOG_WARNING("check sum failed for glyph %d in file \n", glyphMetrics.code, fileName.c_str() );
259       }
260     }
261
262     file.close();
263     success = checkSumPassed;
264   }
265
266   return success;
267 }
268
269 void Write( std::string fontFamily, std::string fontStyle, const Integration::GlyphSet& glyphSet )
270 {
271   // append the file.
272   std::string fileName = CreateFileName( fontFamily, fontStyle );
273   std::ofstream file( fileName.c_str(), std::ios::out | std::ios::binary | std::ios::app );
274
275   if( file.good() )
276   {
277     const Integration::GlyphSet::CharacterList& characterList = glyphSet.GetCharacterList();
278
279     for( Integration::GlyphSet::CharacterConstIter it = characterList.begin(), endIt = characterList.end(); it != endIt; ++it )
280     {
281       WriteGlyphMetrics( file, it->second );
282     }
283
284     file.close();
285   }
286   else
287   {
288     DALI_LOG_WARNING( "Failed to open metric to file %s", fileName.c_str() );
289   }
290 }
291
292
293 } // MetricsCache
294 } // SlpPlatform
295 } // Dali