Update with current status
[gnash.git] / libcore / Font.cpp
blob45c88e047433d30ab0bee991e17429cb3375c8c2
1 // Font.cpp: ActionScript Font handling, for Gnash.
2 //
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc
5 //
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.
10 //
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 "Font.h"
26 #include <utility>
27 #include <memory>
29 #include "log.h"
30 #include "ShapeRecord.h"
31 #include "DefineFontTag.h"
32 #include "FreetypeGlyphsProvider.h"
34 namespace gnash {
36 namespace {
38 /// Reverse lookup of Glyph in CodeTable.
40 /// Inefficient, which is probably why TextSnapshot was designed like it
41 /// is.
42 class CodeLookup
44 public:
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;
51 private:
52 const int _glyph;
57 Font::GlyphInfo::GlyphInfo()
59 advance(0)
62 Font::GlyphInfo::GlyphInfo(std::unique_ptr<SWF::ShapeRecord> the_glyph,
63 float advance)
65 glyph(std::move(the_glyph)),
66 advance(advance)
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)),
87 _unicodeChars(false),
88 _shiftJISChars(false),
89 _ansiChars(true),
90 _italic(italic),
91 _bold(bold)
93 assert(!_name.empty());
96 Font::~Font()
100 SWF::ShapeRecord*
101 Font::get_glyph(int index, bool embedded) const
103 // What to do if embedded is true and this is a
104 // device-only font?
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 ?
113 return nullptr;
116 void
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."));
127 return;
130 _displayName = fontName.displayName;
131 _copyrightName = fontName.copyrightName;
135 Font::GlyphInfoRecords::size_type
136 Font::glyphCount() const
138 assert(_fontTag);
139 return _fontTag->glyphTable().size();
143 void
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);
154 void
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."));
166 return;
168 _embeddedCodeTable.reset(table.release());
172 void
173 Font::setName(const std::string& name)
175 _name = name;
179 std::uint16_t
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(),
186 CodeLookup(glyph));
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);
195 return 0;
197 return it->first;
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;
210 return glyph_index;
213 // Try adding an os font, if possible
214 if (!embedded) {
215 glyph_index = const_cast<Font*>(this)->add_os_glyph(code);
217 return glyph_index;
220 float
221 Font::get_advance(int glyph_index, bool embedded) const
223 // What to do if embedded is true and this is a
224 // device-only font?
225 const GlyphInfoRecords& lookup = (embedded && _fontTag) ?
226 _fontTag->glyphTable() : _deviceGlyphTable;
228 if (glyph_index < 0) {
229 // Default advance.
230 return 512.0f;
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
242 float
243 Font::get_kerning_adjustment(int last_code, int code) const
245 kerning_pair k;
246 k.m_char0 = last_code;
247 k.m_char1 = code;
248 kernings_table::const_iterator it = m_kerning_pairs.find(k);
249 if (it != m_kerning_pairs.end()) {
250 float adjustment = it->second;
251 return adjustment;
253 return 0;
256 size_t
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
261 if (embed) {
262 if ( _fontTag && _fontTag->subpixelFont() ) return 1024 * 20.0;
263 else return 1024;
266 FreetypeGlyphsProvider* ft = ftProvider();
267 if (!ft) {
268 log_error(_("Device font provider was not initialized, "
269 "can't get unitsPerEM"));
270 return 0;
273 return ft->unitsPerEM();
277 Font::add_os_glyph(std::uint16_t code)
279 FreetypeGlyphsProvider* ft = ftProvider();
280 if (!ft) return -1;
282 assert(_deviceCodeTable.find(code) == _deviceCodeTable.end());
284 float advance;
286 // Get the vectorial glyph
287 std::unique_ptr<SWF::ShapeRecord> sh = ft->getGlyph(code, advance);
289 if (!sh.get()) {
290 log_error(_("Could not create shape "
291 "glyph for DisplayObject code %u (%c) with "
292 "device font %s (%p)"), code, code, _name, ft);
293 return -1;
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);
304 return newOffset;
307 bool
308 Font::matches(const std::string& name, bool bold, bool italic) const
310 return (_bold == bold && _italic == italic && name ==_name);
313 float
314 Font::leading() const {
315 return _fontTag ? _fontTag->leading() : 0.0f;
318 FreetypeGlyphsProvider*
319 Font::ftProvider() const
321 if (_ftProvider.get()) return _ftProvider.get();
323 if (_name.empty()) {
324 log_error(_("No name associated with this font, can't use device "
325 "fonts (should I use a default one?)"));
326 return nullptr;
329 _ftProvider = FreetypeGlyphsProvider::createFace(_name, _bold, _italic);
331 if (!_ftProvider.get()) {
332 log_error(_("Could not create a freetype face %s"), _name);
333 return nullptr;
336 return _ftProvider.get();
339 float
340 Font::ascent(bool embedded) const
342 if (embedded && _fontTag) return _fontTag->ascent();
343 FreetypeGlyphsProvider* ft = ftProvider();
344 if (ft) return ft->ascent();
345 return 0;
348 float
349 Font::descent(bool embedded) const
351 if (embedded && _fontTag) return _fontTag->descent();
352 FreetypeGlyphsProvider* ft = ftProvider();
353 if (ft) return ft->descent();
354 return 0;
357 } // namespace gnash
359 // Local Variables:
360 // mode: C++
361 // indent-tabs-mode: t
362 // End: