1 // Font.cpp: ActionScript Font handling, for Gnash.
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
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
29 #include "smart_ptr.h"
31 #include "ShapeRecord.h"
32 #include "DefineFontTag.h"
33 #include "FreetypeGlyphsProvider.h"
39 /// Reverse lookup of Glyph in CodeTable.
41 /// Inefficient, which is probably why TextSnapshot was designed like it
46 CodeLookup(const int glyph
) : _glyph(glyph
) {}
48 bool operator()(const std::pair
<const boost::uint16_t, int>& p
) const {
49 return p
.second
== _glyph
;
58 Font::GlyphInfo::GlyphInfo()
63 Font::GlyphInfo::GlyphInfo(std::auto_ptr
<SWF::ShapeRecord
> glyph
,
66 glyph(glyph
.release()),
70 Font::GlyphInfo::GlyphInfo(const GlyphInfo
& o
)
77 Font::Font(std::auto_ptr
<SWF::DefineFontTag
> ft
)
79 _fontTag(ft
.release()),
80 _name(_fontTag
->name()),
81 _unicodeChars(_fontTag
->unicodeChars()),
82 _shiftJISChars(_fontTag
->shiftJISChars()),
83 _ansiChars(_fontTag
->ansiChars()),
84 _italic(_fontTag
->italic()),
85 _bold(_fontTag
->bold())
87 if (_fontTag
->hasCodeTable()) {
88 _embeddedCodeTable
= _fontTag
->getCodeTable();
92 Font::Font(const std::string
& name
, bool bold
, bool italic
)
97 _shiftJISChars(false),
102 assert(!_name
.empty());
110 Font::get_glyph(int index
, bool embedded
) const
112 // What to do if embedded is true and this is a
114 const GlyphInfoRecords
& lookup
= (embedded
&& _fontTag
) ?
115 _fontTag
->glyphTable() : _deviceGlyphTable
;
117 if (index
>= 0 && (size_t)index
< lookup
.size()) {
118 return lookup
[index
].glyph
.get();
121 // TODO: should we log an error here ?
126 Font::addFontNameInfo(const FontNameInfo
& fontName
)
128 if (!_displayName
.empty() || !_copyrightName
.empty())
130 IF_VERBOSE_MALFORMED_SWF(
131 log_swferror(_("Attempt to set font display or copyright name "
132 "again. This should mean there is more than one "
133 "DefineFontName tag referring to the same Font. Don't "
134 "know what to do in this case, so ignoring."));
139 _displayName
= fontName
.displayName
;
140 _copyrightName
= fontName
.copyrightName
;
144 Font::GlyphInfoRecords::size_type
145 Font::glyphCount() const
148 return _fontTag
->glyphTable().size();
153 Font::setFlags(boost::uint8_t flags
)
155 _shiftJISChars
= flags
& (1 << 6);
156 _unicodeChars
= flags
& (1 << 5);
157 _ansiChars
= flags
& (1 << 4);
158 _italic
= flags
& (1 << 1);
159 _bold
= flags
& (1 << 0);
164 Font::setCodeTable(std::auto_ptr
<CodeTable
> table
)
166 if (_embeddedCodeTable
) {
167 IF_VERBOSE_MALFORMED_SWF(
168 log_swferror(_("Attempt to add an embedded glyph CodeTable to "
169 "a font that already has one. This should mean there "
170 "are several DefineFontInfo tags, or a DefineFontInfo "
171 "tag refers to a font created by DefineFone2 or "
172 "DefineFont3. Don't know what should happen in this "
173 "case, so ignoring."));
177 _embeddedCodeTable
.reset(table
.release());
182 Font::setName(const std::string
& name
)
189 Font::codeTableLookup(int glyph
, bool embedded
) const
191 const CodeTable
& ctable
= (embedded
&& _embeddedCodeTable
) ?
192 *_embeddedCodeTable
: _deviceCodeTable
;
194 CodeTable::const_iterator it
= std::find_if(ctable
.begin(), ctable
.end(),
197 if (it
== ctable
.end()) {
198 // NB: this occurs with a long and complex SWF (bug #32537)
199 // that defines the same font twice and ends up with a glyph
200 // table shorter than the number of glyphs. We don't know
201 // whether it's a SWF or a Gnash bug.
202 log_error("Failed to find glyph %s in %s font %s",
203 glyph
, embedded
? "embedded" : "device", _name
);
210 Font::get_glyph_index(boost::uint16_t code
, bool embedded
) const
212 const CodeTable
& ctable
= (embedded
&& _embeddedCodeTable
) ?
213 *_embeddedCodeTable
: _deviceCodeTable
;
215 int glyph_index
= -1;
216 CodeTable::const_iterator it
= ctable
.find(code
);
217 if (it
!= ctable
.end()) {
218 glyph_index
= it
->second
;
222 // Try adding an os font, if possible
224 glyph_index
= const_cast<Font
*>(this)->add_os_glyph(code
);
230 Font::get_advance(int glyph_index
, bool embedded
) const
232 // What to do if embedded is true and this is a
234 const GlyphInfoRecords
& lookup
= (embedded
&& _fontTag
) ?
235 _fontTag
->glyphTable() : _deviceGlyphTable
;
237 if (glyph_index
< 0) {
242 assert(static_cast<size_t>(glyph_index
) < lookup
.size());
243 assert(glyph_index
>= 0);
245 return lookup
[glyph_index
].advance
;
249 // Return the adjustment in advance between the given two
250 // DisplayObjects. Normally this will be 0; i.e. the
252 Font::get_kerning_adjustment(int last_code
, int code
) const
255 k
.m_char0
= last_code
;
257 kernings_table::const_iterator it
= m_kerning_pairs
.find(k
);
258 if (it
!= m_kerning_pairs
.end()) {
259 float adjustment
= it
->second
;
266 Font::unitsPerEM(bool embed
) const
268 // the EM square is 1024 x 1024 for DefineFont up to 2
269 // and 20 as much for DefineFont3 up
271 if ( _fontTag
&& _fontTag
->subpixelFont() ) return 1024 * 20.0;
275 FreetypeGlyphsProvider
* ft
= ftProvider();
277 log_error("Device font provider was not initialized, "
278 "can't get unitsPerEM");
282 return ft
->unitsPerEM();
286 Font::add_os_glyph(boost::uint16_t code
)
288 FreetypeGlyphsProvider
* ft
= ftProvider();
291 assert(_deviceCodeTable
.find(code
) == _deviceCodeTable
.end());
295 // Get the vectorial glyph
296 std::auto_ptr
<SWF::ShapeRecord
> sh
= ft
->getGlyph(code
, advance
);
299 log_error("Could not create shape "
300 "glyph for DisplayObject code %u (%c) with "
301 "device font %s (%p)", code
, code
, _name
, ft
);
305 // Find new glyph offset
306 int newOffset
= _deviceGlyphTable
.size();
308 // Add the new glyph id
309 _deviceCodeTable
[code
] = newOffset
;
311 _deviceGlyphTable
.push_back(GlyphInfo(sh
, advance
));
317 Font::matches(const std::string
& name
, bool bold
, bool italic
) const
319 return (_bold
== bold
&& _italic
== italic
&& name
==_name
);
323 Font::leading() const {
324 return _fontTag
? _fontTag
->leading() : 0.0f
;
327 FreetypeGlyphsProvider
*
328 Font::ftProvider() const
330 if (_ftProvider
.get()) return _ftProvider
.get();
333 log_error("No name associated with this font, can't use device "
334 "fonts (should I use a default one?)");
338 _ftProvider
= FreetypeGlyphsProvider::createFace(_name
, _bold
, _italic
);
340 if (!_ftProvider
.get()) {
341 log_error("Could not create a freetype face %s", _name
);
345 return _ftProvider
.get();
349 Font::ascent(bool embedded
) const
351 if (embedded
&& _fontTag
) return _fontTag
->ascent();
352 FreetypeGlyphsProvider
* ft
= ftProvider();
353 if (ft
) return ft
->ascent();
358 Font::descent(bool embedded
) const
360 if (embedded
&& _fontTag
) return _fontTag
->descent();
361 FreetypeGlyphsProvider
* ft
= ftProvider();
362 if (ft
) return ft
->descent();
370 // indent-tabs-mode: t