2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "metrics-cache.h"
26 #include <boost/functional/hash.hpp>
30 #include <dali/integration-api/glyph-set.h>
36 namespace // Anonymous namespace
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
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" );
50 std::string CreateFileName(std::string fontFamily, std::string fontStyle)
52 std::string cacheFileName(DALI_DEFAULT_FONT_CACHE_PATH + fontFamily + "-" + fontStyle + METRICS_EXTENSION);
54 std::replace(cacheFileName.begin(), cacheFileName.end(), ' ', '-' );
58 std::size_t CalculateGlobalMetricCheckSum( const Integration::GlobalMetrics& globalMetrics )
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 );
71 return boost::hash_value( checksum );
75 std::size_t CalculateGlyphCheckSum( const Integration::GlyphMetrics& metrics )
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);
84 return boost::hash_value( checksum );
87 bool ReadGlyphMetrics( std::ifstream& file, Integration::GlyphMetrics& metrics )
89 std::size_t checkSumRead;
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 ) );
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;
103 const std::size_t calcCheckSum = CalculateGlyphCheckSum( metrics );
105 return ( calcCheckSum == checkSumRead );
108 void WriteGlyphMetrics( std::ofstream& file, const Integration::GlyphMetrics& metrics )
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 ) );
118 const std::size_t calcCheckSum = CalculateGlyphCheckSum( metrics );
120 file.write( reinterpret_cast<const char*>( &calcCheckSum ), sizeof( std::size_t ) );
123 bool ReadGlyphGlobalMetrics( std::ifstream& file, Integration::GlobalMetrics& globalMetrics )
125 char version_string[ VERSION_SIZE ];
127 // Check file version
128 file.read( version_string, VERSION_SIZE );
129 if( strncmp( version_string, FILE_VERSION, VERSION_SIZE ) != 0 )
134 std::size_t checkSumRead;
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 ) );
147 const std::size_t calcCheckSum = CalculateGlobalMetricCheckSum( globalMetrics );
149 return (calcCheckSum == checkSumRead);
152 void WriteGlyphGlobalMetrics( std::ofstream &file, const Integration::GlobalMetrics& globalMetrics )
154 file.write( FILE_VERSION, VERSION_SIZE );
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 ) );
166 const std::size_t calcCheckSum = CalculateGlobalMetricCheckSum( globalMetrics );
168 file.write( reinterpret_cast<const char*>( &calcCheckSum ), sizeof( std::size_t ) );
171 } // Anonymous namespace
173 namespace SlpPlatform
175 namespace MetricsCache
178 bool ReadGlobal( std::string fontFamily, std::string fontStyle, Integration::GlobalMetrics& globalMetrics)
180 bool success = false;
182 std::string fileName = CreateFileName( fontFamily, fontStyle );
184 std::ifstream file( fileName.c_str(), std::ios::in | std::ios::binary );
188 file.seekg( std::ios::beg );
190 success = ReadGlyphGlobalMetrics( file, globalMetrics );
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.
196 // file.eof is true only after an invalid read
206 void WriteGlobal( std::string fontFamily, std::string fontStyle, const Integration::GlobalMetrics& globalMetrics)
208 std::string fileName = CreateFileName( fontFamily, fontStyle );
209 std::ios_base::openmode mode = ( std::ios::out | std::ios::binary | std::ios::trunc );
211 std::ofstream file( fileName.c_str(), mode );
215 WriteGlyphGlobalMetrics( file, globalMetrics );
221 bool Read( std::string fontFamily, std::string fontStyle, std::vector<Integration::GlyphMetrics>& glyphMetricsContainer )
223 std::string fileName = CreateFileName( fontFamily, fontStyle );
224 bool success( false );
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 );
231 // skip over the gobal metrics
232 file.seekg( GLOBAL_METRIC_HEADER_SIZE , std::ios::beg );
234 bool checkSumPassed(true);
236 // file.good() is set to false if end of file is reached, or an error occurred
237 while( checkSumPassed && file.good() )
239 Integration::GlyphMetrics glyphMetrics;
241 checkSumPassed = ReadGlyphMetrics( file, glyphMetrics );
243 // eof only returns true after a failed read
246 // this will occur when we hit the end of the file.
247 checkSumPassed = true;
253 // fill the map with cached metrics.
254 glyphMetricsContainer.push_back(glyphMetrics);
258 DALI_LOG_WARNING("check sum failed for glyph %d in file \n", glyphMetrics.code, fileName.c_str() );
263 success = checkSumPassed;
269 void Write( std::string fontFamily, std::string fontStyle, const Integration::GlyphSet& glyphSet )
272 std::string fileName = CreateFileName( fontFamily, fontStyle );
273 std::ofstream file( fileName.c_str(), std::ios::out | std::ios::binary | std::ios::app );
277 const Integration::GlyphSet::CharacterList& characterList = glyphSet.GetCharacterList();
279 for( Integration::GlyphSet::CharacterConstIter it = characterList.begin(), endIt = characterList.end(); it != endIt; ++it )
281 WriteGlyphMetrics( file, it->second );
288 DALI_LOG_WARNING( "Failed to open metric to file %s", fileName.c_str() );