Update suitable examples and tests to use blank mode
[shapes.git] / source / fontmetrics.cc
blob5491b4edac88e19c27e39f79c6907c39520b3a88
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include "fontmetrics.h"
20 #include "strrefdup.h"
21 #include "shapesexceptions.h"
24 FontMetrics::CharacterMetrics::~CharacterMetrics( )
26 if( ligatureSetupMap_ != 0 )
28 delete ligatureSetupMap_;
32 bool
33 FontMetrics::CharacterMetrics::isEmpty( ) const
35 return xmax_ == 0 && ymax_ == 0&& xmin_ == 0 && ymin_ == 0;
38 bool
39 FontMetrics::CharacterMetrics::hasLigature( size_t otherInternalPosition, size_t * ligatureInternalPosition ) const
41 typedef typeof( ligatures_ ) MapType;
42 MapType::const_iterator i = ligatures_.find( otherInternalPosition );
43 if( i == ligatures_.end( ) )
45 return false;
47 *ligatureInternalPosition = i->second;
48 return true;
51 void
52 FontMetrics::CharacterMetrics::addLigature( RefCountPtr< const char > otherName, RefCountPtr< const char > ligatureName )
54 typedef typeof( *ligatureSetupMap_ ) MapType;
55 if( ligatureSetupMap_ == 0 )
57 ligatureSetupMap_ = new MapType;;
59 ligatureSetupMap_->insert( MapType::value_type( otherName, ligatureName ) );
62 void
63 FontMetrics::CharacterMetrics::setupLigatures( const std::map< RefCountPtr< const char >, size_t, charRefPtrLess > & nameMap ) const
65 if( ligatureSetupMap_ == 0 )
67 return;
70 typedef typeof( *ligatureSetupMap_ ) MapType;
71 typedef typeof( nameMap ) NameMapType;
72 for( MapType::const_iterator i = ligatureSetupMap_->begin( ); i != ligatureSetupMap_->end( ); ++i )
74 NameMapType::const_iterator iFirst = nameMap.find( i->first );
75 NameMapType::const_iterator iSecond = nameMap.find( i->second );
76 if( iFirst == nameMap.end( ) || iSecond == nameMap.end( ) )
78 throw strrefdup( "Font metrics ligature uses undefined character name." );
80 ligatures_[ iFirst->second ] = iSecond->second;
83 delete ligatureSetupMap_;
84 ligatureSetupMap_ = 0;
87 void
88 FontMetrics::CharacterMetrics::display( std::ostream & os ) const
90 os << "[" << internalPosition_ << "] "
91 << " C " << characterCode_ << ";"
92 << " W0 " << horizontalCharWidthX_ << " " << horizontalCharWidthY_ << ";"
93 << " B " << xmin_ << " " << ymin_ << " " << xmax_ << " " << ymax_ << ";" ;
96 FontMetrics::WritingDirectionMetrics::WritingDirectionMetrics( )
97 { }
99 FontMetrics::WritingDirectionMetrics::~WritingDirectionMetrics( )
102 FontMetrics::SingleByte_WritingDirectionMetrics::SingleByte_WritingDirectionMetrics( )
104 // charData_ begins with a default entry. This makes it possible to use 0 for "undefined" in codeMap_.
105 FontMetrics::CharacterMetrics * defaultChar = new FontMetrics::CharacterMetrics( charData_.size( ) );
106 charData_.push_back( defaultChar );
107 // The values of defaultChar are not set here, since we need both horizontal and vertical information for that.
109 codeMap_.resize( 256, 0 );
112 FontMetrics::SingleByte_WritingDirectionMetrics::~SingleByte_WritingDirectionMetrics( )
115 void
116 FontMetrics::SingleByte_WritingDirectionMetrics::setupLigatures( )
118 typedef typeof( charData_ ) ListType;
119 for( ListType::iterator i = charData_.begin( ); i != charData_.end( ); ++i )
121 (*i)->setupLigatures( nameMap_ );
125 const FontMetrics::CharacterMetrics *
126 FontMetrics::SingleByte_WritingDirectionMetrics::charByName( const char * name ) const
128 typedef typeof( nameMap_ ) NameMapType;
129 NameMapType::const_iterator i = nameMap_.find( strrefdup( name ) );
130 if( i == nameMap_.end( ) )
132 throw "No character by that name in font metrics.";
134 return charData_[ i->second ];
137 const FontMetrics::CharacterMetrics *
138 FontMetrics::SingleByte_WritingDirectionMetrics::charByCode_MacRoman( unsigned char code ) const
140 return charData_[ codeMap_[ code ] ];
143 const FontMetrics::CharacterMetrics *
144 FontMetrics::SingleByte_WritingDirectionMetrics::charByCode( Shapes::Kernel::UnicodeCodePoint code, FontMetrics::CharacterMetrics * mem ) const
146 return charByCode_MacRoman( code.get_MacRoman( ) );
149 const FontMetrics::CharacterMetrics *
150 FontMetrics::SingleByte_WritingDirectionMetrics::default_char( ) const
152 return charByCode_MacRoman( 0 );
156 void
157 FontMetrics::SingleByte_WritingDirectionMetrics::display( std::ostream & os ) const
159 typedef typeof( nameMap_ ) NameMapType;
160 for( NameMapType::const_iterator i = nameMap_.begin( ); i != nameMap_.end( ); ++i )
162 os << "\"" << i->first << "\" " ;
163 charData_[ i->second ]->display( os );
164 os << std::endl ;
168 FontMetrics::TrackKerning::TrackKerning( double sizeLow, double trackLow, double sizeHigh, double trackHigh )
169 : sizeLow_( sizeLow ), trackLow_( trackLow ), sizeHigh_( sizeHigh ), trackHigh_( trackHigh )
172 double
173 FontMetrics::TrackKerning::operator () ( double sz ) const
175 if( sz < sizeLow_ )
177 return trackLow_;
179 if( sz > sizeHigh_ )
181 return trackHigh_;
183 return trackLow_ + ( ( sz - sizeLow_ ) / ( sizeHigh_ - sizeLow_ ) ) * ( trackHigh_ - trackLow_ );
186 FontMetrics::FontMetric::~FontMetric( )
189 FontMetrics::AFM::AFM( )
190 : FontMetric( false ),
191 version_( NullPtr< const char >( ) ),
192 notice_( NullPtr< const char >( ) ),
193 encodingScheme_( NullPtr< const char >( ) ),
194 characterSet_( NullPtr< const char >( ) ),
195 isFixedV_( false )
197 hasKerning_ = true;
200 FontMetrics::AFM::~AFM( )
203 double
204 FontMetrics::AFM::getHorizontalKernPairXByCode( Shapes::Kernel::UnicodeCodePoint code1, Shapes::Kernel::UnicodeCodePoint code2 ) const
206 KernPairMap::const_iterator i = horizontalKernPairsX_.find( KernPairMap::key_type( code1, code2 ) );
207 if( i == horizontalKernPairsX_.end( ) )
209 return 0;
211 return i->second;
214 #ifdef HAVE_FT2
216 FontMetrics::FreeType2_Metric::FreeType2_Metric( FT_Face face )
217 : FontMetric( true ),
218 face_( face ),
219 font_unit_( 1 / static_cast< double >( face_->units_per_EM ) )
221 familyName_ = strrefdup( face->family_name );
222 if( face->style_name != 0 )
224 weight_ = strrefdup( face->style_name );
225 std::ostringstream oss;
226 oss << face->family_name << "-" << face->style_name ;
227 fontName_ = strrefdup( oss );
229 else
231 weight_ = strrefdup( "" );
232 fontName_ = familyName_;
234 fullName_ = fontName_;
236 fontBBoxXMin_ = face->bbox.xMin * font_unit_;
237 fontBBoxYMin_ = face->bbox.yMin * font_unit_;
238 fontBBoxXMax_ = face->bbox.xMax * font_unit_;
239 fontBBoxYMax_ = face->bbox.yMax * font_unit_;
241 ascender_ = face->ascender * font_unit_;
242 descender_ = face->descender * font_unit_;
243 leading_ = face->height * font_unit_;
245 if( FT_HAS_HORIZONTAL( face ) )
247 horizontalMetrics_ = RefCountPtr< FontMetrics::FreeType2_WritingDirectionMetrics >( new FontMetrics::FreeType2_WritingDirectionMetrics( face, *this, false ) );
249 if( FT_HAS_VERTICAL( face ) )
251 verticalMetrics_ = RefCountPtr< FontMetrics::FreeType2_WritingDirectionMetrics >( new FontMetrics::FreeType2_WritingDirectionMetrics( face, *this, true ) );
254 #ifdef HAVE_FT2_10
255 isCIDFont_ = FT_IS_CID_KEYED( face_ ); /* I can't see why we should care about this value. */
256 hasKerning_ = FT_HAS_KERNING( face_ );
257 #else
258 isCIDFont_ = false;
259 hasKerning_ = false;
260 #endif
263 FontMetrics::FreeType2_Metric::~FreeType2_Metric( )
266 double
267 FontMetrics::FreeType2_Metric::getHorizontalKernPairXByCode( Shapes::Kernel::UnicodeCodePoint code1, Shapes::Kernel::UnicodeCodePoint code2 ) const
269 if( ! FT_HAS_KERNING( face_ ) )
271 throw Shapes::Exceptions::OutOfRange( "FreeType says that the current font does not support automatic kerning." );
273 FT_Vector k;
274 FT_Error error = FT_Get_Kerning( face_, FT_Get_Char_Index( face_, code1.get_UCS4( ) ), FT_Get_Char_Index( face_, code2.get_UCS4( ) ),
275 FT_KERNING_UNSCALED, & k );
276 if( error != 0 )
278 std::ostringstream msg;
279 msg << "Unable obtain kern value from FreeType, between code point " << code1.get_UCS4( ) << " and code point " << code2.get_UCS4( ) ;
280 throw Shapes::Exceptions::ExternalError( strrefdup( msg ) );
282 return k.x * font_unit_;
285 FontMetrics::FreeType2_WritingDirectionMetrics::FreeType2_WritingDirectionMetrics( FT_Face face, const FontMetric & parent, bool vertical )
286 : face_( face ),
287 default_char_( 0 ),
288 vertical_( vertical ),
289 font_unit_( 1 / static_cast< double >( face_->units_per_EM ) )
291 default_char_.horizontalCharWidthX_ = parent.fontBBoxXMax_ - parent.fontBBoxXMin_;
292 default_char_.horizontalCharWidthY_ = parent.fontBBoxYMax_ - parent.fontBBoxYMin_;
293 default_char_.verticalCharWidthX_ = parent.fontBBoxXMax_ - parent.fontBBoxXMin_;
294 default_char_.verticalCharWidthY_ = parent.fontBBoxYMax_ - parent.fontBBoxYMin_;
295 default_char_.xmin_ = parent.fontBBoxXMin_;
296 default_char_.ymin_ = parent.fontBBoxYMin_;
297 default_char_.xmax_ = parent.fontBBoxXMax_;
298 default_char_.ymax_ = parent.fontBBoxYMax_;
299 default_char_.vX_ = 0; /* What is this?! */
300 default_char_.vY_ = 0; /* What is this?! */
303 FontMetrics::FreeType2_WritingDirectionMetrics::~FreeType2_WritingDirectionMetrics( )
306 const FontMetrics::CharacterMetrics *
307 FontMetrics::FreeType2_WritingDirectionMetrics::charByCode( Shapes::Kernel::UnicodeCodePoint code, FontMetrics::CharacterMetrics * mem ) const
309 FT_UInt index = FT_Get_Char_Index( face_, code.get_UCS4( ) );
310 if( index == 0 )
312 return & default_char_;
314 FT_Error error = FT_Load_Glyph( face_, index, FT_LOAD_NO_SCALE );
315 if( error != 0 )
317 std::ostringstream msg;
318 msg << "Unable to load glyph in FreeType, at code point " << code.get_UCS4( ) ;
319 throw Shapes::Exceptions::OutOfRange( strrefdup( msg ) );
321 FT_Glyph_Metrics m = face_->glyph->metrics;
322 if( vertical_ )
324 mem->xmin_ = m.vertBearingX * font_unit_;
325 mem->ymax_ = m.vertBearingY * font_unit_;
326 mem->xmax_ = mem->xmin_ + m.width * font_unit_;
327 mem->ymin_ = mem->ymax_ - m.height * font_unit_;
328 mem->verticalCharWidthY_ = m.vertAdvance * font_unit_;
330 else
332 mem->xmin_ = m.horiBearingX * font_unit_;
333 mem->ymax_ = m.horiBearingY * font_unit_;
334 mem->xmax_ = mem->xmin_ + m.width * font_unit_;
335 mem->ymin_ = mem->ymax_ - m.height * font_unit_;
336 mem->horizontalCharWidthX_ = m.horiAdvance * font_unit_;
338 return mem;
341 const FontMetrics::CharacterMetrics *
342 FontMetrics::FreeType2_WritingDirectionMetrics::default_char( ) const
344 return & default_char_;
347 #endif