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
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_
;
33 FontMetrics::CharacterMetrics::isEmpty( ) const
35 return xmax_
== 0 && ymax_
== 0&& xmin_
== 0 && ymin_
== 0;
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( ) )
47 *ligatureInternalPosition
= i
->second
;
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
) );
63 FontMetrics::CharacterMetrics::setupLigatures( const std::map
< RefCountPtr
< const char >, size_t, charRefPtrLess
> & nameMap
) const
65 if( ligatureSetupMap_
== 0 )
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;
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( )
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( )
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 );
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
);
168 FontMetrics::TrackKerning::TrackKerning( double sizeLow
, double trackLow
, double sizeHigh
, double trackHigh
)
169 : sizeLow_( sizeLow
), trackLow_( trackLow
), sizeHigh_( sizeHigh
), trackHigh_( trackHigh
)
173 FontMetrics::TrackKerning::operator () ( double sz
) const
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 >( ) ),
200 FontMetrics::AFM::~AFM( )
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( ) )
216 FontMetrics::FreeType2_Metric::FreeType2_Metric( FT_Face face
)
217 : FontMetric( true ),
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
);
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 ) );
255 isCIDFont_
= FT_IS_CID_KEYED( face_
); /* I can't see why we should care about this value. */
256 hasKerning_
= FT_HAS_KERNING( face_
);
263 FontMetrics::FreeType2_Metric::~FreeType2_Metric( )
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." );
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
);
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
)
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( ) );
312 return & default_char_
;
314 FT_Error error
= FT_Load_Glyph( face_
, index
, FT_LOAD_NO_SCALE
);
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
;
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_
;
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_
;
341 const FontMetrics::CharacterMetrics
*
342 FontMetrics::FreeType2_WritingDirectionMetrics::default_char( ) const
344 return & default_char_
;