big merge from master, fix rpm creation, drop fetching swfdec
[gnash.git] / libcore / Font.cpp
blob431d090b81e918cbff7e769f07f9d1557b665a74
1 // Font.cpp: ActionScript Font handling, for Gnash.
2 //
3 // Copyright (C) 2006, 2007, 2008, 2009, 2010,
4 // 2011 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 "smart_ptr.h"
30 #include "log.h"
31 #include "ShapeRecord.h"
32 #include "DefineFontTag.h"
33 #include "FreetypeGlyphsProvider.h"
35 namespace gnash {
37 namespace {
39 /// Reverse lookup of Glyph in CodeTable.
41 /// Inefficient, which is probably why TextSnapshot was designed like it
42 /// is.
43 class CodeLookup
45 public:
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;
52 private:
53 const int _glyph;
58 Font::GlyphInfo::GlyphInfo()
60 advance(0)
63 Font::GlyphInfo::GlyphInfo(std::auto_ptr<SWF::ShapeRecord> glyph,
64 float advance)
66 glyph(glyph.release()),
67 advance(advance)
70 Font::GlyphInfo::GlyphInfo(const GlyphInfo& o)
72 glyph(o.glyph),
73 advance(o.advance)
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)
94 _fontTag(0),
95 _name(name),
96 _unicodeChars(false),
97 _shiftJISChars(false),
98 _ansiChars(true),
99 _italic(italic),
100 _bold(bold)
102 assert(!_name.empty());
105 Font::~Font()
109 SWF::ShapeRecord*
110 Font::get_glyph(int index, bool embedded) const
112 // What to do if embedded is true and this is a
113 // device-only font?
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 ?
122 return 0;
125 void
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."));
136 return;
139 _displayName = fontName.displayName;
140 _copyrightName = fontName.copyrightName;
144 Font::GlyphInfoRecords::size_type
145 Font::glyphCount() const
147 assert(_fontTag);
148 return _fontTag->glyphTable().size();
152 void
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);
163 void
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."));
175 return;
177 _embeddedCodeTable.reset(table.release());
181 void
182 Font::setName(const std::string& name)
184 _name = name;
188 boost::uint16_t
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(),
195 CodeLookup(glyph));
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);
204 return 0;
206 return it->first;
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;
219 return glyph_index;
222 // Try adding an os font, if possible
223 if (!embedded) {
224 glyph_index = const_cast<Font*>(this)->add_os_glyph(code);
226 return glyph_index;
229 float
230 Font::get_advance(int glyph_index, bool embedded) const
232 // What to do if embedded is true and this is a
233 // device-only font?
234 const GlyphInfoRecords& lookup = (embedded && _fontTag) ?
235 _fontTag->glyphTable() : _deviceGlyphTable;
237 if (glyph_index < 0) {
238 // Default advance.
239 return 512.0f;
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
251 float
252 Font::get_kerning_adjustment(int last_code, int code) const
254 kerning_pair k;
255 k.m_char0 = last_code;
256 k.m_char1 = code;
257 kernings_table::const_iterator it = m_kerning_pairs.find(k);
258 if (it != m_kerning_pairs.end()) {
259 float adjustment = it->second;
260 return adjustment;
262 return 0;
265 size_t
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
270 if (embed) {
271 if ( _fontTag && _fontTag->subpixelFont() ) return 1024 * 20.0;
272 else return 1024;
275 FreetypeGlyphsProvider* ft = ftProvider();
276 if (!ft) {
277 log_error("Device font provider was not initialized, "
278 "can't get unitsPerEM");
279 return 0;
282 return ft->unitsPerEM();
286 Font::add_os_glyph(boost::uint16_t code)
288 FreetypeGlyphsProvider* ft = ftProvider();
289 if (!ft) return -1;
291 assert(_deviceCodeTable.find(code) == _deviceCodeTable.end());
293 float advance;
295 // Get the vectorial glyph
296 std::auto_ptr<SWF::ShapeRecord> sh = ft->getGlyph(code, advance);
298 if (!sh.get()) {
299 log_error("Could not create shape "
300 "glyph for DisplayObject code %u (%c) with "
301 "device font %s (%p)", code, code, _name, ft);
302 return -1;
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));
313 return newOffset;
316 bool
317 Font::matches(const std::string& name, bool bold, bool italic) const
319 return (_bold == bold && _italic == italic && name ==_name);
322 float
323 Font::leading() const {
324 return _fontTag ? _fontTag->leading() : 0.0f;
327 FreetypeGlyphsProvider*
328 Font::ftProvider() const
330 if (_ftProvider.get()) return _ftProvider.get();
332 if (_name.empty()) {
333 log_error("No name associated with this font, can't use device "
334 "fonts (should I use a default one?)");
335 return 0;
338 _ftProvider = FreetypeGlyphsProvider::createFace(_name, _bold, _italic);
340 if (!_ftProvider.get()) {
341 log_error("Could not create a freetype face %s", _name);
342 return 0;
345 return _ftProvider.get();
348 float
349 Font::ascent(bool embedded) const
351 if (embedded && _fontTag) return _fontTag->ascent();
352 FreetypeGlyphsProvider* ft = ftProvider();
353 if (ft) return ft->ascent();
354 return 0;
357 float
358 Font::descent(bool embedded) const
360 if (embedded && _fontTag) return _fontTag->descent();
361 FreetypeGlyphsProvider* ft = ftProvider();
362 if (ft) return ft->descent();
363 return 0;
366 } // namespace gnash
368 // Local Variables:
369 // mode: C++
370 // indent-tabs-mode: t
371 // End: