1 // Font.cpp: ActionScript Font handling, for Gnash.
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 // Based on the public domain work of Thatcher Ulrich <tu@tulrich.com> 2003
24 #include "smart_ptr.h"
27 #include "ShapeRecord.h"
28 #include "DefineFontTag.h"
29 #include "FreetypeGlyphsProvider.h"
31 #include <utility> // for std::make_pair
38 /// Reverse lookup of Glyph in CodeTable.
40 /// Inefficient, which is probably why TextSnapshot was designed like it
45 CodeLookup(const int glyph
) : _glyph(glyph
) {}
47 bool operator()(const std::pair
<const boost::uint16_t, int>& p
) {
48 return p
.second
== _glyph
;
57 Font::GlyphInfo::GlyphInfo()
62 Font::GlyphInfo::GlyphInfo(std::auto_ptr
<SWF::ShapeRecord
> glyph
,
65 glyph(glyph
.release()),
69 Font::GlyphInfo::GlyphInfo(const GlyphInfo
& o
)
76 Font::Font(std::auto_ptr
<SWF::DefineFontTag
> ft
)
78 _fontTag(ft
.release()),
79 _name(_fontTag
->name()),
80 _unicodeChars(_fontTag
->unicodeChars()),
81 _shiftJISChars(_fontTag
->shiftJISChars()),
82 _ansiChars(_fontTag
->ansiChars()),
83 _italic(_fontTag
->italic()),
84 _bold(_fontTag
->bold())
86 if (_fontTag
->hasCodeTable()) _embeddedCodeTable
= _fontTag
->getCodeTable();
89 Font::Font(const std::string
& name
, bool bold
, bool italic
)
94 _shiftJISChars(false),
99 assert(!_name
.empty());
107 Font::get_glyph(int index
, bool embedded
) const
109 // What to do if embedded is true and this is a
111 const GlyphInfoRecords
& lookup
= (embedded
&& _fontTag
) ?
112 _fontTag
->glyphTable() : _deviceGlyphTable
;
114 if (index
>= 0 && (size_t)index
< lookup
.size()) {
115 return lookup
[index
].glyph
.get();
118 // TODO: should we log an error here ?
123 Font::addFontNameInfo(const FontNameInfo
& fontName
)
125 if (!_displayName
.empty() || !_copyrightName
.empty())
127 IF_VERBOSE_MALFORMED_SWF(
128 log_swferror(_("Attempt to set font display or copyright name "
129 "again. This should mean there is more than one "
130 "DefineFontName tag referring to the same Font. Don't "
131 "know what to do in this case, so ignoring."));
136 _displayName
= fontName
.displayName
;
137 _copyrightName
= fontName
.copyrightName
;
141 Font::GlyphInfoRecords::size_type
142 Font::glyphCount() const
145 return _fontTag
->glyphTable().size();
150 Font::setFlags(boost::uint8_t flags
)
152 _shiftJISChars
= flags
& (1 << 6);
153 _unicodeChars
= flags
& (1 << 5);
154 _ansiChars
= flags
& (1 << 4);
155 _italic
= flags
& (1 << 1);
156 _bold
= flags
& (1 << 0);
161 Font::setCodeTable(std::auto_ptr
<CodeTable
> table
)
163 if (_embeddedCodeTable
)
165 IF_VERBOSE_MALFORMED_SWF(
166 log_swferror(_("Attempt to add an embedded glyph CodeTable to "
167 "a font that already has one. This should mean there "
168 "are several DefineFontInfo tags, or a DefineFontInfo "
169 "tag refers to a font created by DefineFone2 or "
170 "DefineFont3. Don't know what should happen in this "
171 "case, so ignoring."));
175 _embeddedCodeTable
.reset(table
.release());
180 Font::setName(const std::string
& name
)
187 Font::codeTableLookup(int glyph
, bool embedded
) const
189 const CodeTable
& ctable
= (embedded
&& _embeddedCodeTable
) ?
190 *_embeddedCodeTable
: _deviceCodeTable
;
192 CodeTable::const_iterator it
= std::find_if(ctable
.begin(), ctable
.end(),
194 assert (it
!= ctable
.end());
199 Font::get_glyph_index(boost::uint16_t code
, bool embedded
) const
201 const CodeTable
& ctable
= (embedded
&& _embeddedCodeTable
) ?
202 *_embeddedCodeTable
: _deviceCodeTable
;
204 int glyph_index
= -1;
205 CodeTable::const_iterator it
= ctable
.find(code
);
206 if (it
!= ctable
.end()) {
207 glyph_index
= it
->second
;
211 // Try adding an os font, if possible
213 glyph_index
= const_cast<Font
*>(this)->add_os_glyph(code
);
219 Font::get_advance(int glyph_index
, bool embedded
) const
221 // What to do if embedded is true and this is a
223 const GlyphInfoRecords
& lookup
= (embedded
&& _fontTag
) ?
224 _fontTag
->glyphTable() : _deviceGlyphTable
;
226 if (glyph_index
< 0) {
231 assert(static_cast<size_t>(glyph_index
) < lookup
.size());
232 assert(glyph_index
>= 0);
234 return lookup
[glyph_index
].advance
;
238 // Return the adjustment in advance between the given two
239 // DisplayObjects. Normally this will be 0; i.e. the
241 Font::get_kerning_adjustment(int last_code
, int code
) const
244 k
.m_char0
= last_code
;
246 kernings_table::const_iterator it
= m_kerning_pairs
.find(k
);
247 if (it
!= m_kerning_pairs
.end()) {
248 float adjustment
= it
->second
;
255 Font::unitsPerEM(bool embed
) const
257 // the EM square is 1024 x 1024 for DefineFont up to 2
258 // and 20 as much for DefineFont3 up
260 if ( _fontTag
&& _fontTag
->subpixelFont() ) return 1024 * 20.0;
264 FreetypeGlyphsProvider
* ft
= ftProvider();
266 log_error("Device font provider was not initialized, "
267 "can't get unitsPerEM");
271 return ft
->unitsPerEM();
275 Font::add_os_glyph(boost::uint16_t code
)
277 FreetypeGlyphsProvider
* ft
= ftProvider();
280 assert(_deviceCodeTable
.find(code
) == _deviceCodeTable
.end());
284 // Get the vectorial glyph
285 std::auto_ptr
<SWF::ShapeRecord
> sh
= ft
->getGlyph(code
, advance
);
288 log_error("Could not create shape "
289 "glyph for DisplayObject code %u (%c) with "
290 "device font %s (%p)", code
, code
, _name
, ft
);
294 // Find new glyph offset
295 int newOffset
= _deviceGlyphTable
.size();
297 // Add the new glyph id
298 _deviceCodeTable
[code
] = newOffset
;
300 _deviceGlyphTable
.push_back(GlyphInfo(sh
, advance
));
306 Font::matches(const std::string
& name
, bool bold
, bool italic
) const
308 return (_bold
== bold
&& _italic
== italic
&& name
==_name
);
312 Font::leading() const {
313 return _fontTag
? _fontTag
->leading() : 0.0f
;
316 FreetypeGlyphsProvider
*
317 Font::ftProvider() const
319 if (_ftProvider
.get()) return _ftProvider
.get();
322 log_error("No name associated with this font, can't use device "
323 "fonts (should I use a default one?)");
327 _ftProvider
= FreetypeGlyphsProvider::createFace(_name
, _bold
, _italic
);
329 if (!_ftProvider
.get()) {
330 log_error("Could not create a freetype face %s", _name
);
334 return _ftProvider
.get();
338 Font::ascent(bool embedded
) const
340 if (embedded
&& _fontTag
) return _fontTag
->ascent();
341 FreetypeGlyphsProvider
* ft
= ftProvider();
342 if (ft
) return ft
->ascent();
347 Font::descent(bool embedded
) const
349 if (embedded
&& _fontTag
) return _fontTag
->descent();
350 FreetypeGlyphsProvider
* ft
= ftProvider();
351 if (ft
) return ft
->descent();
359 // indent-tabs-mode: t