1 // Font.cpp: ActionScript Font handling, for Gnash.
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // 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
30 #include "ShapeRecord.h"
31 #include "DefineFontTag.h"
32 #include "FreetypeGlyphsProvider.h"
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 std::uint16_t, int>& p
) const {
48 return p
.second
== _glyph
;
57 Font::GlyphInfo::GlyphInfo()
62 Font::GlyphInfo::GlyphInfo(std::unique_ptr
<SWF::ShapeRecord
> the_glyph
,
65 glyph(std::move(the_glyph
)),
69 Font::Font(std::unique_ptr
<SWF::DefineFontTag
> ft
)
71 _fontTag(ft
.release()),
72 _name(_fontTag
->name()),
73 _unicodeChars(_fontTag
->unicodeChars()),
74 _shiftJISChars(_fontTag
->shiftJISChars()),
75 _ansiChars(_fontTag
->ansiChars()),
76 _italic(_fontTag
->italic()),
77 _bold(_fontTag
->bold())
79 if (_fontTag
->hasCodeTable()) {
80 _embeddedCodeTable
= _fontTag
->getCodeTable();
84 Font::Font(std::string name
, bool bold
, bool italic
)
86 _name(std::move(name
)),
88 _shiftJISChars(false),
93 assert(!_name
.empty());
101 Font::get_glyph(int index
, bool embedded
) const
103 // What to do if embedded is true and this is a
105 const GlyphInfoRecords
& lookup
= (embedded
&& _fontTag
) ?
106 _fontTag
->glyphTable() : _deviceGlyphTable
;
108 if (index
>= 0 && (size_t)index
< lookup
.size()) {
109 return lookup
[index
].glyph
.get();
112 // TODO: should we log an error here ?
117 Font::addFontNameInfo(const FontNameInfo
& fontName
)
119 if (!_displayName
.empty() || !_copyrightName
.empty())
121 IF_VERBOSE_MALFORMED_SWF(
122 log_swferror(_("Attempt to set font display or copyright name "
123 "again. This should mean there is more than one "
124 "DefineFontName tag referring to the same Font. Don't "
125 "know what to do in this case, so ignoring."));
130 _displayName
= fontName
.displayName
;
131 _copyrightName
= fontName
.copyrightName
;
135 Font::GlyphInfoRecords::size_type
136 Font::glyphCount() const
139 return _fontTag
->glyphTable().size();
144 Font::setFlags(std::uint8_t flags
)
146 _shiftJISChars
= flags
& (1 << 6);
147 _unicodeChars
= flags
& (1 << 5);
148 _ansiChars
= flags
& (1 << 4);
149 _italic
= flags
& (1 << 1);
150 _bold
= flags
& (1 << 0);
155 Font::setCodeTable(std::unique_ptr
<CodeTable
> table
)
157 if (_embeddedCodeTable
) {
158 IF_VERBOSE_MALFORMED_SWF(
159 log_swferror(_("Attempt to add an embedded glyph CodeTable to "
160 "a font that already has one. This should mean there "
161 "are several DefineFontInfo tags, or a DefineFontInfo "
162 "tag refers to a font created by DefineFont2 or "
163 "DefineFont3. Don't know what should happen in this "
164 "case, so ignoring."));
168 _embeddedCodeTable
.reset(table
.release());
173 Font::setName(const std::string
& name
)
180 Font::codeTableLookup(int glyph
, bool embedded
) const
182 const CodeTable
& ctable
= (embedded
&& _embeddedCodeTable
) ?
183 *_embeddedCodeTable
: _deviceCodeTable
;
185 CodeTable::const_iterator it
= std::find_if(ctable
.begin(), ctable
.end(),
188 if (it
== ctable
.end()) {
189 // NB: this occurs with a long and complex SWF (bug #32537)
190 // that defines the same font twice and ends up with a glyph
191 // table shorter than the number of glyphs. We don't know
192 // whether it's a SWF or a Gnash bug.
193 log_error(_("Failed to find glyph %s in %s font %s"),
194 glyph
, embedded
? "embedded" : "device", _name
);
201 Font::get_glyph_index(std::uint16_t code
, bool embedded
) const
203 const CodeTable
& ctable
= (embedded
&& _embeddedCodeTable
) ?
204 *_embeddedCodeTable
: _deviceCodeTable
;
206 int glyph_index
= -1;
207 CodeTable::const_iterator it
= ctable
.find(code
);
208 if (it
!= ctable
.end()) {
209 glyph_index
= it
->second
;
213 // Try adding an os font, if possible
215 glyph_index
= const_cast<Font
*>(this)->add_os_glyph(code
);
221 Font::get_advance(int glyph_index
, bool embedded
) const
223 // What to do if embedded is true and this is a
225 const GlyphInfoRecords
& lookup
= (embedded
&& _fontTag
) ?
226 _fontTag
->glyphTable() : _deviceGlyphTable
;
228 if (glyph_index
< 0) {
233 assert(static_cast<size_t>(glyph_index
) < lookup
.size());
234 assert(glyph_index
>= 0);
236 return lookup
[glyph_index
].advance
;
240 // Return the adjustment in advance between the given two
241 // DisplayObjects. Normally this will be 0; i.e. the
243 Font::get_kerning_adjustment(int last_code
, int code
) const
246 k
.m_char0
= last_code
;
248 kernings_table::const_iterator it
= m_kerning_pairs
.find(k
);
249 if (it
!= m_kerning_pairs
.end()) {
250 float adjustment
= it
->second
;
257 Font::unitsPerEM(bool embed
) const
259 // the EM square is 1024 x 1024 for DefineFont up to 2
260 // and 20 as much for DefineFont3 up
262 if ( _fontTag
&& _fontTag
->subpixelFont() ) return 1024 * 20.0;
266 FreetypeGlyphsProvider
* ft
= ftProvider();
268 log_error(_("Device font provider was not initialized, "
269 "can't get unitsPerEM"));
273 return ft
->unitsPerEM();
277 Font::add_os_glyph(std::uint16_t code
)
279 FreetypeGlyphsProvider
* ft
= ftProvider();
282 assert(_deviceCodeTable
.find(code
) == _deviceCodeTable
.end());
286 // Get the vectorial glyph
287 std::unique_ptr
<SWF::ShapeRecord
> sh
= ft
->getGlyph(code
, advance
);
290 log_error(_("Could not create shape "
291 "glyph for DisplayObject code %u (%c) with "
292 "device font %s (%p)"), code
, code
, _name
, ft
);
296 // Find new glyph offset
297 int newOffset
= _deviceGlyphTable
.size();
299 // Add the new glyph id
300 _deviceCodeTable
[code
] = newOffset
;
302 _deviceGlyphTable
.emplace_back(std::move(sh
), advance
);
308 Font::matches(const std::string
& name
, bool bold
, bool italic
) const
310 return (_bold
== bold
&& _italic
== italic
&& name
==_name
);
314 Font::leading() const {
315 return _fontTag
? _fontTag
->leading() : 0.0f
;
318 FreetypeGlyphsProvider
*
319 Font::ftProvider() const
321 if (_ftProvider
.get()) return _ftProvider
.get();
324 log_error(_("No name associated with this font, can't use device "
325 "fonts (should I use a default one?)"));
329 _ftProvider
= FreetypeGlyphsProvider::createFace(_name
, _bold
, _italic
);
331 if (!_ftProvider
.get()) {
332 log_error(_("Could not create a freetype face %s"), _name
);
336 return _ftProvider
.get();
340 Font::ascent(bool embedded
) const
342 if (embedded
&& _fontTag
) return _fontTag
->ascent();
343 FreetypeGlyphsProvider
* ft
= ftProvider();
344 if (ft
) return ft
->ascent();
349 Font::descent(bool embedded
) const
351 if (embedded
&& _fontTag
) return _fontTag
->descent();
352 FreetypeGlyphsProvider
* ft
= ftProvider();
353 if (ft
) return ft
->descent();
361 // indent-tabs-mode: t