Sync to trunk.

This commit is contained in:
John Schember 2012-11-06 18:52:39 -05:00
commit 5d3f97064f
159 changed files with 1946 additions and 21953 deletions

View File

@ -47,12 +47,6 @@ License: Apache 2.0
The full text of the Apache 2.0 license is available at:
http://www.apache.org/licenses/LICENSE-2.0
Files: src/sfntly/*
Copyright: Google Inc.
License: Apache 2.0
The full text of the Apache 2.0 license is available at:
http://www.apache.org/licenses/LICENSE-2.0
Files: resources/viewer/mathjax/*
Copyright: Unknown
License: Apache 2.0

View File

@ -659,6 +659,9 @@ There are three possible things I know of, that can cause this:
* You are using a Wacom branded mouse. There is an incompatibility between Wacom mice and the graphics toolkit |app| uses. Try using a non-Wacom mouse.
* If you use RoboForm, it is known to cause |app| to crash. Add |app| to
the blacklist of programs inside RoboForm to fix this.
* Sometimes if some software has installed lots of new files in your fonts folder, |app| can crash until it finishes indexing them. Just start |app|, then leave it alone for about 20 minutes, without clicking on anything. After that you should be able to use |app| as normal.

View File

@ -40,6 +40,6 @@ class LondonReviewOfBooks(BasicNewsRecipe):
soup = self.index_to_soup('http://www.lrb.co.uk/')
cover_item = soup.find('p',attrs={'class':'cover'})
if cover_item:
cover_url = 'http://www.lrb.co.uk' + cover_item.a.img['src']
cover_url = cover_item.a.img['src']
return cover_url

View File

@ -11,7 +11,6 @@ let g:syntastic_cpp_include_dirs = [
\'/usr/include/freetype2',
\'/usr/include/fontconfig',
\'src/qtcurve/common', 'src/qtcurve',
\'src/sfntly/src', 'src/sfntly/src/sample',
\'/usr/include/ImageMagick',
\]
let g:syntastic_c_include_dirs = g:syntastic_cpp_include_dirs

View File

@ -19,7 +19,6 @@ from setup.build_environment import (chmlib_inc_dirs,
magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs,
icu_lib_dirs, win_ddk_lib_dirs, ft_libs, ft_lib_dirs, ft_inc_dirs,
zlib_libs, zlib_lib_dirs, zlib_inc_dirs)
from setup.sfntly import SfntlyBuilderMixin
MT
isunix = islinux or isosx or isbsd
@ -63,26 +62,8 @@ if isosx:
icu_libs = ['icucore']
icu_cflags = ['-DU_DISABLE_RENAMING'] # Needed to use system libicucore.dylib
class SfntlyExtension(Extension, SfntlyBuilderMixin):
def __init__(self, *args, **kwargs):
Extension.__init__(self, *args, **kwargs)
SfntlyBuilderMixin.__init__(self)
def preflight(self, *args, **kwargs):
self(*args, **kwargs)
extensions = [
SfntlyExtension('sfntly',
['calibre/utils/fonts/sfntly.cpp'],
headers= ['calibre/utils/fonts/sfntly.h'],
libraries=icu_libs,
lib_dirs=icu_lib_dirs,
inc_dirs=icu_inc_dirs,
cflags=icu_cflags
),
Extension('speedup',
['calibre/utils/speedup.c'],
),

View File

@ -1,93 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import shlex, os
from glob import glob
from setup import iswindows
class Group(object):
def __init__(self, name, base, build_base, cflags):
self.name = name
self.cflags = cflags
self.headers = frozenset(glob(os.path.join(base, '*.h')))
self.src_files = glob(os.path.join(base, '*.cc'))
self.bdir = os.path.abspath(os.path.join(build_base, name))
if not os.path.exists(self.bdir):
os.makedirs(self.bdir)
self.objects = [os.path.join(self.bdir,
os.path.basename(x).rpartition('.')[0] + ('.obj' if iswindows else
'.o')) for x in self.src_files]
def __call__(self, compiler, linker, builder, all_headers):
for src, obj in zip(self.src_files, self.objects):
if builder.newer(obj, [src] + list(all_headers)):
sinc = ['/Tp'+src] if iswindows else ['-c', src]
oinc = ['/Fo'+obj] if iswindows else ['-o', obj]
cmd = [compiler] + self.cflags + sinc + oinc
builder.info(' '.join(cmd))
builder.check_call(cmd)
class SfntlyBuilderMixin(object):
def __init__(self):
self.sfntly_cflags = [
'-DSFNTLY_NO_EXCEPTION',
'-DSFNTLY_EXPERIMENTAL',
]
if iswindows:
self.sfntly_cflags += [
'-D_UNICODE', '-DUNICODE',
] + shlex.split('/W4 /WX /Gm- /Gy /GR-')
self.cflags += ['-DWIN32']
else:
# Possibly add -fno-inline (slower, but more robust)
self.sfntly_cflags += [
'-Werror',
'-fno-exceptions',
]
if len(self.libraries) > 1:
self.libraries = ['icuuc']
if not iswindows:
self.libraries += ['pthread']
def __call__(self, obj_dir, compiler, linker, builder, cflags, ldflags):
self.sfntly_build_dir = os.path.join(obj_dir, 'sfntly')
if '/Ox' in cflags:
cflags.remove('/Ox')
if '-O3' in cflags:
cflags.remove('-O3')
if '/W3' in cflags:
cflags.remove('/W3')
if '-ggdb' not in cflags:
cflags.insert(0, '/O2' if iswindows else '-O2')
groups = []
all_headers = set()
all_objects = []
src_dir = self.absolutize([os.path.join('sfntly', 'src')])[0]
inc_dirs = [src_dir]
self.inc_dirs += inc_dirs
inc_flags = builder.inc_dirs_to_cflags(self.inc_dirs)
for loc in ('', 'port', 'data', 'math', 'table', 'table/bitmap',
'table/core', 'table/truetype'):
path = os.path.join(src_dir, 'sfntly', *loc.split('/'))
gr = Group(loc, path, self.sfntly_build_dir, cflags+
inc_flags+self.sfntly_cflags+self.cflags)
groups.append(gr)
all_headers |= gr.headers
all_objects.extend(gr.objects)
for group in groups:
group(compiler, linker, builder, all_headers)
self.extra_objs = all_objects

View File

@ -91,7 +91,6 @@ class Plugins(collections.Mapping):
'speedup',
'freetype',
'woff',
'sfntly',
]
if iswindows:
plugins.extend(['winutil', 'wpd', 'winfonts'])

View File

@ -212,7 +212,7 @@ def main(args=sys.argv):
return
if len(args) > 1 and args[1] in ('-f', '--subset-font'):
from calibre.utils.fonts.subset import main
from calibre.utils.fonts.sfnt.subset import main
main(['subset-font']+args[2:])
return

View File

@ -133,6 +133,7 @@ def add_pipeline_options(parser, plumber):
[
'base_font_size', 'disable_font_rescaling',
'font_size_mapping', 'embed_font_family',
'subset_embedded_fonts',
'line_height', 'minimum_line_height',
'linearize_tables',
'extra_css', 'filter_css',

View File

@ -204,6 +204,17 @@ OptionRecommendation(name='embed_font_family',
'with some output formats, principally EPUB and AZW3.')
),
OptionRecommendation(name='subset_embedded_fonts',
recommended_value=False, level=OptionRecommendation.LOW,
help=_(
'Subset all embedded fonts. Every embedded font is reduced '
'to contain only the glyphs used in this document. This decreases '
'the size of the font files. Useful if you are embedding a '
'particularly large font with lots of unused glyphs. Note that '
'subsetting is only supported for fonts that contain TrueType '
'outlines, not Postscript outlines.')
),
OptionRecommendation(name='linearize_tables',
recommended_value=False, level=OptionRecommendation.LOW,
help=_('Some badly designed documents use tables to control the '
@ -1112,6 +1123,10 @@ OptionRecommendation(name='search_replace',
RemoveFakeMargins()(self.oeb, self.log, self.opts)
RemoveAdobeMargins()(self.oeb, self.log, self.opts)
if self.opts.subset_embedded_fonts:
from calibre.ebooks.oeb.transforms.subset import SubsetFonts
SubsetFonts()(self.oeb, self.log, self.opts)
pr(0.9)
self.flush()

View File

@ -0,0 +1,284 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from collections import defaultdict
from calibre.ebooks.oeb.base import urlnormalize
from calibre.utils.fonts.sfnt.subset import subset, NoGlyphs, UnsupportedFont
class SubsetFonts(object):
'''
Subset all embedded fonts. Must be run after CSS flattening, as it requires
CSS normalization and flattening to work.
'''
def __call__(self, oeb, log, opts):
self.oeb, self.log, self.opts = oeb, log, opts
self.find_embedded_fonts()
if not self.embedded_fonts:
self.log.debug('No embedded fonts found')
return
self.find_style_rules()
self.find_font_usage()
totals = [0, 0]
def remove(font):
totals[1] += len(font['item'].data)
self.oeb.manifest.remove(font['item'])
font['rule'].parentStyleSheet.deleteRule(font['rule'])
for font in self.embedded_fonts:
if not font['chars']:
self.log('The font %s is unused. Removing it.'%font['src'])
remove(font)
continue
try:
raw, old_stats, new_stats = subset(font['item'].data, font['chars'])
except NoGlyphs:
self.log('The font %s has no used glyphs. Removing it.'%font['src'])
remove(font)
continue
except UnsupportedFont as e:
self.log.warn('The font %s is unsupported for subsetting. %s'%(
font['src'], e))
sz = len(font['item'].data)
totals[0] += sz
totals[1] += sz
else:
font['item'].data = raw
nlen = sum(new_stats.itervalues())
olen = sum(old_stats.itervalues())
self.log('Decreased the font %s to %.1f%% of its original size'%
(font['src'], nlen/olen *100))
totals[0] += nlen
totals[1] += olen
font['item'].unload_data_from_memory()
if totals[0]:
self.log('Reduced total font size to %.1f%% of original'%
(totals[0]/totals[1] * 100))
def get_font_properties(self, rule, default=None):
'''
Given a CSS rule, extract normalized font properties from
it. Note that shorthand font property should already have been expanded
by the CSS flattening code.
'''
props = {}
s = rule.style
for q in ('font-family', 'src', 'font-weight', 'font-stretch',
'font-style'):
g = 'uri' if q == 'src' else 'value'
try:
val = s.getProperty(q).propertyValue[0]
val = getattr(val, g)
if q == 'font-family':
val = [x.value for x in s.getProperty(q).propertyValue]
if val and val[0] == 'inherit':
val = None
except (IndexError, KeyError, AttributeError, TypeError, ValueError):
val = None if q in {'src', 'font-family'} else default
if q in {'font-weight', 'font-stretch', 'font-style'}:
val = val.lower() if val else val
if val == 'inherit':
val = default
if q == 'font-weight':
val = {'normal':'400', 'bold':'700'}.get(val, val)
if val not in {'100', '200', '300', '400', '500', '600', '700',
'800', '900', 'bolder', 'lighter'}:
val = default
if val == 'normal': val = '400'
elif q == 'font-style':
if val not in {'normal', 'italic', 'oblique'}:
val = default
elif q == 'font-stretch':
if val not in { 'normal', 'ultra-condensed', 'extra-condensed',
'condensed', 'semi-condensed', 'semi-expanded',
'expanded', 'extra-expanded', 'ultra-expanded'}:
val = default
props[q] = val
return props
def find_embedded_fonts(self):
'''
Find all @font-face rules and extract the relevant info from them.
'''
self.embedded_fonts = []
for item in self.oeb.manifest:
if not hasattr(item.data, 'cssRules'): continue
for i, rule in enumerate(item.data.cssRules):
if rule.type != rule.FONT_FACE_RULE:
continue
props = self.get_font_properties(rule, default='normal')
if not props['font-family'] or not props['src']:
continue
path = item.abshref(props['src'])
ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None)
if not ff:
continue
props['item'] = ff
if props['font-weight'] in {'bolder', 'lighter'}:
props['font-weight'] = '400'
props['weight'] = int(props['font-weight'])
props['chars'] = set()
props['rule'] = rule
self.embedded_fonts.append(props)
def find_style_rules(self):
'''
Extract all font related style information from all stylesheets into a
dict mapping classes to font properties specified by that class. All
the heavy lifting has already been done by the CSS flattening code.
'''
rules = defaultdict(dict)
for item in self.oeb.manifest:
if not hasattr(item.data, 'cssRules'): continue
for i, rule in enumerate(item.data.cssRules):
if rule.type != rule.STYLE_RULE:
continue
props = {k:v for k,v in
self.get_font_properties(rule).iteritems() if v}
if not props:
continue
for sel in rule.selectorList:
sel = sel.selectorText
if sel and sel.startswith('.'):
# We dont care about pseudo-selectors as the worst that
# can happen is some extra characters will remain in
# the font
sel = sel.partition(':')[0]
rules[sel[1:]].update(props)
self.style_rules = dict(rules)
def find_font_usage(self):
for item in self.oeb.manifest:
if not hasattr(item.data, 'xpath'): continue
for body in item.data.xpath('//*[local-name()="body"]'):
base = {'font-family':['serif'], 'font-weight': '400',
'font-style':'normal', 'font-stretch':'normal'}
self.find_usage_in(body, base)
def elem_style(self, cls, inherited_style):
'''
Find the effective style for the given element.
'''
classes = cls.split()
style = inherited_style.copy()
for cls in classes:
style.update(self.style_rules.get(cls, {}))
wt = style.get('font-weight', None)
pwt = inherited_style.get('font-weight', '400')
if wt == 'bolder':
style['font-weight'] = {
'100':'400',
'200':'400',
'300':'400',
'400':'700',
'500':'700',
}.get(pwt, '900')
elif wt == 'lighter':
style['font-weight'] = {
'600':'400', '700':'400',
'800':'700', '900':'700'}.get(pwt, '100')
return style
def used_font(self, style):
'''
Given a style find the embedded font that matches it. Returns None if
no match is found ( can happen if not family matches).
'''
ff = style.get('font-family', [])
lnames = {x.lower() for x in ff}
matching_set = []
# Filter on font-family
for ef in self.embedded_fonts:
flnames = {x.lower() for x in ef.get('font-family', [])}
if not lnames.intersection(flnames):
continue
matching_set.append(ef)
if not matching_set:
return None
# Filter on font-stretch
widths = {x:i for i, x in enumerate(( 'ultra-condensed',
'extra-condensed', 'condensed', 'semi-condensed', 'normal',
'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'
))}
width = widths[style.get('font-stretch', 'normal')]
for f in matching_set:
f['width'] = widths[style.get('font-stretch', 'normal')]
min_dist = min(abs(width-f['width']) for f in matching_set)
nearest = [f for f in matching_set if abs(width-f['width']) ==
min_dist]
if width <= 4:
lmatches = [f for f in nearest if f['width'] <= width]
else:
lmatches = [f for f in nearest if f['width'] >= width]
matching_set = (lmatches or nearest)
# Filter on font-style
fs = style.get('font-style', 'normal')
order = {
'oblique':['oblique', 'italic', 'normal'],
'normal':['normal', 'oblique', 'italic']
}.get(fs, ['italic', 'oblique', 'normal'])
for q in order:
matches = [f for f in matching_set if f.get('font-style', 'normal')
== q]
if matches:
matching_set = matches
break
# Filter on font weight
fw = int(style.get('font-weight', '400'))
if fw == 400:
q = [400, 500, 300, 200, 100, 600, 700, 800, 900]
elif fw == 500:
q = [500, 400, 300, 200, 100, 600, 700, 800, 900]
elif fw < 400:
q = [fw] + list(xrange(fw-100, -100, -100)) + list(xrange(fw+100,
100, 1000))
else:
q = [fw] + list(xrange(fw+100, 100, 1000)) + list(xrange(fw-100,
-100, -100))
for wt in q:
matches = [f for f in matching_set if f['weight'] == wt]
if matches:
return matches[0]
def find_chars(self, elem):
ans = set()
if elem.text:
ans |= set(elem.text)
for child in elem:
if child.tail:
ans |= set(child.tail)
return ans
def find_usage_in(self, elem, inherited_style):
style = self.elem_style(elem.get('class', ''), inherited_style)
for child in elem:
self.find_usage_in(child, style)
font = self.used_font(style)
if font:
chars = self.find_chars(elem)
if chars:
font['chars'] |= chars

View File

@ -239,10 +239,11 @@ class PluginWidget(QWidget,Ui_Form):
def initialize(self, name, db):
'''
CheckBoxControls (c_type: check_box):
['generate_titles','generate_series','generate_genres',
'generate_recently_added','generate_descriptions','include_hr']
['cross_reference_authors',
'generate_titles','generate_series','generate_genres',
'generate_recently_added','generate_descriptions',
'include_hr']
ComboBoxControls (c_type: combo_box):
['exclude_source_field','header_note_source_field',
'merge_source_field']

View File

@ -305,7 +305,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
<string>Other options</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="1">
<item row="3" column="1">
<layout class="QHBoxLayout" name="merge_with_comments_hl">
<item>
<widget class="QComboBox" name="merge_source_field">
@ -372,7 +372,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
</item>
</layout>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="minimumSize">
<size>
@ -397,7 +397,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
</property>
</widget>
</item>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
@ -413,7 +413,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<layout class="QHBoxLayout" name="replace_cover_hl">
<item>
<widget class="QRadioButton" name="generate_new_cover">
@ -447,7 +447,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
</item>
</layout>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>E&amp;xtra Description note:</string>
@ -460,7 +460,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="header_note_source_field">
@ -561,6 +561,27 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Author cross-references:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="cross_references_hl">
<item>
<widget class="QCheckBox" name="cross_reference_authors">
<property name="text">
<string>For books with multiple authors, list each author separately</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -32,7 +32,7 @@ class LookAndFeelWidget(Widget, Ui_Form):
Widget.__init__(self, parent,
['change_justification', 'extra_css', 'base_font_size',
'font_size_mapping', 'line_height', 'minimum_line_height',
'embed_font_family',
'embed_font_family', 'subset_embedded_fonts',
'smarten_punctuation', 'unsmarten_punctuation',
'disable_font_rescaling', 'insert_blank_line',
'remove_paragraph_spacing',

View File

@ -406,7 +406,14 @@
</widget>
</item>
<item row="6" column="1" colspan="2">
<widget class="FontFamilyChooser" name="opt_embed_font_family"/>
<widget class="FontFamilyChooser" name="opt_embed_font_family" native="true"/>
</item>
<item row="6" column="3" colspan="2">
<widget class="QCheckBox" name="opt_subset_embedded_fonts">
<property name="text">
<string>&amp;Subset all embedded fonts</string>
</property>
</widget>
</item>
</layout>
</widget>

View File

@ -225,7 +225,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.mi.series_index = 3
self.mi.rating = 4.0
self.mi.tags = [_('Tag 1'), _('Tag 2')]
self.mi.language = ['eng']
self.mi.languages = ['eng']
# Remove help icon on title bar
icon = self.windowIcon()

View File

@ -13,7 +13,7 @@ from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen,
QStyledItemDelegate, QSize, QStyle, QStringListModel, pyqtSignal,
QDialog, QVBoxLayout, QApplication, QFontComboBox, QPushButton,
QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon,
QHBoxLayout, QLabel, QModelIndex)
QHBoxLayout, QLabel, QModelIndex, QLineEdit)
from calibre.constants import config_dir
from calibre.gui2 import choose_files, error_dialog, info_dialog
@ -197,15 +197,56 @@ class FontFamilyDialog(QDialog):
afb.setIcon(QIcon(I('plus.png')))
afb.clicked.connect(self.add_fonts)
self.ml = QLabel(_('Choose a font family from the list below:'))
self.search = QLineEdit(self)
self.search.setPlaceholderText(_('Search'))
self.search.returnPressed.connect(self.find)
self.nb = QToolButton(self)
self.nb.setIcon(QIcon(I('arrow-down.png')))
self.nb.setToolTip(_('Find Next'))
self.pb = QToolButton(self)
self.pb.setIcon(QIcon(I('arrow-up.png')))
self.pb.setToolTip(_('Find Previous'))
self.nb.clicked.connect(self.find_next)
self.pb.clicked.connect(self.find_previous)
l.addWidget(self.ml, 0, 0, 1, 2)
l.addWidget(self.view, 1, 0, 1, 1)
l.addWidget(self.faces, 1, 1, 1, 1)
l.addWidget(self.bb, 2, 0, 1, 2)
l.addWidget(self.ml, 0, 0, 1, 4)
l.addWidget(self.search, 1, 0, 1, 1)
l.addWidget(self.nb, 1, 1, 1, 1)
l.addWidget(self.pb, 1, 2, 1, 1)
l.addWidget(self.view, 2, 0, 1, 3)
l.addWidget(self.faces, 1, 3, 2, 1)
l.addWidget(self.bb, 3, 0, 1, 4)
l.setAlignment(self.faces, Qt.AlignTop)
self.resize(800, 600)
def set_current(self, i):
self.view.setCurrentIndex(self.m.index(i))
def keyPressEvent(self, e):
if e.key() == Qt.Key_Return:
return
return QDialog.keyPressEvent(self, e)
def find(self, backwards=False):
i = self.view.currentIndex().row()
if i < 0: i = 0
q = icu_lower(unicode(self.search.text())).strip()
if not q: return
r = (xrange(i-1, -1, -1) if backwards else xrange(i+1,
len(self.families)))
for j in r:
f = self.families[j]
if q in icu_lower(f):
self.set_current(j)
return
def find_next(self):
self.find()
def find_previous(self):
self.find(backwards=True)
def build_font_list(self):
try:
self.families = list(self.font_scanner.find_font_families())

View File

@ -188,6 +188,10 @@ class MetadataSingleDialogBase(ResizableDialog):
self.tags_editor_button.setToolTip(_('Open Tag Editor'))
self.tags_editor_button.setIcon(QIcon(I('chapters.png')))
self.tags_editor_button.clicked.connect(self.tags_editor)
self.clear_tags_button = QToolButton(self)
self.clear_tags_button.setToolTip(_('Clear all tags'))
self.clear_tags_button.setIcon(QIcon(I('trash.png')))
self.clear_tags_button.clicked.connect(self.tags.clear)
self.basic_metadata_widgets.append(self.tags)
self.identifiers = IdentifiersEdit(self)
@ -656,9 +660,10 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
l.addItem(self.tabs[0].spc_one, 1, 0, 1, 3)
sto(self.cover.buttons[-1], self.rating)
create_row2(1, self.rating)
sto(self.rating, self.tags)
create_row2(2, self.tags, self.tags_editor_button)
sto(self.tags_editor_button, self.paste_isbn_button)
sto(self.rating, self.tags_editor_button)
sto(self.tags_editor_button, self.tags)
create_row2(2, self.tags, self.clear_tags_button, front_button=self.tags_editor_button)
sto(self.clear_tags_button, self.paste_isbn_button)
sto(self.paste_isbn_button, self.identifiers)
create_row2(3, self.identifiers, self.clear_identifiers_button,
front_button=self.paste_isbn_button)
@ -761,6 +766,7 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
tl.addWidget(self.manage_authors_button, 2, 0, 1, 1)
tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1)
tl.addWidget(self.tags_editor_button, 6, 0, 1, 1)
create_row(0, self.title, self.title_sort,
button=self.deduce_title_sort_button, span=2,
@ -773,7 +779,7 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
create_row(4, self.series, self.series_index,
button=self.clear_series_button, icon='trash.png')
create_row(5, self.series_index, self.tags)
create_row(6, self.tags, self.rating, button=self.tags_editor_button)
create_row(6, self.tags, self.rating, button=self.clear_tags_button)
create_row(7, self.rating, self.pubdate)
create_row(8, self.pubdate, self.publisher,
button=self.pubdate.clear_button, icon='trash.png')
@ -785,7 +791,8 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
button=self.clear_identifiers_button, icon='trash.png')
sto(self.clear_identifiers_button, self.swap_title_author_button)
sto(self.swap_title_author_button, self.manage_authors_button)
sto(self.manage_authors_button, self.paste_isbn_button)
sto(self.manage_authors_button, self.tags_editor_button)
sto(self.tags_editor_button, self.paste_isbn_button)
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
13, 1, 1 ,1)
@ -896,6 +903,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
tl.addWidget(self.manage_authors_button, 2, 0, 2, 1)
tl.addWidget(self.paste_isbn_button, 12, 0, 1, 1)
tl.addWidget(self.tags_editor_button, 6, 0, 1, 1)
create_row(0, self.title, self.title_sort,
button=self.deduce_title_sort_button, span=2,
@ -908,7 +916,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
create_row(4, self.series, self.series_index,
button=self.clear_series_button, icon='trash.png')
create_row(5, self.series_index, self.tags)
create_row(6, self.tags, self.rating, button=self.tags_editor_button)
create_row(6, self.tags, self.rating, button=self.clear_tags_button)
create_row(7, self.rating, self.pubdate)
create_row(8, self.pubdate, self.publisher,
button=self.pubdate.clear_button, icon='trash.png')
@ -920,7 +928,8 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
button=self.clear_identifiers_button, icon='trash.png')
sto(self.clear_identifiers_button, self.swap_title_author_button)
sto(self.swap_title_author_button, self.manage_authors_button)
sto(self.manage_authors_button, self.paste_isbn_button)
sto(self.manage_authors_button, self.tags_editor_button)
sto(self.tags_editor_button, self.paste_isbn_button)
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
13, 1, 1 ,1)

View File

@ -403,7 +403,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
return
all_locations = OrderedDict(ConfigWidget.LOCATIONS)
try:
plugin_action = plugin.load_actual_plugin(self.gui)
except:
# Broken plugin, fails to initialize. Given that, it's probably
# already configured, so we can just quit.
return
installed_actions = OrderedDict([
(key, list(gprefs.get('action-layout-'+key, [])))
for key in all_locations])

View File

@ -3,18 +3,16 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''
Miscellaneous widgets used in the GUI
'''
import re, traceback, os
import re, os
from PyQt4.Qt import (QIcon, QFont, QLabel, QListWidget, QAction,
QListWidgetItem, QTextCharFormat, QApplication, QSyntaxHighlighter,
QCursor, QColor, QWidget, QPixmap, QSplitterHandle, QToolButton,
QAbstractListModel, QVariant, Qt, SIGNAL, pyqtSignal, QRegExp, QSize,
QSplitter, QPainter, QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu,
QStringListModel, QCompleter, QStringList, QTimer, QRect,
QGraphicsView, QByteArray)
QVariant, Qt, SIGNAL, pyqtSignal, QRegExp, QSize, QSplitter, QPainter,
QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu, QStringListModel,
QCompleter, QStringList, QTimer, QRect, QGraphicsView, QByteArray)
from calibre.constants import iswindows
from calibre.gui2 import (NONE, error_dialog, pixmap_to_data, gprefs,
from calibre.gui2 import (error_dialog, pixmap_to_data, gprefs,
warning_dialog)
from calibre.gui2.filename_pattern_ui import Ui_Form
from calibre import fit_image
@ -348,43 +346,6 @@ class CoverView(QGraphicsView, ImageDropMixin): # {{{
# }}}
class FontFamilyModel(QAbstractListModel): # {{{
def __init__(self, *args):
QAbstractListModel.__init__(self, *args)
from calibre.utils.fonts.scanner import font_scanner
try:
self.families = font_scanner.find_font_families()
except:
self.families = []
print 'WARNING: Could not load fonts'
traceback.print_exc()
# Restrict to Qt families as Qt tends to crash
self.families[:0] = [_('None')]
self.font = QFont('Arial' if iswindows else 'sansserif')
def rowCount(self, *args):
return len(self.families)
def data(self, index, role):
try:
family = self.families[index.row()]
except:
traceback.print_exc()
return NONE
if role == Qt.DisplayRole:
return QVariant(family)
if role == Qt.FontRole:
# If a user chooses some non standard font as the interface font,
# rendering some font names causes Qt to crash, so return what is
# hopefully a "safe" font
return QVariant(self.font)
return NONE
def index_of(self, family):
return self.families.index(family.strip())
# }}}
# BasicList {{{
class BasicListItem(QListWidgetItem):

View File

@ -41,6 +41,13 @@ class EPUB_MOBI(CatalogPlugin):
help = _('Title of generated catalog used as title in metadata.\n'
"Default: '%default'\n"
"Applies to: AZW3, ePub, MOBI output formats")),
Option('--cross-reference-authors',
default=False,
dest='cross_reference_authors',
action = 'store_true',
help=_("Create cross-references in Authors section for books with multiple authors.\n"
"Default: '%default'\n"
"Applies to: AZW3, ePub, MOBI output formats")),
Option('--debug-pipeline',
default=None,
dest='debug_pipeline',
@ -58,7 +65,6 @@ class EPUB_MOBI(CatalogPlugin):
help=_("Regex describing tags to exclude as genres.\n"
"Default: '%default' excludes bracketed tags, e.g. '[Project Gutenberg]', and '+', the default tag for read books.\n"
"Applies to: AZW3, ePub, MOBI output formats")),
Option('--exclusion-rules',
default="(('Catalogs','Tags','Catalog'),)",
dest='exclusion_rules',
@ -72,7 +78,6 @@ class EPUB_MOBI(CatalogPlugin):
"When multiple rules are defined, all rules will be applied.\n"
"Default: \n" + '"' + '%default' + '"' + "\n"
"Applies to AZW3, ePub, MOBI output formats")),
Option('--generate-authors',
default=False,
dest='generate_authors',
@ -318,8 +323,8 @@ class EPUB_MOBI(CatalogPlugin):
build_log.append(" opts:")
for key in keys:
if key in ['catalog_title','author_clip','connected_kindle','creator',
'description_clip','exclude_book_marker','exclude_genre',
'exclude_tags','exclusion_rules', 'fmt',
'cross_reference_authors','description_clip','exclude_book_marker',
'exclude_genre','exclude_tags','exclusion_rules', 'fmt',
'header_note_source_field','merge_comments_rule',
'output_profile','prefix_rules','read_book_marker',
'search_text','sort_by','sort_descriptions_by_author','sync',

View File

@ -14,11 +14,12 @@ from calibre.customize.conversion import DummyReporter
from calibre.customize.ui import output_profiles
from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString
from calibre.ebooks.chardet import substitute_entites
from calibre.ebooks.metadata import author_to_author_sort
from calibre.library.catalogs import AuthorSortMismatchException, EmptyCatalogException
from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.config import config_dir
from calibre.utils.date import format_date, is_date_undefined, now as nowf
from calibre.utils.filenames import ascii_text
from calibre.utils.filenames import ascii_text, shorten_components_to
from calibre.utils.icu import capitalize, collation_order, sort_key
from calibre.utils.magick.draw import thumbnail
from calibre.utils.zipfile import ZipFile
@ -109,6 +110,7 @@ class CatalogBuilder(object):
self.stylesheet = stylesheet
self.cache_dir = os.path.join(config_dir, 'caches', 'catalog')
self.catalog_path = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='')
self.content_dir = os.path.join(self.catalog_path, "content")
self.excluded_tags = self.get_excluded_tags()
self.generate_for_kindle_azw3 = True if (_opts.fmt == 'azw3' and
_opts.output_profile and
@ -127,12 +129,13 @@ class CatalogBuilder(object):
self.books_by_title = None
self.books_by_title_no_series_prefix = None
self.books_to_catalog = None
self.content_dir = os.path.join(self.catalog_path, "content")
self.current_step = 0.0
self.error = []
self.generate_recently_read = False
self.genres = []
self.genre_tags_dict = None
self.genre_tags_dict = \
self.filter_db_tags(max_len = 245 - len("%s/Genre_.html" % self.content_dir)) \
if self.opts.generate_genres else None
self.html_filelist_1 = []
self.html_filelist_2 = []
self.merge_comments_rule = dict(zip(['field','position','hr'],
@ -505,7 +508,7 @@ class CatalogBuilder(object):
if not os.path.isdir(images_path):
os.makedirs(images_path)
def detect_author_sort_mismatches(self):
def detect_author_sort_mismatches(self, books_to_test):
""" Detect author_sort mismatches.
Sort by author, look for inconsistencies in author_sort among
@ -513,17 +516,18 @@ class CatalogBuilder(object):
annoyance for EPUB.
Inputs:
self.books_to_catalog (list): list of books to catalog
books_by_author (list): list of books to test, possibly unsorted
Output:
self.books_by_author (list): sorted by author
(none)
Exceptions:
AuthorSortMismatchException: author_sort mismatch detected
"""
self.books_by_author = sorted(list(self.books_to_catalog), key=self._kf_books_by_author_sorter_author)
authors = [(record['author'], record['author_sort']) for record in self.books_by_author]
books_by_author = sorted(list(books_to_test), key=self._kf_books_by_author_sorter_author)
authors = [(record['author'], record['author_sort']) for record in books_by_author]
current_author = authors[0]
for (i,author) in enumerate(authors):
if author != current_author and i:
@ -582,7 +586,10 @@ class CatalogBuilder(object):
if rule['field'].lower() == 'tags':
if rule['pattern'].lower() in map(unicode.lower,record['tags']):
if self.opts.verbose:
_log_prefix_rule_match_info(rule, record, rule['pattern'])
self.opts.log.info(" %s '%s' by %s (%s: Tags includes '%s')" %
(rule['prefix'],record['title'],
record['authors'][0], rule['name'],
rule['pattern']))
return rule['prefix']
# Regex match for custom field
@ -698,6 +705,7 @@ class CatalogBuilder(object):
def fetch_books_by_author(self):
""" Generate a list of books sorted by author.
For books with multiple authors, relist book with additional authors.
Sort the database by author. Report author_sort inconsistencies as warning when
building EPUB or MOBI, error when building MOBI. Collect a list of unique authors
to self.authors.
@ -717,25 +725,30 @@ class CatalogBuilder(object):
self.update_progress_full_step(_("Sorting database"))
self.detect_author_sort_mismatches()
books_by_author = list(self.books_to_catalog)
self.detect_author_sort_mismatches(books_by_author)
if self.opts.cross_reference_authors:
books_by_author = self.relist_multiple_authors(books_by_author)
#books_by_author = sorted(list(books_by_author), key=self._kf_books_by_author_sorter_author)
# Sort authors using sort_key to normalize accented letters
# Determine the longest author_sort length before sorting
asl = [i['author_sort'] for i in self.books_by_author]
asl = [i['author_sort'] for i in books_by_author]
las = max(asl, key=len)
self.books_by_author = sorted(self.books_to_catalog,
books_by_author = sorted(books_by_author,
key=lambda x: sort_key(self._kf_books_by_author_sorter_author_sort(x, len(las))))
if self.DEBUG and self.opts.verbose:
tl = [i['title'] for i in self.books_by_author]
tl = [i['title'] for i in books_by_author]
lt = max(tl, key=len)
fs = '{:<6}{:<%d} {:<%d} {!s}' % (len(lt),len(las))
print(fs.format('','Title','Author','Series'))
for i in self.books_by_author:
for i in books_by_author:
print(fs.format('', i['title'],i['author_sort'],i['series']))
# Build the unique_authors set from existing data
authors = [(record['author'], capitalize(record['author_sort'])) for record in self.books_by_author]
authors = [(record['author'], capitalize(record['author_sort'])) for record in books_by_author]
# authors[] contains a list of all book authors, with multiple entries for multiple books by author
# authors[]: (([0]:friendly [1]:sort))
@ -773,6 +786,7 @@ class CatalogBuilder(object):
author[2])).encode('utf-8'))
self.authors = unique_authors
self.books_by_author = books_by_author
return True
def fetch_books_by_title(self):
@ -860,15 +874,15 @@ class CatalogBuilder(object):
this_title['series_index'] = 0.0
this_title['title_sort'] = self.generate_sort_title(this_title['title'])
if 'authors' in record:
# from calibre.ebooks.metadata import authors_to_string
# return authors_to_string(self.authors)
if 'authors' in record:
this_title['authors'] = record['authors']
# Synthesize author attribution from authors list
if record['authors']:
this_title['author'] = " &amp; ".join(record['authors'])
else:
this_title['author'] = 'Unknown'
this_title['author'] = _('Unknown')
this_title['authors'] = [this_title['author']]
if 'author_sort' in record and record['author_sort'].strip():
this_title['author_sort'] = record['author_sort']
@ -1090,7 +1104,7 @@ class CatalogBuilder(object):
self.bookmarked_books = bookmarks
def filter_db_tags(self):
def filter_db_tags(self, max_len):
""" Remove excluded tags from data set, return normalized genre list.
Filter all db tags, removing excluded tags supplied in opts.
@ -1098,13 +1112,13 @@ class CatalogBuilder(object):
tags are flattened to alphanumeric ascii_text.
Args:
(none)
max_len: maximum length of normalized tag to fit within OS constraints
Return:
genre_tags_dict (dict): dict of filtered, normalized tags in data set
"""
def _format_tag_list(tags, indent=2, line_break=70, header='Tag list'):
def _format_tag_list(tags, indent=1, line_break=70, header='Tag list'):
def _next_tag(sorted_tags):
for (i, tag) in enumerate(sorted_tags):
if i < len(tags) - 1:
@ -1123,6 +1137,31 @@ class CatalogBuilder(object):
out_str = ' ' * (indent + 1)
return ans + out_str
def _normalize_tag(tag, max_len):
""" Generate an XHTML-legal anchor string from tag.
Parse tag for non-ascii, convert to unicode name.
Args:
tags (str): tag name possible containing symbols
max_len (int): maximum length of tag
Return:
normalized (str): unicode names substituted for non-ascii chars,
clipped to max_len
"""
normalized = massaged = re.sub('\s','',ascii_text(tag).lower())
if re.search('\W',normalized):
normalized = ''
for c in massaged:
if re.search('\W',c):
normalized += self.generate_unicode_name(c)
else:
normalized += c
shortened = shorten_components_to(max_len, [normalized])[0]
return shortened
# Entry point
normalized_tags = []
friendly_tags = []
@ -1141,7 +1180,7 @@ class CatalogBuilder(object):
if tag == ' ':
continue
normalized_tags.append(self.normalize_tag(tag))
normalized_tags.append(_normalize_tag(tag, max_len))
friendly_tags.append(tag)
genre_tags_dict = dict(zip(friendly_tags,normalized_tags))
@ -1938,8 +1977,6 @@ class CatalogBuilder(object):
self.update_progress_full_step(_("Genres HTML"))
self.genre_tags_dict = self.filter_db_tags()
# Extract books matching filtered_tags
genre_list = []
for friendly_tag in sorted(self.genre_tags_dict, key=sort_key):
@ -2021,10 +2058,11 @@ class CatalogBuilder(object):
books_by_current_author += 1
# Write the genre book list as an article
titles_spanned = self.generate_html_by_genre(genre, True if index==0 else False,
outfile = "%s/Genre_%s.html" % (self.content_dir, genre)
titles_spanned = self.generate_html_by_genre(genre,
True if index==0 else False,
genre_tag_set[genre],
"%s/Genre_%s.html" % (self.content_dir,
genre))
outfile)
tag_file = "content/Genre_%s.html" % genre
master_genre_list.append({'tag':genre,
@ -2546,7 +2584,7 @@ class CatalogBuilder(object):
for (i, tag) in enumerate(sorted(book.get('tags', []))):
aTag = Tag(_soup,'a')
if self.opts.generate_genres:
aTag['href'] = "Genre_%s.html" % self.normalize_tag(tag)
aTag['href'] = "Genre_%s.html" % self.genre_tags_dict[tag]
aTag.insert(0,escape(NavigableString(tag)))
genresTag.insert(gtc, aTag)
gtc += 1
@ -4600,28 +4638,6 @@ class CatalogBuilder(object):
return merged
def normalize_tag(self, tag):
""" Generate an XHTML-legal anchor string from tag.
Parse tag for non-ascii, convert to unicode name.
Args:
tags (str): tag name possible containing symbols
Return:
normalized (str): unicode names substituted for non-ascii chars
"""
normalized = massaged = re.sub('\s','',ascii_text(tag).lower())
if re.search('\W',normalized):
normalized = ''
for c in massaged:
if re.search('\W',c):
normalized += self.generate_unicode_name(c)
else:
normalized += c
return normalized
def process_exclusions(self, data_set):
""" Filter data_set based on exclusion_rules.
@ -4694,6 +4710,43 @@ class CatalogBuilder(object):
else:
return data_set
def relist_multiple_authors(self, books_by_author):
""" Create multiple entries for books with multiple authors
Given a list of books by author, scan list for books with multiple
authors. Add a cloned copy of the book per additional author.
Args:
books_by_author (list): book list possibly containing books
with multiple authors
Return:
(list): books_by_author with additional cloned entries for books with
multiple authors
"""
multiple_author_books = []
# Find the multiple author books
for book in books_by_author:
if len(book['authors']) > 1:
multiple_author_books.append(book)
for book in multiple_author_books:
cloned_authors = list(book['authors'])
for x, author in enumerate(book['authors']):
if x:
first_author = cloned_authors.pop(0)
cloned_authors.append(first_author)
new_book = deepcopy(book)
new_book['author'] = ' & '.join(cloned_authors)
new_book['authors'] = list(cloned_authors)
asl = [author_to_author_sort(auth) for auth in cloned_authors]
new_book['author_sort'] = ' & '.join(asl)
books_by_author.append(new_book)
return books_by_author
def update_progress_full_step(self, description):
""" Update calibre's job status UI.

View File

@ -200,6 +200,11 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
template = re.sub(r'\{series_index[^}]*?\}', '', template)
if mi.rating is not None:
format_args['rating'] = mi.format_rating(divide_by=2.0)
if mi.identifiers:
format_args['identifiers'] = mi.format_field_extended('identifiers')[1]
else:
format_args['identifiers'] = ''
if hasattr(mi.timestamp, 'timetuple'):
format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple())
if hasattr(mi.pubdate, 'timetuple'):

View File

@ -37,11 +37,6 @@ def test_freetype():
test()
print ('FreeType OK!')
def test_sfntly():
from calibre.utils.fonts.subset import test
test()
print ('sfntly OK!')
def test_winutil():
from calibre.devices.scanner import win_pnp_drives
matches = win_pnp_drives.scanner()
@ -120,7 +115,6 @@ def test():
test_plugins()
test_lxml()
test_freetype()
test_sfntly()
test_sqlite()
test_imaging()
test_unrar()

View File

@ -309,8 +309,11 @@ class WindowsAtomicFolderMove(object):
handle = h
break
if handle is None:
if os.path.exists(path):
raise ValueError(u'The file %r did not exist when this move'
' operation was started'%path)
else:
raise ValueError(u'The file %r does not exist'%path)
try:
win32file.CreateHardLink(dest, path)
if os.path.getsize(dest) != os.path.getsize(path):

View File

@ -0,0 +1,74 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from datetime import datetime, timedelta
def align_block(raw, multiple=4, pad=b'\0'):
'''
Return raw with enough pad bytes append to ensure its length is a multiple
of 4.
'''
extra = len(raw) % multiple
if extra == 0: return raw
return raw + pad*(multiple - extra)
class UnknownTable(object):
def __init__(self, raw):
self.raw = raw
def __call__(self):
return self.raw
def __len__(self):
return len(self.raw)
class DateTimeProperty(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, type=None):
return datetime(1904, 1, 1) + timedelta(seconds=getattr(obj,
self.name))
def __set__(self, obj, val):
td = val - datetime(1904, 1, 1)
setattr(obj, self.name, int(td.total_seconds()))
class FixedProperty(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, type=None):
val = getattr(obj, self.name)
return val / 0x10000
def __set__(self, obj, val):
return int(round(val*(0x10000)))
def max_power_of_two(x):
"""
Return the highest exponent of two, so that
(2 ** exponent) <= x
"""
exponent = 0
while x:
x = x >> 1
exponent += 1
return max(exponent - 1, 0)
def load_font(stream_or_path):
raw = stream_or_path
if hasattr(raw, 'read'):
raw = raw.read()
from calibre.utils.fonts.sfnt.container import Sfnt
return Sfnt(raw)

View File

@ -0,0 +1,153 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from struct import unpack_from, unpack
from calibre.utils.fonts.sfnt import UnknownTable
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
# Useful links
# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf
class CFF(object):
def __init__(self, raw):
(self.major_version, self.minor_version, self.header_size,
self.offset_size) = unpack_from(b'>4B', raw)
if (self.major_version, self.minor_version) != (1, 0):
raise UnsupportedFont('The CFF table has unknown version: '
'(%d, %d)'%(self.major_version, self.minor_version))
offset = self.header_size
# Read Names Index
self.font_names = Index(raw, offset)
offset = self.font_names.pos
if len(self.font_names) > 1:
raise UnsupportedFont('CFF table has more than one font.')
# Read Top Dict
self.top_index = Index(raw, offset)
offset = self.top_index.pos
# Read strings
self.strings = Strings(raw, offset)
offset = self.strings.pos
print (self.strings[len(cff_standard_strings):])
class Index(list):
def __init__(self, raw, offset):
list.__init__(self)
count = unpack_from(b'>H', raw, offset)[0]
offset += 2
self.pos = offset
if count > 0:
self.offset_size = unpack_from(b'>B', raw, offset)[0]
offset += 1
if self.offset_size == 3:
offsets = [unpack(b'>L', b'\0' + raw[i:i+3])[0]
for i in xrange(offset, 3*(count+2), 3)]
else:
fmt = {1:'B', 2:'H', 4:'L'}.get(self.offset_size)
fmt = ('>%d%s'%(count+1, fmt)).encode('ascii')
offsets = unpack_from(fmt, raw, offset)
offset += self.offset_size * (count+1) - 1
for i in xrange(len(offsets)-1):
off, noff = offsets[i:i+2]
obj = raw[offset+i:offset+noff]
self.append(obj)
self.pos = offset + offsets[-1]
class Strings(Index):
def __init__(self, raw, offset):
super(Strings, self).__init__(raw, offset)
for x in reversed(cff_standard_strings):
self.insert(0, x)
class CFFTable(UnknownTable):
def decompile(self):
self.cff = CFF(self.raw)
# cff_standard_strings {{{
# The 391 Standard Strings as used in the CFF format.
# from Adobe Technical None #5176, version 1.0, 18 March 1998
cff_standard_strings = [
'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal',
'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft',
'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling',
'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle',
'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl',
'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet',
'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright',
'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex',
'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash',
'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe',
'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf',
'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn',
'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply',
'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave',
'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave',
'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall',
'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior',
'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior',
'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior',
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall',
'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall',
'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall',
'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall',
'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall',
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior',
'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall',
'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall',
'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall',
'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall',
'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall',
'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002',
'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman',
'Semibold'
]
# }}}

View File

@ -0,0 +1,11 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'

View File

@ -0,0 +1,200 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from struct import unpack
t1_operand_encoding = [None] * 256
t1_operand_encoding[0:32] = (32) * ["do_operator"]
t1_operand_encoding[32:247] = (247 - 32) * ["read_byte"]
t1_operand_encoding[247:251] = (251 - 247) * ["read_small_int1"]
t1_operand_encoding[251:255] = (255 - 251) * ["read_small_int2"]
t1_operand_encoding[255] = "read_long_int"
t2_operand_encoding = t1_operand_encoding[:]
t2_operand_encoding[28] = "read_short_int"
t2_operand_encoding[255] = "read_fixed_1616"
cff_dict_operand_encoding = t2_operand_encoding[:]
cff_dict_operand_encoding[29] = "read_long_int"
cff_dict_operand_encoding[30] = "read_real_number"
cff_dict_operand_encoding[255] = "reserved"
real_nibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'.', 'E', 'E-', None, '-']
class SimpleConverter(object):
def read(self, parent, value):
return value
def write(self, parent, value):
return value
class TODO(SimpleConverter):
pass
class Reader(dict):
def read_byte(self, b0, data, index):
return b0 - 139, index
def read_small_int1(self, b0, data, index):
b1 = ord(data[index])
return (b0-247)*256 + b1 + 108, index+1
def read_small_int2(self, b0, data, index):
b1 = ord(data[index])
return -(b0-251)*256 - b1 - 108, index+1
def read_short_int(self, b0, data, index):
bin = data[index] + data[index+1]
value, = unpack(b">h", bin)
return value, index+2
def read_long_int(self, b0, data, index):
bin = data[index] + data[index+1] + data[index+2] + data[index+3]
value, = unpack(b">l", bin)
return value, index+4
def read_fixed_1616(self, b0, data, index):
bin = data[index] + data[index+1] + data[index+2] + data[index+3]
value, = unpack(b">l", bin)
return value / 65536.0, index+4
def read_real_number(self, b0, data, index):
number = ''
while True:
b = ord(data[index])
index = index + 1
nibble0 = (b & 0xf0) >> 4
nibble1 = b & 0x0f
if nibble0 == 0xf:
break
number = number + real_nibbles[nibble0]
if nibble1 == 0xf:
break
number = number + real_nibbles[nibble1]
return float(number), index
class Dict(Reader):
operand_encoding = cff_dict_operand_encoding
TABLE = []
def __init__(self):
Reader.__init__(self)
table = self.TABLE[:]
for i in xrange(len(table)):
op, name, arg, default, conv = table[i]
if conv is not None:
continue
if arg in ("delta", "array", 'number', 'SID'):
conv = SimpleConverter()
else:
raise Exception('Should not happen')
table[i] = op, name, arg, default, conv
self.operators = {op:(name, arg) for op, name, arg, default, conv in
table}
def decompile(self, strings, data):
self.strings = strings
self.stack = []
index = 0
while index < len(data):
b0 = ord(data[index])
index += 1
handler = getattr(self, self.operand_encoding[b0])
value, index = handler(b0, data, index)
if value is not None:
self.stack.append(value)
def do_operator(self, b0, data, index):
if b0 == 12:
op = (b0, ord(data[index]))
index += 1
else:
op = b0
operator, arg_type = self.operators[op]
self.handle_operator(operator, arg_type)
return None, index
def handle_operator(self, operator, arg_type):
if isinstance(arg_type, tuple):
value = ()
for i in xrange(len(arg_type)-1, -1, -1):
arg = arg_type[i]
arghandler = getattr(self, 'arg_' + arg)
value = (arghandler(operator),) + value
else:
arghandler = getattr(self, 'arg_' + arg_type)
value = arghandler(operator)
self[operator] = value
def arg_number(self, name):
return self.stack.pop()
def arg_SID(self, name):
return self.strings[self.stack.pop()]
def arg_array(self, name):
ans = self.stack[:]
del self.stack[:]
return ans
def arg_delta(self, name):
out = []
current = 0
for v in self.stack:
current = current + v
out.append(current)
del self.stack[:]
return out
class TopDict(Dict):
TABLE = [
#opcode name argument type default converter
((12, 30), 'ROS', ('SID','SID','number'), None, SimpleConverter()),
((12, 20), 'SyntheticBase', 'number', None, None),
(0, 'version', 'SID', None, None),
(1, 'Notice', 'SID', None, None),
((12, 0), 'Copyright', 'SID', None, None),
(2, 'FullName', 'SID', None, None),
((12, 38), 'FontName', 'SID', None, None),
(3, 'FamilyName', 'SID', None, None),
(4, 'Weight', 'SID', None, None),
((12, 1), 'isFixedPitch', 'number', 0, None),
((12, 2), 'ItalicAngle', 'number', 0, None),
((12, 3), 'UnderlinePosition', 'number', None, None),
((12, 4), 'UnderlineThickness', 'number', 50, None),
((12, 5), 'PaintType', 'number', 0, None),
((12, 6), 'CharstringType', 'number', 2, None),
((12, 7), 'FontMatrix', 'array', [0.001,0,0,0.001,0,0], None),
(13, 'UniqueID', 'number', None, None),
(5, 'FontBBox', 'array', [0,0,0,0], None),
((12, 8), 'StrokeWidth', 'number', 0, None),
(14, 'XUID', 'array', None, None),
((12, 21), 'PostScript', 'SID', None, None),
((12, 22), 'BaseFontName', 'SID', None, None),
((12, 23), 'BaseFontBlend', 'delta', None, None),
((12, 31), 'CIDFontVersion', 'number', 0, None),
((12, 32), 'CIDFontRevision', 'number', 0, None),
((12, 33), 'CIDFontType', 'number', 0, None),
((12, 34), 'CIDCount', 'number', 8720, None),
(15, 'charset', 'number', 0, TODO()),
((12, 35), 'UIDBase', 'number', None, None),
(16, 'Encoding', 'number', 0, TODO()),
(18, 'Private', ('number','number'), None, TODO()),
((12, 37), 'FDSelect', 'number', None, TODO()),
((12, 36), 'FDArray', 'number', None, TODO()),
(17, 'CharStrings', 'number', None, TODO()),
]

View File

@ -0,0 +1,159 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from struct import unpack_from, unpack
from calibre.utils.fonts.sfnt import UnknownTable
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
from calibre.utils.fonts.sfnt.cff.dict_data import TopDict
# Useful links
# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
# http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf
class CFF(object):
def __init__(self, raw):
(self.major_version, self.minor_version, self.header_size,
self.offset_size) = unpack_from(b'>4B', raw)
if (self.major_version, self.minor_version) != (1, 0):
raise UnsupportedFont('The CFF table has unknown version: '
'(%d, %d)'%(self.major_version, self.minor_version))
offset = self.header_size
# Read Names Index
self.font_names = Index(raw, offset)
offset = self.font_names.pos
if len(self.font_names) > 1:
raise UnsupportedFont('CFF table has more than one font.')
# Read Top Dict
self.top_index = Index(raw, offset)
self.top_dict = TopDict()
offset = self.top_index.pos
# Read strings
self.strings = Strings(raw, offset)
offset = self.strings.pos
# Decompile Top Dict
self.top_dict.decompile(self.strings, self.top_index[0])
import pprint
pprint.pprint(self.top_dict)
class Index(list):
def __init__(self, raw, offset, prepend=()):
list.__init__(self)
self.extend(prepend)
count = unpack_from(b'>H', raw, offset)[0]
offset += 2
self.pos = offset
if count > 0:
self.offset_size = unpack_from(b'>B', raw, offset)[0]
offset += 1
if self.offset_size == 3:
offsets = [unpack(b'>L', b'\0' + raw[i:i+3])[0]
for i in xrange(offset, 3*(count+2), 3)]
else:
fmt = {1:'B', 2:'H', 4:'L'}.get(self.offset_size)
fmt = ('>%d%s'%(count+1, fmt)).encode('ascii')
offsets = unpack_from(fmt, raw, offset)
offset += self.offset_size * (count+1) - 1
for i in xrange(len(offsets)-1):
off, noff = offsets[i:i+2]
obj = raw[offset+off:offset+noff]
self.append(obj)
self.pos = offset + offsets[-1]
class Strings(Index):
def __init__(self, raw, offset):
super(Strings, self).__init__(raw, offset, prepend=cff_standard_strings)
class CFFTable(UnknownTable):
def decompile(self):
self.cff = CFF(self.raw)
# cff_standard_strings {{{
# The 391 Standard Strings as used in the CFF format.
# from Adobe Technical None #5176, version 1.0, 18 March 1998
cff_standard_strings = [
'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal',
'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft',
'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling',
'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle',
'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl',
'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet',
'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright',
'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex',
'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash',
'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe',
'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf',
'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn',
'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply',
'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave',
'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave',
'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall',
'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior',
'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior',
'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior',
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall',
'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall',
'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall',
'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall',
'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall',
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior',
'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall',
'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall',
'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall',
'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall',
'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall',
'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002',
'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman',
'Semibold'
]
# }}}

View File

@ -0,0 +1,236 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
# Note that the code for creating a BMP table (cmap format 4) is taken with
# thanks from the fonttools project (BSD licensed).
from struct import unpack_from, calcsize, pack
from collections import OrderedDict
from calibre.utils.fonts.utils import get_bmp_glyph_ids
from calibre.utils.fonts.sfnt import UnknownTable, max_power_of_two
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
def split_range(start_code, end_code, cmap): # {{{
# Try to split a range of character codes into subranges with consecutive
# glyph IDs in such a way that the cmap4 subtable can be stored "most"
# efficiently.
if start_code == end_code:
return [], [end_code]
last_id = cmap[start_code]
last_code = start_code
in_order = None
ordered_begin = None
sub_ranges = []
# Gather subranges in which the glyph IDs are consecutive.
for code in range(start_code + 1, end_code + 1):
glyph_id = cmap[code]
if glyph_id - 1 == last_id:
if in_order is None or not in_order:
in_order = 1
ordered_begin = last_code
else:
if in_order:
in_order = 0
sub_ranges.append((ordered_begin, last_code))
ordered_begin = None
last_id = glyph_id
last_code = code
if in_order:
sub_ranges.append((ordered_begin, last_code))
assert last_code == end_code
# Now filter out those new subranges that would only make the data bigger.
# A new segment cost 8 bytes, not using a new segment costs 2 bytes per
# character.
new_ranges = []
for b, e in sub_ranges:
if b == start_code and e == end_code:
break # the whole range, we're fine
if b == start_code or e == end_code:
threshold = 4 # split costs one more segment
else:
threshold = 8 # split costs two more segments
if (e - b + 1) > threshold:
new_ranges.append((b, e))
sub_ranges = new_ranges
if not sub_ranges:
return [], [end_code]
if sub_ranges[0][0] != start_code:
sub_ranges.insert(0, (start_code, sub_ranges[0][0] - 1))
if sub_ranges[-1][1] != end_code:
sub_ranges.append((sub_ranges[-1][1] + 1, end_code))
# Fill the "holes" in the segments list -- those are the segments in which
# the glyph IDs are _not_ consecutive.
i = 1
while i < len(sub_ranges):
if sub_ranges[i-1][1] + 1 != sub_ranges[i][0]:
sub_ranges.insert(i, (sub_ranges[i-1][1] + 1, sub_ranges[i][0] - 1))
i = i + 1
i = i + 1
# Transform the ranges into start_code/end_code lists.
start = []
end = []
for b, e in sub_ranges:
start.append(b)
end.append(e)
start.pop(0)
assert len(start) + 1 == len(end)
return start, end
# }}}
def set_id_delta(id_delta): # {{{
# The lowest gid in glyphIndexArray, after subtracting id_delta, must be 1.
# id_delta is a short, and must be between -32K and 32K
# startCode can be between 0 and 64K-1, and the first glyph index can be between 1 and 64K-1
# This means that we have a problem because we can need to assign to
# id_delta values
# between -(64K-2) and 64K -1.
# Since the final gi is reconstructed from the glyphArray GID by:
# (short)finalGID = (gid + id_delta) % 0x10000),
# we can get from a startCode of 0 to a final GID of 64 -1K by subtracting 1, and casting the
# negative number to an unsigned short.
# Similarly , we can get from a startCode of 64K-1 to a final GID of 1 by adding 2, because of
# the modulo arithmetic.
if id_delta > 0x7FFF:
id_delta = id_delta - 0x10000
elif id_delta < -0x7FFF:
id_delta = id_delta + 0x10000
return id_delta
# }}}
class CmapTable(UnknownTable):
def __init__(self, *args, **kwargs):
super(CmapTable, self).__init__(*args, **kwargs)
self.version, self.num_tables = unpack_from(b'>HH', self.raw)
self.tables = {}
offset = 4
sz = calcsize(b'>HHL')
recs = []
for i in xrange(self.num_tables):
platform, encoding, table_offset = unpack_from(b'>HHL', self.raw,
offset)
offset += sz
recs.append((platform, encoding, table_offset))
self.bmp_table = None
for i in xrange(len(recs)):
platform, encoding, offset = recs[i]
try:
next_offset = recs[i+1][-1]
except IndexError:
next_offset = len(self.raw)
table = self.raw[offset:next_offset]
if table:
fmt = unpack_from(b'>H', table)[0]
if platform == 3 and encoding == 1 and fmt == 4:
self.bmp_table = table
def get_character_map(self, chars):
'''
Get a mapping of character codes to glyph ids in the font.
'''
if self.bmp_table is None:
raise UnsupportedFont('This font has no Windows BMP cmap subtable.'
' Most likely a special purpose font.')
chars = list(set(chars))
chars.sort()
ans = OrderedDict()
for i, glyph_id in enumerate(get_bmp_glyph_ids(self.bmp_table, 0,
chars)):
if glyph_id > 0:
ans[chars[i]] = glyph_id
return ans
def set_character_map(self, cmap):
self.version, self.num_tables = 0, 1
fmt = b'>7H'
codes = list(cmap.iterkeys())
codes.sort()
if not codes:
start_code = [0xffff]
end_code = [0xffff]
else:
last_code = codes[0]
end_code = []
start_code = [last_code]
for code in codes[1:]:
if code == last_code + 1:
last_code = code
continue
start, end = split_range(start_code[-1], last_code, cmap)
start_code.extend(start)
end_code.extend(end)
start_code.append(code)
last_code = code
end_code.append(last_code)
start_code.append(0xffff)
end_code.append(0xffff)
id_delta = []
id_range_offset = []
glyph_index_array = []
for i in xrange(len(end_code)-1): # skip the closing codes (0xffff)
indices = []
for char_code in xrange(start_code[i], end_code[i] + 1):
indices.append(cmap[char_code])
if (indices == xrange(indices[0], indices[0] + len(indices))):
id_delta_temp = set_id_delta(indices[0] - start_code[i])
id_delta.append(id_delta_temp)
id_range_offset.append(0)
else:
id_delta.append(0)
id_range_offset.append(2 * (len(end_code) +
len(glyph_index_array) - i))
glyph_index_array.extend(indices)
id_delta.append(1) # 0xffff + 1 == 0. So this end code maps to .notdef
id_range_offset.append(0)
seg_count = len(end_code)
max_exponent = max_power_of_two(seg_count)
search_range = 2 * (2 ** max_exponent)
entry_selector = max_exponent
range_shift = 2 * seg_count - search_range
char_code_array = end_code + [0] + start_code
char_code_array = pack(b'>%dH'%len(char_code_array), *char_code_array)
id_delta_array = pack(b'>%dh'%len(id_delta), *id_delta)
rest_array = id_range_offset + glyph_index_array
rest_array = pack(b'>%dH'%len(rest_array), *rest_array)
data = char_code_array + id_delta_array + rest_array
length = calcsize(fmt) + len(data)
header = pack(fmt, 4, length, 0,
2*seg_count, search_range, entry_selector, range_shift)
self.bmp_table = header + data
fmt = b'>4HL'
offset = calcsize(fmt)
self.raw = pack(fmt, self.version, self.num_tables, 3, 1, offset) + \
self.bmp_table

View File

@ -0,0 +1,127 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from struct import pack, calcsize
from io import BytesIO
from collections import OrderedDict
from calibre.utils.fonts.utils import (get_tables, checksum_of_block,
verify_checksums)
from calibre.utils.fonts.sfnt import align_block, UnknownTable, max_power_of_two
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
from calibre.utils.fonts.sfnt.head import HeadTable
from calibre.utils.fonts.sfnt.maxp import MaxpTable
from calibre.utils.fonts.sfnt.loca import LocaTable
from calibre.utils.fonts.sfnt.glyf import GlyfTable
from calibre.utils.fonts.sfnt.cmap import CmapTable
from calibre.utils.fonts.sfnt.cff.table import CFFTable
# OpenType spec: http://www.microsoft.com/typography/otspec/otff.htm
class Sfnt(object):
def __init__(self, raw):
self.sfnt_version = raw[:4]
if self.sfnt_version not in {b'\x00\x01\x00\x00', b'OTTO', b'true',
b'type1'}:
raise UnsupportedFont('Font has unknown sfnt version: %r'%self.sfnt_version)
self.read_tables(raw)
def read_tables(self, raw):
self.tables = {}
for table_tag, table, table_index, table_offset, table_checksum in get_tables(raw):
self.tables[table_tag] = {
b'head' : HeadTable,
b'maxp' : MaxpTable,
b'loca' : LocaTable,
b'glyf' : GlyfTable,
b'cmap' : CmapTable,
b'CFF ' : CFFTable,
}.get(table_tag, UnknownTable)(table)
def __getitem__(self, key):
return self.tables[key]
def __contains__(self, key):
return key in self.tables
def __delitem__(self, key):
del self.tables[key]
def pop(self, key, default=None):
return self.tables.pop(key, default)
def sizes(self):
ans = OrderedDict()
for tag in sorted(self.tables):
ans[tag] = len(self[tag])
return ans
def __call__(self):
stream = BytesIO()
def spack(*args):
stream.write(pack(*args))
stream.seek(0)
# Write header
num_tables = len(self.tables)
ln2 = max_power_of_two(num_tables)
srange = (2**ln2) * 16
spack(b'>4s4H',
self.sfnt_version, num_tables, srange, ln2, num_tables * 16 - srange)
# Write tables
head_offset = None
table_data = []
offset = stream.tell() + ( calcsize(b'>4s3L') * num_tables )
sizes = OrderedDict()
for tag in sorted(self.tables):
table = self.tables[tag]
raw = table()
table_len = len(raw)
if tag == b'head':
head_offset = offset
raw = raw[:8] + b'\0\0\0\0' + raw[12:]
raw = align_block(raw)
checksum = checksum_of_block(raw)
spack(b'>4s3L', tag, checksum, offset, table_len)
offset += len(raw)
table_data.append(raw)
sizes[tag] = table_len
for x in table_data:
stream.write(x)
checksum = checksum_of_block(stream.getvalue())
q = (0xB1B0AFBA - checksum) & 0xffffffff
stream.seek(head_offset + 8)
spack(b'>L', q)
return stream.getvalue(), sizes
def test_roundtrip(ff=None):
if ff is None:
data = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True)
else:
with open(ff, 'rb') as f:
data = f.read()
rd = Sfnt(data)()[0]
verify_checksums(rd)
if data[:12] != rd[:12]:
raise ValueError('Roundtripping failed, font header not the same')
if len(data) != len(rd):
raise ValueError('Roundtripping failed, size different')
if __name__ == '__main__':
import sys
test_roundtrip(sys.argv[-1])

View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
class UnsupportedFont(ValueError):
pass
class NoGlyphs(ValueError):
pass

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from struct import unpack_from
from collections import OrderedDict
from calibre.utils.fonts.sfnt import UnknownTable
ARG_1_AND_2_ARE_WORDS = 0x0001 # if set args are words otherwise they are bytes
ARGS_ARE_XY_VALUES = 0x0002 # if set args are xy values, otherwise they are points
ROUND_XY_TO_GRID = 0x0004 # for the xy values if above is true
WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0
NON_OVERLAPPING = 0x0010 # set to same value for all components (obsolete!)
MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one
WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy
WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11
WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow
USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph
OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts
SCALED_COMPONENT_OFFSET = 0x0800 # composite designed to have the component offset scaled (designed for Apple)
UNSCALED_COMPONENT_OFFSET = 0x1000 # composite designed not to have the component offset scaled (designed for MS)
class SimpleGlyph(object):
def __init__(self, num_of_countours, raw):
self.num_of_countours = num_of_countours
self.raw = raw
# The list of glyph indices referred to by this glyph, will always be
# empty for a simple glyph and not empty for a composite glyph
self.glyph_indices = []
self.is_composite = False
def __len__(self):
return len(self.raw)
def __call__(self):
return self.raw
class CompositeGlyph(SimpleGlyph):
def __init__(self, num_of_countours, raw):
super(CompositeGlyph, self).__init__(num_of_countours, raw)
self.is_composite = True
flags = MORE_COMPONENTS
offset = 10
while flags & MORE_COMPONENTS:
flags, glyph_index = unpack_from(b'>HH', raw, offset)
self.glyph_indices.append(glyph_index)
offset += 4
if flags & ARG_1_AND_2_ARE_WORDS:
offset += 4
else:
offset += 2
if flags & WE_HAVE_A_SCALE:
offset += 2
elif flags & WE_HAVE_AN_X_AND_Y_SCALE:
offset += 4
elif flags & WE_HAVE_A_TWO_BY_TWO:
offset += 8
class GlyfTable(UnknownTable):
def glyph_data(self, offset, length):
raw = self.raw[offset:offset+length]
num_of_countours = unpack_from(b'>h', raw)[0] if raw else 0
if num_of_countours >= 0:
return SimpleGlyph(num_of_countours, raw)
return CompositeGlyph(num_of_countours, raw)
def update(self, sorted_glyph_map):
ans = OrderedDict()
offset = 0
block = []
for glyph_id, glyph in sorted_glyph_map.iteritems():
raw = glyph()
ans[glyph_id] = (offset, len(raw))
offset += len(raw)
block.append(raw)
self.raw = b''.join(block)
return ans

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from itertools import izip
from struct import unpack_from, pack
from calibre.utils.fonts.sfnt import UnknownTable, DateTimeProperty, FixedProperty
class HeadTable(UnknownTable):
created = DateTimeProperty('_created')
modified = DateTimeProperty('_modified')
version_number = FixedProperty('_version_number')
font_revision = FixedProperty('_font_revision')
def __init__(self, *args, **kwargs):
super(HeadTable, self).__init__(*args, **kwargs)
field_types = (
'_version_number' , 'l',
'_font_revision' , 'l',
'checksum_adjustment' , 'L',
'magic_number' , 'L',
'flags' , 'H',
'units_per_em' , 'H',
'_created' , 'q',
'_modified' , 'q',
'x_min' , 'H',
'y_min' , 'H',
'x_max' , 'H',
'y_max' , 'H',
'mac_style' , 'H',
'lowest_rec_ppem' , 'H',
'font_direction_hint' , 'h',
'index_to_loc_format' , 'h',
'glyph_data_format' , 'h'
)
self._fmt = ('>%s'%(''.join(field_types[1::2]))).encode('ascii')
self._fields = field_types[0::2]
for f, val in izip(self._fields, unpack_from(self._fmt, self.raw)):
setattr(self, f, val)
def update(self):
vals = [getattr(self, f) for f in self._fields]
self.raw = pack(self._fmt, *vals)

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from struct import calcsize, unpack_from, pack
from operator import itemgetter
from calibre.utils.fonts.sfnt import UnknownTable
class LocaTable(UnknownTable):
def load_offsets(self, head_table, maxp_table):
fmt = 'H' if head_table.index_to_loc_format == 0 else 'L'
num_glyphs = maxp_table.num_glyphs
sz = calcsize(('>%s'%fmt).encode('ascii'))
num = len(self.raw)//sz
self.offset_map = unpack_from(('>%d%s'%(num, fmt)).encode('ascii'),
self.raw)
self.offset_map = self.offset_map[:num_glyphs+1]
if fmt == 'H':
self.offset_map = [2*i for i in self.offset_map]
self.fmt = fmt
def glyph_location(self, glyph_id):
offset = self.offset_map[glyph_id]
next_offset = self.offset_map[glyph_id+1]
return offset, next_offset - offset
def subset(self, resolved_glyph_map):
'''
Update this table to contain pointers only to the glyphs in
resolved_glyph_map which must be a map of glyph_ids to (offset, sz)
'''
self.offset_map = [0 for i in self.offset_map]
glyphs = [(glyph_id, x[0], x[1]) for glyph_id, x in
resolved_glyph_map.iteritems()]
glyphs.sort(key=itemgetter(1))
for glyph_id, offset, sz in glyphs:
self.offset_map[glyph_id] = offset
self.offset_map[glyph_id+1] = offset + sz
# Fix all zero entries to be the same as the previous entry, which
# means that if the ith entry is zero, the i-1 glyph is not present.
for i in xrange(1, len(self.offset_map)):
if self.offset_map[i] == 0:
self.offset_map[i] = self.offset_map[i-1]
vals = self.offset_map
if self.fmt == 'H':
vals = [i//2 for i in self.offset_map]
self.raw = pack(('>%d%s'%(len(vals), self.fmt)).encode('ascii'), *vals)
def dump_glyphs(self, sfnt):
if not hasattr(self, 'offset_map'):
self.load_offsets(sfnt[b'head'], sfnt[b'maxp'])
for i in xrange(len(self.offset_map)-1):
off, noff = self.offset_map[i], self.offset_map[i+1]
if noff != off:
print ('Glyph id:', i, 'size:', noff-off)

View File

@ -0,0 +1,49 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from itertools import izip
from struct import unpack_from, pack
from calibre.utils.fonts.sfnt import UnknownTable, FixedProperty
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
class MaxpTable(UnknownTable):
version = FixedProperty('_version')
def __init__(self, *args, **kwargs):
super(MaxpTable, self).__init__(*args, **kwargs)
self._fmt = b'>lH'
self._version, self.num_glyphs = unpack_from(self._fmt, self.raw)
self.fields = ('_version', 'num_glyphs')
if self.version > 1.0:
raise UnsupportedFont('This font has a maxp table with version: %s'
%self.version)
if self.version == 1.0:
self.fields = ('_version', 'num_glyphs', 'max_points',
'max_contours', 'max_composite_points',
'max_composite_contours', 'max_zones',
'max_twilight_points', 'max_storage', 'max_function_defs',
'max_instruction_defs', 'max_stack_elements',
'max_size_of_instructions', 'max_component_elements',
'max_component_depth')
self._fmt = b'>lH' + b'H'*(len(self.fields)-2)
vals = unpack_from(self._fmt, self.raw)
for f, val in izip(self.fields, vals):
setattr(self, f, val)
def update(self):
vals = [getattr(self, f) for f in self._fields]
self.raw = pack(self._fmt, *vals)

View File

@ -7,45 +7,112 @@ __license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from future_builtins import map
from collections import OrderedDict
from operator import itemgetter
class NoGlyphs(ValueError):
'Raised when the font has no glyphs for the specified characters'
pass
from calibre.utils.fonts.sfnt.container import Sfnt
from calibre.utils.fonts.sfnt.errors import UnsupportedFont, NoGlyphs
class UnsupportedFont(ValueError):
'Raised when the font is not supported for subsetting '
'(usually an OTF font with PostScript outlines).'
pass
# TrueType outlines {{{
def load_sfntly():
from calibre.constants import plugins
sfntly, err = plugins['sfntly']
if err:
raise RuntimeError('Failed to load sfntly: %s'%err)
return sfntly
def resolve_glyphs(loca, glyf, character_map):
unresolved_glyphs = set(character_map.itervalues())
unresolved_glyphs.add(0) # We always want the .notdef glyph
resolved_glyphs = {}
def subset(font_data, individual_chars, ranges=()):
if font_data[:4] not in {b'\x00\x01\x00\x00', b'OTTO', b'true', b'typ1'}:
raise ValueError('Not a supported font file. sfnt_version not recognized: %r'%
font_data[:4])
individual = tuple(sorted(map(ord, individual_chars)))
cranges = []
for s, e in ranges:
sc, ec = map(ord, (s, e))
if ec <= sc:
raise ValueError('The start character %s is after the end'
' character %s'%(s, e))
cranges.append((sc, ec))
sfntly = load_sfntly()
while unresolved_glyphs:
glyph_id = unresolved_glyphs.pop()
try:
return sfntly.subset(font_data, individual, tuple(cranges))
except sfntly.NoGlyphs:
raise NoGlyphs('No glyphs were found in this font for the'
' specified characters. Subsetting is pointless')
except sfntly.UnsupportedFont as e:
raise UnsupportedFont(type('')(e))
offset, length = loca.glyph_location(glyph_id)
except (IndexError, ValueError, KeyError, TypeError):
continue
if length < 1:
continue
glyph = glyf.glyph_data(offset, length)
if len(glyph) == 0:
continue
resolved_glyphs[glyph_id] = glyph
for gid in glyph.glyph_indices:
if gid not in resolved_glyphs:
unresolved_glyphs.add(gid)
return OrderedDict(sorted(resolved_glyphs.iteritems(), key=itemgetter(0)))
def subset_truetype(sfnt, character_map):
loca = sfnt[b'loca']
glyf = sfnt[b'glyf']
try:
head, maxp = sfnt[b'head'], sfnt[b'maxp']
except KeyError:
raise UnsupportedFont('This font does not contain head and/or maxp tables')
loca.load_offsets(head, maxp)
resolved_glyphs = resolve_glyphs(loca, glyf, character_map)
if not resolved_glyphs or set(resolved_glyphs) == {0}:
raise NoGlyphs('This font has no glyphs for the specified character '
'set, subsetting it is pointless')
# Keep only character codes that have resolved glyphs
for code, glyph_id in tuple(character_map.iteritems()):
if glyph_id not in resolved_glyphs:
del character_map[code]
# Update the glyf table
glyph_offset_map = glyf.update(resolved_glyphs)
# Update the loca table
loca.subset(glyph_offset_map)
# }}}
def subset_postscript(sfnt, character_map):
cff = sfnt[b'CFF ']
cff.decompile()
raise Exception('TODO: Implement CFF subsetting')
def subset(raw, individual_chars, ranges=()):
chars = list(map(ord, individual_chars))
for r in ranges:
chars += list(xrange(ord(r[0]), ord(r[1])+1))
sfnt = Sfnt(raw)
old_sizes = sfnt.sizes()
# Remove the Digital Signature table since it is useless in a subset
# font anyway
sfnt.pop(b'DSIG', None)
try:
cmap = sfnt[b'cmap']
except KeyError:
raise UnsupportedFont('This font has no cmap table')
# Get mapping of chars to glyph ids for all specified chars
character_map = cmap.get_character_map(chars)
if b'loca' in sfnt and b'glyf' in sfnt:
# TrueType Outlines
subset_truetype(sfnt, character_map)
elif b'CFF ' in sfnt:
# PostScript Outlines
from calibre.utils.config_base import tweaks
if tweaks['subset_cff_table']:
subset_postscript(sfnt, character_map)
else:
raise UnsupportedFont('This font contains PostScript outlines, '
'subsetting not supported')
else:
raise UnsupportedFont('This font does not contain TrueType '
'or PostScript outlines')
# Restrict the cmap table to only contain entries for the resolved glyphs
cmap.set_character_map(character_map)
raw, new_sizes = sfnt()
return raw, old_sizes, new_sizes
# CLI {{{
def option_parser():
import textwrap
from calibre.utils.config import OptionParser
@ -87,65 +154,6 @@ def print_stats(old_stats, new_stats):
'%10s'%nsz, ' ', '%5.1f %%'%np, suffix)
prints('='*80)
def test_mem():
load_sfntly()
from calibre.utils.mem import memory
import gc
gc.collect()
start_mem = memory()
raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True)
calls = 1000
for i in xrange(calls):
subset(raw, (), (('a', 'z'),))
del raw
for i in xrange(3): gc.collect()
print ('Leaked memory per call:', (memory() - start_mem)/calls*1024, 'KB')
def test():
raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True)
sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ())
if len(sf) > 0.3 * len(raw):
raise Exception('Subsetting failed')
def all():
from calibre.utils.fonts.scanner import font_scanner
failed = []
unsupported = []
total = 0
for family in font_scanner.find_font_families():
for font in font_scanner.fonts_for_family(family):
raw = font_scanner.get_font_data(font)
print ('Subsetting', font['full_name'], end='\t')
total += 1
try:
sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ())
except NoGlyphs:
continue
except UnsupportedFont as e:
unsupported.append((font['full_name'], font['path'], unicode(e)))
print ('Unsupported!')
continue
except Exception as e:
print ('Failed!')
failed.append((font['full_name'], font['path'], unicode(e)))
else:
print ('Reduced to:', '%.1f'%(
sum(new_stats.itervalues())/sum(old_stats.itervalues())
* 100), '%')
if unsupported:
print ('\n\nUnsupported:')
for name, path, err in unsupported:
print (name, path, err)
print()
if failed:
print ('\n\nFailures:')
for name, path, err in failed:
print (name, path, err)
print()
print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:',
len(failed))
def main(args):
import sys, time
@ -203,5 +211,69 @@ if __name__ == '__main__':
pass
import sys
main(sys.argv)
# }}}
# Tests {{{
def test_mem():
from calibre.utils.mem import memory
import gc
gc.collect()
start_mem = memory()
raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True)
calls = 1000
for i in xrange(calls):
subset(raw, (), (('a', 'z'),))
del raw
for i in xrange(3): gc.collect()
print ('Leaked memory per call:', (memory() - start_mem)/calls*1024, 'KB')
def test():
raw = P('fonts/liberation/LiberationSerif-Regular.ttf', data=True)
sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ())
if len(sf) > 0.3 * len(raw):
raise Exception('Subsetting failed')
def all():
from calibre.utils.fonts.scanner import font_scanner
failed = []
unsupported = []
total = 0
for family in font_scanner.find_font_families():
for font in font_scanner.fonts_for_family(family):
raw = font_scanner.get_font_data(font)
print ('Subsetting', font['full_name'], end='\t')
total += 1
try:
sf, old_stats, new_stats = subset(raw, set(('a', 'b', 'c')), ())
except NoGlyphs:
print('No glyphs!')
continue
except UnsupportedFont as e:
unsupported.append((font['full_name'], font['path'], unicode(e)))
print ('Unsupported!')
continue
except Exception as e:
print ('Failed!')
failed.append((font['full_name'], font['path'], unicode(e)))
else:
print ('Reduced to:', '%.1f'%(
sum(new_stats.itervalues())/sum(old_stats.itervalues())
* 100), '%')
if unsupported:
print ('\n\nUnsupported:')
for name, path, err in unsupported:
print (name, path, err)
print()
if failed:
print ('\n\nFailures:')
for name, path, err in failed:
print (name, path, err)
print()
print('Total:', total, 'Unsupported:', len(unsupported), 'Failed:',
len(failed))
# }}}

View File

@ -1,628 +0,0 @@
/*
* sfntly.cpp
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#define _UNICODE
#define UNICODE
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "sfntly.h"
#include <new>
#include <sfntly/port/memory_input_stream.h>
#include <sfntly/port/memory_output_stream.h>
static PyObject *Error = NULL;
static PyObject *NoGlyphs = NULL;
static PyObject *UnsupportedFont = NULL;
// Predicates {{{
CompositePredicate::CompositePredicate(IntegerSet &chars, IntegerList &ranges) :
chars(chars), ranges(ranges) {}
CompositePredicate::~CompositePredicate() {}
bool CompositePredicate::operator()(int32_t character) const {
for (size_t i = 0; i < ranges.size()/2; i++) {
if (ranges[2*i] <= character && character <= ranges[2*i+1]) return true;
}
return chars.count(character) > 0;
}
// }}}
// Font Info {{{
GlyphId::GlyphId(int32_t glyph_id, FontId font_id) : glyph_id_(glyph_id), font_id_(font_id) {}
GlyphId::~GlyphId() {}
bool GlyphId::operator==(const GlyphId& other) const { return glyph_id_ == other.glyph_id(); }
bool GlyphId::operator<(const GlyphId& other) const { return glyph_id_ < other.glyph_id(); }
int32_t GlyphId::glyph_id() const { return glyph_id_; }
void GlyphId::set_glyph_id(const int32_t glyph_id) { glyph_id_ = glyph_id; }
FontId GlyphId::font_id() const { return font_id_; }
void GlyphId::set_font_id(const FontId font_id) { font_id_ = font_id; }
FontInfo::FontInfo() : chars_to_glyph_ids_(new CharacterMap),
resolved_glyph_ids_(new GlyphIdSet), fonts_(new FontIdMap) { }
FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids,
GlyphIdSet* resolved_glyph_ids,
FontIdMap* fonts) {
chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(),
chars_to_glyph_ids->end());
resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(),
resolved_glyph_ids->end());
fonts_ = new FontIdMap(fonts->begin(), fonts->end());
}
FontInfo::~FontInfo() {
delete chars_to_glyph_ids_;
delete resolved_glyph_ids_;
delete fonts_;
}
FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) {
if (!fonts_)
return NULL;
FontIdMap::iterator it = fonts_->find(font_id);
if (it == fonts_->end())
return NULL;
return it->second->GetTable(tag);
}
const TableMap* FontInfo::GetTableMap(FontId font_id) {
if (!fonts_)
return NULL;
FontIdMap::iterator it = fonts_->find(font_id);
if (it == fonts_->end())
return NULL;
return it->second->GetTableMap();
}
CharacterMap* FontInfo::chars_to_glyph_ids() const { return chars_to_glyph_ids_; }
void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) { *chars_to_glyph_ids_ = *chars_to_glyph_ids; }
GlyphIdSet* FontInfo::resolved_glyph_ids() const { return resolved_glyph_ids_; }
void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) { *resolved_glyph_ids_ = *resolved_glyph_ids; }
FontIdMap* FontInfo::fonts() const { return fonts_; }
void FontInfo::set_fonts(FontIdMap* fonts) { *fonts_ = *fonts; }
FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id) : font_(font), font_id_(font_id),
predicate_(NULL) { Initialize(); }
FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font,
FontId font_id,
CharacterPredicate* predicate) :
font_(font), font_id_(font_id), predicate_(predicate) { Initialize(); }
FontSourcedInfoBuilder::~FontSourcedInfoBuilder() { }
CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() {
if (!cmap_) {
PyErr_SetString(UnsupportedFont, "This font has no format 4 cmap table (usually symbol or asian fonts), subsetting is not supported");
return NULL;
}
CharacterMap* chars_to_glyph_ids = new CharacterMap;
bool success = GetCharacterMap(chars_to_glyph_ids);
if (!success) {
delete chars_to_glyph_ids;
if (!PyErr_Occurred()) PyErr_SetString(Error, "Error creating character map.\n");
return NULL;
}
GlyphIdSet* resolved_glyph_ids = new GlyphIdSet;
success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids);
if (!success) {
delete chars_to_glyph_ids;
delete resolved_glyph_ids;
if (!PyErr_Occurred()) PyErr_SetString(Error, "Error resolving composite glyphs.\n");
return NULL;
}
Ptr<FontInfo> font_info = new FontInfo;
font_info->set_chars_to_glyph_ids(chars_to_glyph_ids);
font_info->set_resolved_glyph_ids(resolved_glyph_ids);
FontIdMap* font_id_map = new FontIdMap;
font_id_map->insert(std::make_pair(font_id_, font_));
font_info->set_fonts(font_id_map);
delete chars_to_glyph_ids;
delete resolved_glyph_ids;
delete font_id_map;
return font_info.Detach();
}
bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) {
if (!cmap_ || !chars_to_glyph_ids)
return false;
chars_to_glyph_ids->clear();
CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator();
if (!character_iterator)
return false;
while (character_iterator->HasNext()) {
int32_t character = character_iterator->Next();
if (!predicate_ || (*predicate_)(character)) {
chars_to_glyph_ids->insert
(std::make_pair(character,
GlyphId(cmap_->GlyphId(character), font_id_)));
}
}
delete character_iterator;
return true;
}
bool FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
GlyphIdSet* resolved_glyph_ids) {
if (!chars_to_glyph_ids || !resolved_glyph_ids)
return false;
resolved_glyph_ids->clear();
resolved_glyph_ids->insert(GlyphId(0, font_id_));
IntegerSet* unresolved_glyph_ids = new IntegerSet;
// Since composite glyph elements might themselves be composite, we would need
// to recursively resolve the elements too. To avoid the recursion we
// create two sets, |unresolved_glyph_ids| for the unresolved glyphs,
// initially containing all the ids and |resolved_glyph_ids|, initially empty.
// We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and,
// if the glyph is composite, add its elements to the unresolved set.
for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
e = chars_to_glyph_ids->end(); it != e; ++it) {
unresolved_glyph_ids->insert(it->second.glyph_id());
}
// As long as there are unresolved glyph ids.
while (!unresolved_glyph_ids->empty()) {
// Get the corresponding glyph.
if (!loca_table_) {
PyErr_SetString(UnsupportedFont, "This font does not have a loca table. Subsetting is not supported for fonts without loca tables (usually OTF fonts with PostScript (CFF) outlines).");
return false;
}
int32_t glyph_id = *(unresolved_glyph_ids->begin());
unresolved_glyph_ids->erase(unresolved_glyph_ids->begin());
if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) {
continue;
}
int32_t length = loca_table_->GlyphLength(glyph_id);
if (length == 0) {
continue;
}
int32_t offset = loca_table_->GlyphOffset(glyph_id);
GlyphPtr glyph;
if (!glyph_table_) {
PyErr_SetString(UnsupportedFont, "This font does not have a glyf table. Subsetting is not supported for fonts without glyf tables (usually OTF fonts with PostScript (CFF) outlines).");
return false;
}
glyph.Attach(glyph_table_->GetGlyph(offset, length));
if (glyph == NULL) {
continue;
}
// Mark the glyph as resolved.
resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_));
// If it is composite, add all its components to the unresolved glyph set.
if (glyph->GlyphType() == GlyphType::kComposite) {
Ptr<GlyphTable::CompositeGlyph> composite_glyph =
down_cast<GlyphTable::CompositeGlyph*>(glyph.p_);
int32_t num_glyphs = composite_glyph->NumGlyphs();
for (int32_t i = 0; i < num_glyphs; ++i) {
int32_t glyph_id = composite_glyph->GlyphIndex(i);
if (resolved_glyph_ids->find(GlyphId(glyph_id, -1))
== resolved_glyph_ids->end()) {
unresolved_glyph_ids->insert(glyph_id);
}
}
}
}
delete unresolved_glyph_ids;
return true;
}
void FontSourcedInfoBuilder::Initialize() {
Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font_->GetTable(Tag::cmap));
// We prefer Windows BMP format 4 cmaps.
cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP));
// But if none is found,
if (!cmap_) {
return;
}
loca_table_ = down_cast<LocaTable*>(font_->GetTable(Tag::loca));
glyph_table_ = down_cast<GlyphTable*>(font_->GetTable(Tag::glyf));
}
// }}}
// Font Assembler {{{
FontAssembler::FontAssembler(FontInfo* font_info, IntegerSet* table_blacklist) :
table_blacklist_(table_blacklist) {
font_info_ = font_info;
Initialize();
}
FontAssembler::FontAssembler(FontInfo* font_info) : table_blacklist_(NULL) {
font_info_ = font_info;
Initialize();
}
FontAssembler::~FontAssembler() { }
// Assemble a new font from the font info object.
CALLER_ATTACH Font* FontAssembler::Assemble() {
// Assemble tables we can subset.
if (!AssembleCMapTable() || !AssembleGlyphAndLocaTables()) {
return NULL;
}
// For all other tables, either include them unmodified or don't at all.
const TableMap* common_table_map =
font_info_->GetTableMap(font_info_->fonts()->begin()->first);
for (TableMap::const_iterator it = common_table_map->begin(),
e = common_table_map->end(); it != e; ++it) {
if (table_blacklist_
&& table_blacklist_->find(it->first) != table_blacklist_->end()) {
continue;
}
font_builder_->NewTableBuilder(it->first, it->second->ReadFontData());
}
return font_builder_->Build();
}
IntegerSet* FontAssembler::table_blacklist() const { return table_blacklist_; }
void FontAssembler::set_table_blacklist(IntegerSet* table_blacklist) {
table_blacklist_ = table_blacklist;
}
bool FontAssembler::AssembleCMapTable() {
// Creating the new CMapTable and the new format 4 CMap
Ptr<CMapTable::Builder> cmap_table_builder =
down_cast<CMapTable::Builder*>
(font_builder_->NewTableBuilder(Tag::cmap));
if (!cmap_table_builder)
return false;
Ptr<CMapTable::CMapFormat4::Builder> cmap_builder =
down_cast<CMapTable::CMapFormat4::Builder*>
(cmap_table_builder->NewCMapBuilder(CMapFormat::kFormat4,
CMapTable::WINDOWS_BMP));
if (!cmap_builder)
return false;
// Creating the segments and the glyph id array
CharacterMap* chars_to_glyph_ids = font_info_->chars_to_glyph_ids();
SegmentList* segment_list = new SegmentList;
IntegerList* glyph_id_array = new IntegerList;
int32_t last_chararacter = -2;
int32_t last_offset = 0;
Ptr<CMapTable::CMapFormat4::Builder::Segment> current_segment;
// For simplicity, we will have one segment per contiguous range.
// To test the algorithm, we've replaced the original CMap with the CMap
// generated by this code without removing any character.
// Tuffy.ttf: CMap went from 3146 to 3972 bytes (1.7% to 2.17% of file)
// AnonymousPro.ttf: CMap went from 1524 to 1900 bytes (0.96% to 1.2%)
for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
e = chars_to_glyph_ids->end(); it != e; ++it) {
int32_t character = it->first;
int32_t glyph_id = it->second.glyph_id();
if (character != last_chararacter + 1) { // new segment
if (current_segment != NULL) {
current_segment->set_end_count(last_chararacter);
segment_list->push_back(current_segment);
}
// start_code = character
// end_code = -1 (unknown for now)
// id_delta = 0 (we don't use id_delta for this representation)
// id_range_offset = last_offset (offset into the glyph_id_array)
current_segment =
new CMapTable::CMapFormat4::Builder::
Segment(character, -1, 0, last_offset);
}
glyph_id_array->push_back(glyph_id);
last_offset += DataSize::kSHORT;
last_chararacter = character;
}
// The last segment is still open.
if (glyph_id_array->size() < 1) {
PyErr_SetString(NoGlyphs, "No glyphs for the specified characters found");
return false;
}
current_segment->set_end_count(last_chararacter);
segment_list->push_back(current_segment);
// Updating the id_range_offset for every segment.
for (int32_t i = 0, num_segs = segment_list->size(); i < num_segs; ++i) {
Ptr<CMapTable::CMapFormat4::Builder::Segment> segment = segment_list->at(i);
segment->set_id_range_offset(segment->id_range_offset()
+ (num_segs - i + 1) * DataSize::kSHORT);
}
// Adding the final, required segment.
current_segment =
new CMapTable::CMapFormat4::Builder::Segment(0xffff, 0xffff, 1, 0);
segment_list->push_back(current_segment);
// Writing the segments and glyph id array to the CMap
cmap_builder->set_segments(segment_list);
cmap_builder->set_glyph_id_array(glyph_id_array);
delete segment_list;
delete glyph_id_array;
return true;
}
bool FontAssembler::AssembleGlyphAndLocaTables() {
Ptr<LocaTable::Builder> loca_table_builder =
down_cast<LocaTable::Builder*>
(font_builder_->NewTableBuilder(Tag::loca));
Ptr<GlyphTable::Builder> glyph_table_builder =
down_cast<GlyphTable::Builder*>
(font_builder_->NewTableBuilder(Tag::glyf));
GlyphIdSet* resolved_glyph_ids = font_info_->resolved_glyph_ids();
IntegerList loca_list;
// Basic sanity check: all LOCA tables are of the same size
// This is necessary but not sufficient!
int32_t previous_size = -1;
for (FontIdMap::iterator it = font_info_->fonts()->begin();
it != font_info_->fonts()->end(); ++it) {
Ptr<LocaTable> loca_table =
down_cast<LocaTable*>(font_info_->GetTable(it->first, Tag::loca));
int32_t current_size = loca_table->header_length();
if (previous_size != -1 && current_size != previous_size) {
return false;
}
previous_size = current_size;
}
// Assuming all fonts referenced by the FontInfo are the subsets of the same
// font, their loca tables should all have the same sizes.
// We'll just get the size of the first font's LOCA table for simplicty.
Ptr<LocaTable> first_loca_table =
down_cast<LocaTable*>
(font_info_->GetTable(font_info_->fonts()->begin()->first, Tag::loca));
int32_t num_loca_glyphs = first_loca_table->num_glyphs();
loca_list.resize(num_loca_glyphs);
loca_list.push_back(0);
int32_t last_glyph_id = 0;
int32_t last_offset = 0;
GlyphTable::GlyphBuilderList* glyph_builders =
glyph_table_builder->GlyphBuilders();
for (GlyphIdSet::iterator it = resolved_glyph_ids->begin(),
e = resolved_glyph_ids->end(); it != e; ++it) {
// Get the glyph for this resolved_glyph_id.
int32_t resolved_glyph_id = it->glyph_id();
int32_t font_id = it->font_id();
// Get the LOCA table for the current glyph id.
Ptr<LocaTable> loca_table =
down_cast<LocaTable*>
(font_info_->GetTable(font_id, Tag::loca));
int32_t length = loca_table->GlyphLength(resolved_glyph_id);
int32_t offset = loca_table->GlyphOffset(resolved_glyph_id);
// Get the GLYF table for the current glyph id.
Ptr<GlyphTable> glyph_table =
down_cast<GlyphTable*>
(font_info_->GetTable(font_id, Tag::glyf));
GlyphPtr glyph;
glyph.Attach(glyph_table->GetGlyph(offset, length));
// The data reference by the glyph is copied into a new glyph and
// added to the glyph_builders belonging to the glyph_table_builder.
// When Build gets called, all the glyphs will be built.
Ptr<ReadableFontData> data = glyph->ReadFontData();
Ptr<WritableFontData> copy_data;
copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length()));
data->CopyTo(copy_data);
GlyphBuilderPtr glyph_builder;
glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data));
glyph_builders->push_back(glyph_builder);
// If there are missing glyphs between the last glyph_id and the
// current resolved_glyph_id, since the LOCA table needs to have the same
// size, the offset is kept the same.
for (int32_t i = last_glyph_id + 1; i <= resolved_glyph_id; ++i)
loca_list[i] = last_offset;
last_offset += length;
loca_list[resolved_glyph_id + 1] = last_offset;
last_glyph_id = resolved_glyph_id + 1;
}
// If there are missing glyph ids, their loca entries must all point
// to the same offset as the last valid glyph id making them all zero length.
for (int32_t i = last_glyph_id + 1; i <= num_loca_glyphs; ++i)
loca_list[i] = last_offset;
loca_table_builder->SetLocaList(&loca_list);
return true;
}
void FontAssembler::Initialize() {
font_factory_.Attach(FontFactory::GetInstance());
font_builder_.Attach(font_factory_->NewFontBuilder());
}
// }}}
// Subsetters {{{
// Subsets a given font using a character predicate.
PredicateSubsetter::PredicateSubsetter(Font* font, CharacterPredicate* predicate) : font_(font), predicate_(predicate) {}
PredicateSubsetter::~PredicateSubsetter() { }
// Performs subsetting returning the subsetted font.
CALLER_ATTACH Font* PredicateSubsetter::Subset() {
Ptr<FontSourcedInfoBuilder> info_builder =
new FontSourcedInfoBuilder(font_, 0, predicate_);
Ptr<FontInfo> font_info;
font_info.Attach(info_builder->GetFontInfo());
if (!font_info) {
if (!PyErr_Occurred()) PyErr_SetString(Error, "Could not create font info");
return NULL;
}
IntegerSet* table_blacklist = new IntegerSet;
table_blacklist->insert(Tag::DSIG);
Ptr<FontAssembler> font_assembler = new FontAssembler(font_info,
table_blacklist);
Ptr<Font> font_subset;
font_subset.Attach(font_assembler->Assemble());
delete table_blacklist;
if (!font_subset) { if (!PyErr_Occurred()) PyErr_SetString(Error, "Could not subset font"); }
return font_subset.Detach();
}
// }}}
static void get_stats(Font *font, PyObject *dict) {
PyObject *t;
const TableMap* tables = font->GetTableMap();
for (TableMap::const_iterator it = tables->begin(),
e = tables->end(); it != e; ++it) {
t = PyInt_FromLong(it->second->DataLength());
if (t != NULL) {
PyDict_SetItemString(dict, TagToString(it->first), t);
Py_DECREF(t);
}
}
}
static PyObject*
do_subset(const char *data, Py_ssize_t sz, Ptr<CharacterPredicate> &predicate) {
FontPtr font;
Ptr<FontFactory> font_factory;
FontArray fonts;
MemoryInputStream stream;
PyObject *stats, *stats2;
if (!stream.Attach(reinterpret_cast<const byte_t*>(data), sz))
return PyErr_NoMemory();
font_factory.Attach(FontFactory::GetInstance());
font_factory->LoadFonts(&stream, &fonts);
if (fonts.empty() || fonts[0] == NULL) {
PyErr_SetString(Error, "Failed to load font from provided data.");
return NULL;
}
font = fonts[0];
if (font->num_tables() == 0) {
PyErr_SetString(Error, "Loaded font has 0 tables.");
return NULL;
}
Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
if (!cmap_table) {
PyErr_SetString(Error, "Loaded font has no cmap table.");
return NULL;
}
Ptr<PredicateSubsetter> subsetter = new PredicateSubsetter(font, predicate);
Ptr<Font> new_font;
new_font.Attach(subsetter->Subset());
if (!new_font) return NULL;
Ptr<FontFactory> ff;
ff.Attach(FontFactory::GetInstance());
MemoryOutputStream output_stream;
ff->SerializeFont(new_font, &output_stream);
stats = PyDict_New(); stats2 = PyDict_New();
if (stats == NULL || stats2 == NULL) return PyErr_NoMemory();
get_stats(font, stats);
get_stats(new_font, stats2);
return Py_BuildValue("s#NN", (char*)output_stream.Get(), output_stream.Size(), stats, stats2);
}
static PyObject*
subset(PyObject *self, PyObject *args) {
const char *data;
Py_ssize_t sz;
PyObject *individual_chars, *ranges, *t;
int32_t temp;
if (!PyArg_ParseTuple(args, "s#OO", &data, &sz, &individual_chars, &ranges)) return NULL;
if (!PyTuple_Check(individual_chars) || !PyTuple_Check(ranges)) {
PyErr_SetString(PyExc_TypeError, "individual_chars and ranges must be tuples");
return NULL;
}
if (PyTuple_Size(ranges) < 1 && PyTuple_Size(individual_chars) < 1) {
PyErr_SetString(NoGlyphs, "No characters specified");
return NULL;
}
IntegerSet chars;
for (Py_ssize_t i = 0; i < PyTuple_Size(individual_chars); i++) {
temp = (int32_t)PyInt_AsLong(PyTuple_GET_ITEM(individual_chars, i));
if (temp == -1 && PyErr_Occurred()) return NULL;
chars.insert(temp);
}
IntegerList cranges;
cranges.resize(2*PyTuple_Size(ranges));
for (Py_ssize_t i = 0; i < PyTuple_Size(ranges); i++) {
t = PyTuple_GET_ITEM(ranges, i);
if (!PyTuple_Check(t) || PyTuple_Size(t) != 2) {
PyErr_SetString(PyExc_TypeError, "ranges must contain only 2-tuples");
return NULL;
}
for (Py_ssize_t j = 0; j < 2; j++) {
cranges[2*i+j] = (int32_t)PyInt_AsLong(PyTuple_GET_ITEM(t, j));
if (cranges[2*i+j] == -1 && PyErr_Occurred()) return NULL;
}
}
Ptr<CharacterPredicate> predicate = new (std::nothrow) CompositePredicate(chars, cranges);
if (predicate == NULL) return PyErr_NoMemory();
try {
return do_subset(data, sz, predicate);
} catch (std::exception &e) {
PyErr_SetString(Error, e.what());
return NULL;
} catch (...) {
PyErr_SetString(Error, "An unknown exception occurred while subsetting");
return NULL;
}
}
static
PyMethodDef methods[] = {
{"subset", (PyCFunction)subset, METH_VARARGS,
"subset(bytestring, individual_chars, ranges) -> Subset the sfnt in bytestring, keeping only characters specified by individual_chars and ranges. Returns the subset font as a bytestring and the sizes of all font tables in the old and new fonts."
},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initsfntly(void) {
PyObject *m;
m = Py_InitModule3(
"sfntly", methods,
"Wrapper for the Google sfntly library"
);
if (m == NULL) return;
Error = PyErr_NewException((char*)"sfntly.Error", NULL, NULL);
if (Error == NULL) return;
PyModule_AddObject(m, "Error", Error);
NoGlyphs = PyErr_NewException((char*)"sfntly.NoGlyphs", NULL, NULL);
if (NoGlyphs == NULL) return;
PyModule_AddObject(m, "NoGlyphs", NoGlyphs);
UnsupportedFont = PyErr_NewException((char*)"sfntly.UnsupportedFont", NULL, NULL);
if (UnsupportedFont == NULL) return;
PyModule_AddObject(m, "UnsupportedFont", UnsupportedFont);
}

View File

@ -1,196 +0,0 @@
/*
* sfntly.h
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
#include <map>
#include <set>
#include <sfntly/tag.h>
#include <sfntly/font.h>
#include <sfntly/font_factory.h>
#include <sfntly/port/exception_type.h>
#include <sfntly/table/truetype/loca_table.h>
#include <sfntly/table/truetype/glyph_table.h>
#include <sfntly/tools/subsetter/subsetter.h>
using namespace sfntly;
typedef int32_t FontId;
typedef std::map<FontId, Ptr<Font> > FontIdMap;
class CharacterPredicate : virtual public RefCount {
public:
CharacterPredicate() {}
virtual ~CharacterPredicate() {}
virtual bool operator()(int32_t character) const = 0;
};
class CompositePredicate : public CharacterPredicate,
public RefCounted<CompositePredicate> {
public:
CompositePredicate(IntegerSet &chars, IntegerList &ranges);
~CompositePredicate();
virtual bool operator()(int32_t character) const;
private:
IntegerSet chars;
IntegerList ranges;
};
// Glyph id pair that contains the loca table glyph id as well as the
// font id that has the glyph table this glyph belongs to.
class GlyphId {
public:
GlyphId(int32_t glyph_id, FontId font_id);
~GlyphId();
bool operator==(const GlyphId& other) const;
bool operator<(const GlyphId& other) const;
int32_t glyph_id() const;
void set_glyph_id(const int32_t glyph_id);
FontId font_id() const;
void set_font_id(const FontId font_id);
private:
int32_t glyph_id_;
FontId font_id_;
};
typedef std::map<int32_t, GlyphId> CharacterMap;
typedef std::set<GlyphId> GlyphIdSet;
// Font information used for FontAssembler in the construction of a new font.
// Will make copies of character map, glyph id set and font id map.
class FontInfo : public RefCounted<FontInfo> {
public:
// Empty FontInfo object.
FontInfo();
// chars_to_glyph_ids maps characters to GlyphIds for CMap construction
// resolved_glyph_ids defines GlyphIds which should be in the final font
// fonts is a map of font ids to fonts to reference any needed table
FontInfo(CharacterMap* chars_to_glyph_ids,
GlyphIdSet* resolved_glyph_ids,
FontIdMap* fonts);
virtual ~FontInfo();
// Gets the table with the specified tag from the font corresponding to
// font_id or NULL if there is no such font/table.
// font_id is the id of the font that contains the table
// tag identifies the table to be obtained
virtual FontDataTable* GetTable(FontId font_id, int32_t tag);
// Gets the table map of the font whose id is font_id
virtual const TableMap* GetTableMap(FontId font_id);
CharacterMap* chars_to_glyph_ids() const;
// Takes ownership of the chars_to_glyph_ids CharacterMap.
void set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids);
GlyphIdSet* resolved_glyph_ids() const;
// Takes ownership of the glyph_ids GlyphIdSet.
void set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids);
FontIdMap* fonts() const;
// Takes ownership of the fonts FontIdMap.
void set_fonts(FontIdMap* fonts);
private:
CharacterMap* chars_to_glyph_ids_;
GlyphIdSet* resolved_glyph_ids_;
FontIdMap* fonts_;
};
// FontSourcedInfoBuilder is used to create a FontInfo object from a Font
// optionally specifying a CharacterPredicate to filter out some of
// the font's characters.
// It does not take ownership or copy the values its constructor receives.
class FontSourcedInfoBuilder :
public RefCounted<FontSourcedInfoBuilder> {
public:
FontSourcedInfoBuilder(Font* font, FontId font_id);
FontSourcedInfoBuilder(Font* font,
FontId font_id,
CharacterPredicate* predicate);
virtual ~FontSourcedInfoBuilder();
virtual CALLER_ATTACH FontInfo* GetFontInfo();
protected:
bool GetCharacterMap(CharacterMap* chars_to_glyph_ids);
bool ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
GlyphIdSet* resolved_glyph_ids);
void Initialize();
private:
Ptr<Font> font_;
FontId font_id_;
CharacterPredicate* predicate_;
Ptr<CMapTable::CMap> cmap_;
Ptr<LocaTable> loca_table_;
Ptr<GlyphTable> glyph_table_;
};
// Assembles FontInfo into font builders.
// Does not take ownership of data passed to it.
class FontAssembler : public RefCounted<FontAssembler> {
public:
// font_info is the FontInfo which will be used for the new font
// table_blacklist is used to decide which tables to exclude from the
// final font.
FontAssembler(FontInfo* font_info, IntegerSet* table_blacklist);
explicit FontAssembler(FontInfo* font_info);
~FontAssembler();
// Assemble a new font from the font info object.
virtual CALLER_ATTACH Font* Assemble();
IntegerSet* table_blacklist() const;
void set_table_blacklist(IntegerSet* table_blacklist);
protected:
virtual bool AssembleCMapTable();
virtual bool AssembleGlyphAndLocaTables();
virtual void Initialize();
private:
Ptr<FontInfo> font_info_;
Ptr<FontFactory> font_factory_;
Ptr<Font::Builder> font_builder_;
IntegerSet* table_blacklist_;
};
class PredicateSubsetter : public RefCounted<Subsetter> {
public:
PredicateSubsetter(Font* font, CharacterPredicate* predicate);
virtual ~PredicateSubsetter();
// Performs subsetting returning the subsetted font.
virtual CALLER_ATTACH Font* Subset();
private:
Ptr<Font> font_;
Ptr<CharacterPredicate> predicate_;
};

View File

@ -212,7 +212,11 @@ class SearchQueryParser(object):
# another search.
def _parse(self, query, candidates=None):
self.recurse_level += 1
try:
res = self._parser.parseString(query)[0]
except RuntimeError:
import repr
raise ParseException('Failed to parse query, recursion limit reached: %s'%repr(query))
if candidates is None:
candidates = self.universal_set()
t = self.evaluate(res, candidates)

View File

@ -1,203 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2011 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,199 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/byte_array.h"
#include <algorithm>
#include "sfntly/port/exception_type.h"
namespace sfntly {
const int32_t ByteArray::COPY_BUFFER_SIZE = 8192;
ByteArray::~ByteArray() {}
int32_t ByteArray::Length() { return filled_length_; }
int32_t ByteArray::Size() { return storage_length_; }
int32_t ByteArray::SetFilledLength(int32_t filled_length) {
filled_length_ = std::min<int32_t>(filled_length, storage_length_);
return filled_length_;
}
int32_t ByteArray::Get(int32_t index) {
return InternalGet(index) & 0xff;
}
int32_t ByteArray::Get(int32_t index, ByteVector* b) {
assert(b);
return Get(index, &((*b)[0]), 0, b->size());
}
int32_t ByteArray::Get(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
assert(b);
if (index < 0 || index >= filled_length_) {
return 0;
}
int32_t actual_length = std::min<int32_t>(length, filled_length_ - index);
return InternalGet(index, b, offset, actual_length);
}
void ByteArray::Put(int32_t index, byte_t b) {
if (index < 0 || index >= Size()) {
#if defined (SFNTLY_NO_EXCEPTION)
return;
#else
throw IndexOutOfBoundException(
"Attempt to write outside the bounds of the data");
#endif
}
InternalPut(index, b);
filled_length_ = std::max<int32_t>(filled_length_, index + 1);
}
int32_t ByteArray::Put(int index, ByteVector* b) {
assert(b);
return Put(index, &((*b)[0]), 0, b->size());
}
int32_t ByteArray::Put(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
assert(b);
if (index < 0 || index >= Size()) {
#if defined (SFNTLY_NO_EXCEPTION)
return 0;
#else
throw IndexOutOfBoundException(
"Attempt to write outside the bounds of the data");
#endif
}
int32_t actual_length = std::min<int32_t>(length, Size() - index);
int32_t bytes_written = InternalPut(index, b, offset, actual_length);
filled_length_ = std::max<int32_t>(filled_length_, index + bytes_written);
return bytes_written;
}
int32_t ByteArray::CopyTo(ByteArray* array) {
return CopyTo(array, 0, Length());
}
int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) {
return CopyTo(0, array, offset, length);
}
int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array,
int32_t src_offset, int32_t length) {
assert(array);
if (array->Size() < dst_offset + length) { // insufficient space
return -1;
}
ByteVector b(COPY_BUFFER_SIZE);
int32_t bytes_read = 0;
int32_t index = 0;
int32_t remaining_length = length;
int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
while ((bytes_read =
Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) {
int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read);
UNREFERENCED_PARAMETER(bytes_written);
index += bytes_read;
remaining_length -= bytes_read;
buffer_length = std::min<int32_t>(b.size(), remaining_length);
}
return index;
}
int32_t ByteArray::CopyTo(OutputStream* os) {
return CopyTo(os, 0, Length());
}
int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) {
ByteVector b(COPY_BUFFER_SIZE);
int32_t bytes_read = 0;
int32_t index = 0;
int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) {
os->Write(&b, 0, bytes_read);
index += bytes_read;
buffer_length = std::min<int32_t>(b.size(), length - index);
}
return index;
}
bool ByteArray::CopyFrom(InputStream* is, int32_t length) {
ByteVector b(COPY_BUFFER_SIZE);
int32_t bytes_read = 0;
int32_t index = 0;
int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) {
#if defined (SFNTLY_NO_EXCEPTION)
return 0;
#else
throw IOException("Error writing bytes.");
#endif
}
index += bytes_read;
length -= bytes_read;
buffer_length = std::min<int32_t>(b.size(), length);
}
return true;
}
bool ByteArray::CopyFrom(InputStream* is) {
ByteVector b(COPY_BUFFER_SIZE);
int32_t bytes_read = 0;
int32_t index = 0;
int32_t buffer_length = COPY_BUFFER_SIZE;
while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
if (Put(index, &b[0], 0, bytes_read) != bytes_read) {
#if defined (SFNTLY_NO_EXCEPTION)
return 0;
#else
throw IOException("Error writing bytes.");
#endif
}
index += bytes_read;
}
return true;
}
ByteArray::ByteArray(int32_t filled_length,
int32_t storage_length,
bool growable) {
Init(filled_length, storage_length, growable);
}
ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) {
Init(filled_length, storage_length, false);
}
void ByteArray::Init(int32_t filled_length,
int32_t storage_length,
bool growable) {
storage_length_ = storage_length;
growable_ = growable;
SetFilledLength(filled_length);
}
} // namespace sfntly

View File

@ -1,201 +0,0 @@
/*
* Copyright (C) 2011 The sfntly Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
#include "sfntly/port/refcount.h"
#include "sfntly/port/type.h"
#include "sfntly/port/input_stream.h"
#include "sfntly/port/output_stream.h"
namespace sfntly {
// An abstraction to a contiguous array of bytes.
// C++ port of this class assumes that the data are stored in a linear region
// like std::vector.
class ByteArray : virtual public RefCount {
public:
virtual ~ByteArray();
// Gets the current filled and readable length of the array.
int32_t Length();
// Gets the maximum size of the array. This is the maximum number of bytes that
// the array can hold and all of it may not be filled with data or even fully
// allocated yet.
int32_t Size();
// Determines whether or not this array is growable or of fixed size.
bool growable() { return growable_; }
int32_t SetFilledLength(int32_t filled_length);
// Gets the byte from the given index.
// @param index the index into the byte array
// @return the byte or -1 if reading beyond the bounds of the data
virtual int32_t Get(int32_t index);
// Gets the bytes from the given index and fill the buffer with them. As many
// bytes as will fit into the buffer are read unless that would go past the
// end of the array.
// @param index the index into the byte array
// @param b the buffer to put the bytes read into
// @return the number of bytes read from the buffer
virtual int32_t Get(int32_t index, ByteVector* b);
// Gets the bytes from the given index and fill the buffer with them starting
// at the offset given. As many bytes as the specified length are read unless
// that would go past the end of the array.
// @param index the index into the byte array
// @param b the buffer to put the bytes read into
// @param offset the location in the buffer to start putting the bytes
// @param length the number of bytes to put into the buffer
// @return the number of bytes read from the buffer
virtual int32_t Get(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
// Puts the specified byte into the array at the given index unless that would
// be beyond the length of the array and it isn't growable.
virtual void Put(int32_t index, byte_t b);
// Puts the specified bytes into the array at the given index. The entire
// buffer is put into the array unless that would extend beyond the length and
// the array isn't growable.
virtual int32_t Put(int32_t index, ByteVector* b);
// Puts the specified bytes into the array at the given index. All of the bytes
// specified are put into the array unless that would extend beyond the length
// and the array isn't growable. The bytes to be put into the array are those
// in the buffer from the given offset and for the given length.
// @param index the index into the ByteArray
// @param b the bytes to put into the array
// @param offset the offset in the bytes to start copying from
// @param length the number of bytes to copy into the array
// @return the number of bytes actually written
virtual int32_t Put(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
// Fully copies this ByteArray to another ByteArray to the extent that the
// destination array has storage for the data copied.
virtual int32_t CopyTo(ByteArray* array);
// Copies a segment of this ByteArray to another ByteArray.
// @param array the destination
// @param offset the offset in this ByteArray to start copying from
// @param length the maximum length in bytes to copy
// @return the number of bytes copied
virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length);
// Copies this ByteArray to another ByteArray.
// @param dstOffset the offset in the destination array to start copying to
// @param array the destination
// @param srcOffset the offset in this ByteArray to start copying from
// @param length the maximum length in bytes to copy
// @return the number of bytes copied
virtual int32_t CopyTo(int32_t dst_offset,
ByteArray* array,
int32_t src_offset,
int32_t length);
// Copies this ByteArray to an OutputStream.
// @param os the destination
// @return the number of bytes copied
virtual int32_t CopyTo(OutputStream* os);
// Copies this ByteArray to an OutputStream.
// @param os the destination
// @param offset
// @param length
// @return the number of bytes copied
virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
// Copies from the InputStream into this ByteArray.
// @param is the source
// @param length the number of bytes to copy
virtual bool CopyFrom(InputStream* is, int32_t length);
// Copies everything from the InputStream into this ByteArray.
// @param is the source
virtual bool CopyFrom(InputStream* is);
protected:
// filledLength the length that is "filled" and readable counting from offset.
// storageLength the maximum storage size of the underlying data.
// growable is the storage growable - storageLength is the max growable size.
ByteArray(int32_t filled_length, int32_t storage_length, bool growable);
ByteArray(int32_t filled_length, int32_t storage_length);
void Init(int32_t filled_length, int32_t storage_length, bool growable);
// Internal subclass API
// Stores the byte at the index given.
// @param index the location to store at
// @param b the byte to store
virtual void InternalPut(int32_t index, byte_t b) = 0;
// Stores the array of bytes at the given index.
// @param index the location to store at
// @param b the bytes to store
// @param offset the offset to start from in the byte array
// @param length the length of the byte array to store from the offset
// @return the number of bytes actually stored
virtual int32_t InternalPut(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) = 0;
// Gets the byte at the index given.
// @param index the location to get from
// @return the byte stored at the index
virtual byte_t InternalGet(int32_t index) = 0;
// Gets the bytes at the index given of the given length.
// @param index the location to start getting from
// @param b the array to put the bytes into
// @param offset the offset in the array to put the bytes into
// @param length the length of bytes to read
// @return the number of bytes actually ready
virtual int32_t InternalGet(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) = 0;
// Close this instance of the ByteArray.
virtual void Close() = 0;
// C++ port only, raw pointer to the first element of storage.
virtual byte_t* Begin() = 0;
// Java toString() not ported.
static const int32_t COPY_BUFFER_SIZE;
private:
//bool bound_; // unused, comment out
int32_t filled_length_;
int32_t storage_length_;
bool growable_;
};
typedef Ptr<ByteArray> ByteArrayPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_

View File

@ -1,82 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <limits.h>
#include <algorithm>
#include <functional>
#include "sfntly/data/font_data.h"
namespace sfntly {
int32_t FontData::Size() const {
return std::min<int32_t>(array_->Size() - bound_offset_, bound_length_);
}
bool FontData::Bound(int32_t offset, int32_t length) {
if (offset + length > Size() || offset < 0 || length < 0)
return false;
bound_offset_ += offset;
bound_length_ = length;
return true;
}
bool FontData::Bound(int32_t offset) {
if (offset > Size() || offset < 0)
return false;
bound_offset_ += offset;
return true;
}
int32_t FontData::Length() const {
return std::min<int32_t>(array_->Length() - bound_offset_, bound_length_);
}
FontData::FontData(ByteArray* ba) {
Init(ba);
}
FontData::FontData(FontData* data, int32_t offset, int32_t length) {
Init(data->array_);
Bound(data->bound_offset_ + offset, length);
}
FontData::FontData(FontData* data, int32_t offset) {
Init(data->array_);
Bound(data->bound_offset_ + offset,
(data->bound_length_ == GROWABLE_SIZE)
? GROWABLE_SIZE : data->bound_length_ - offset);
}
FontData::~FontData() {}
void FontData::Init(ByteArray* ba) {
array_ = ba;
bound_offset_ = 0;
bound_length_ = GROWABLE_SIZE;
}
int32_t FontData::BoundOffset(int32_t offset) {
return offset + bound_offset_;
}
int32_t FontData::BoundLength(int32_t offset, int32_t length) {
return std::min<int32_t>(length, bound_length_ - offset);
}
} // namespace sfntly

View File

@ -1,135 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
#include <limits.h>
#include <vector>
#include "sfntly/port/type.h"
#include "sfntly/data/byte_array.h"
#include "sfntly/port/refcount.h"
namespace sfntly {
struct DataSize {
enum {
kBYTE = 1,
kCHAR = 1,
kUSHORT = 2,
kSHORT = 2,
kUINT24 = 3,
kULONG = 4,
kLONG = 4,
kFixed = 4,
kFUNIT = 4,
kFWORD = 2,
kUFWORD = 2,
kF2DOT14 = 2,
kLONGDATETIME = 8,
kTag = 4,
kGlyphID = 2,
kOffset = 2
};
};
class FontData : virtual public RefCount {
public:
// Gets the maximum size of the FontData. This is the maximum number of bytes
// that the font data can hold and all of it may not be filled with data or
// even fully allocated yet.
// @return the maximum size of this font data
virtual int32_t Size() const;
// Sets limits on the size of the FontData. The FontData is then only
// visible within the bounds set.
// @param offset the start of the new bounds
// @param length the number of bytes in the bounded array
// @return true if the bounding range was successful; false otherwise
virtual bool Bound(int32_t offset, int32_t length);
// Sets limits on the size of the FontData. This is a offset bound only so if
// the FontData is writable and growable then there is no limit to that growth
// from the bounding operation.
// @param offset the start of the new bounds which must be within the current
// size of the FontData
// @return true if the bounding range was successful; false otherwise
virtual bool Bound(int32_t offset);
// Makes a slice of this FontData. The returned slice will share the data with
// the original <code>FontData</code>.
// @param offset the start of the slice
// @param length the number of bytes in the slice
// @return a slice of the original FontData
virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length) = 0;
// Makes a bottom bound only slice of this array. The returned slice will
// share the data with the original <code>FontData</code>.
// @param offset the start of the slice
// @return a slice of the original FontData
virtual CALLER_ATTACH FontData* Slice(int32_t offset) = 0;
// Gets the length of the data.
virtual int32_t Length() const;
protected:
// Constructor.
// @param ba the byte array to use for the backing data
explicit FontData(ByteArray* ba);
// Constructor.
// @param data the data to wrap
// @param offset the offset to start the wrap from
// @param length the length of the data wrapped
FontData(FontData* data, int32_t offset, int32_t length);
// Constructor.
// @param data the data to wrap
// @param offset the offset to start the wrap from
FontData(FontData* data, int32_t offset);
virtual ~FontData();
void Init(ByteArray* ba);
// Gets the offset in the underlying data taking into account any bounds on
// the data.
// @param offset the offset to get the bound compensated offset for
// @return the bound compensated offset
int32_t BoundOffset(int32_t offset);
// Gets the length in the underlying data taking into account any bounds on
// the data.
// @param offset the offset that the length is being used at
// @param length the length to get the bound compensated length for
// @return the bound compensated length
int32_t BoundLength(int32_t offset, int32_t length);
static const int32_t GROWABLE_SIZE = INT_MAX;
// TODO(arthurhsu): style guide violation: refactor this protected member
ByteArrayPtr array_;
private:
int32_t bound_offset_;
int32_t bound_length_;
};
typedef Ptr<FontData> FontDataPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_

View File

@ -1,141 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/font_input_stream.h"
#include <algorithm>
namespace sfntly {
FontInputStream::FontInputStream(InputStream* is)
: stream_(is), position_(0), length_(0), bounded_(false) {
}
FontInputStream::FontInputStream(InputStream* is, size_t length)
: stream_(is), position_(0), length_(length), bounded_(true) {
}
FontInputStream::~FontInputStream() {
// Do not close here, underlying InputStream will close themselves.
}
int32_t FontInputStream::Available() {
if (stream_) {
return stream_->Available();
}
return 0;
}
void FontInputStream::Close() {
if (stream_) {
stream_->Close();
}
}
void FontInputStream::Mark(int32_t readlimit) {
if (stream_) {
stream_->Mark(readlimit);
}
}
bool FontInputStream::MarkSupported() {
if (stream_) {
return stream_->MarkSupported();
}
return false;
}
void FontInputStream::Reset() {
if (stream_) {
stream_->Reset();
}
}
int32_t FontInputStream::Read() {
if (!stream_ || (bounded_ && position_ >= length_)) {
return -1;
}
int32_t b = stream_->Read();
if (b >= 0) {
position_++;
}
return b;
}
int32_t FontInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
if (!stream_ || offset < 0 || length < 0 ||
(bounded_ && position_ >= length_)) {
return -1;
}
int32_t bytes_to_read =
bounded_ ? std::min<int32_t>(length, (int32_t)(length_ - position_)) :
length;
int32_t bytes_read = stream_->Read(b, offset, bytes_to_read);
position_ += bytes_read;
return bytes_read;
}
int32_t FontInputStream::Read(ByteVector* b) {
return Read(b, 0, b->size());
}
int32_t FontInputStream::ReadChar() {
return Read();
}
int32_t FontInputStream::ReadUShort() {
return 0xffff & (Read() << 8 | Read());
}
int32_t FontInputStream::ReadShort() {
return ((Read() << 8 | Read()) << 16) >> 16;
}
int32_t FontInputStream::ReadUInt24() {
return 0xffffff & (Read() << 16 | Read() << 8 | Read());
}
int64_t FontInputStream::ReadULong() {
return 0xffffffffL & ReadLong();
}
int32_t FontInputStream::ReadULongAsInt() {
int64_t ulong = ReadULong();
return ((int32_t)ulong) & ~0x80000000;
}
int32_t FontInputStream::ReadLong() {
return Read() << 24 | Read() << 16 | Read() << 8 | Read();
}
int32_t FontInputStream::ReadFixed() {
return ReadLong();
}
int64_t FontInputStream::ReadDateTimeAsLong() {
return (int64_t)ReadULong() << 32 | ReadULong();
}
int64_t FontInputStream::Skip(int64_t n) {
if (stream_) {
int64_t skipped = stream_->Skip(n);
position_ += skipped;
return skipped;
}
return 0;
}
} // namespace sfntly

View File

@ -1,97 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
#include "sfntly/port/type.h"
#include "sfntly/port/input_stream.h"
namespace sfntly {
// An input stream for reading font data.
// The data types used are as listed:
// BYTE 8-bit unsigned integer.
// CHAR 8-bit signed integer.
// USHORT 16-bit unsigned integer.
// SHORT 16-bit signed integer.
// UINT24 24-bit unsigned integer.
// ULONG 32-bit unsigned integer.
// LONG 32-bit signed integer.
// Fixed 32-bit signed fixed-point number (16.16)
// FUNIT Smallest measurable distance in the em space.
// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits.
// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in
// FUnits.
// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14)
// LONGDATETIME Date represented in number of seconds since 12:00 midnight,
// January 1, 1904. The value is represented as a signed 64-bit
// integer.
// Note: Original class inherits from Java's FilterOutputStream, which wraps
// an InputStream within. In C++, we directly do the wrapping without
// defining another layer of abstraction. The wrapped output stream is
// *NOT* reference counted (because it's meaningless to ref-count an I/O
// stream).
class FontInputStream : public InputStream {
public:
// Constructor.
// @param is input stream to wrap
explicit FontInputStream(InputStream* is);
// Constructor for a bounded font input stream.
// @param is input stream to wrap
// @param length the maximum length of bytes to read
FontInputStream(InputStream* is, size_t length);
virtual ~FontInputStream();
virtual int32_t Available();
virtual void Close();
virtual void Mark(int32_t readlimit);
virtual bool MarkSupported();
virtual void Reset();
virtual int32_t Read();
virtual int32_t Read(ByteVector* buffer);
virtual int32_t Read(ByteVector* buffer, int32_t offset, int32_t length);
// Get the current position in the stream in bytes.
// @return the current position in bytes
virtual int64_t position() { return position_; }
virtual int32_t ReadChar();
virtual int32_t ReadUShort();
virtual int32_t ReadShort();
virtual int32_t ReadUInt24();
virtual int64_t ReadULong();
virtual int32_t ReadULongAsInt();
virtual int32_t ReadLong();
virtual int32_t ReadFixed();
virtual int64_t ReadDateTimeAsLong();
virtual int64_t Skip(int64_t n); // n can be negative.
private:
InputStream* stream_;
int64_t position_;
int64_t length_; // Bound on length of data to read.
bool bounded_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_

View File

@ -1,130 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/font_output_stream.h"
#include <algorithm>
namespace sfntly {
FontOutputStream::FontOutputStream(OutputStream* os)
: stream_(os),
position_(0) {
}
FontOutputStream::~FontOutputStream() {
// Do not close, underlying stream shall clean up themselves.
}
void FontOutputStream::Write(byte_t b) {
if (stream_) {
stream_->Write(b);
position_++;
}
}
void FontOutputStream::Write(ByteVector* b) {
if (b) {
Write(b, 0, b->size());
position_ += b->size();
}
}
void FontOutputStream::Write(ByteVector* b, int32_t off, int32_t len) {
assert(b);
assert(stream_);
if (off < 0 || len < 0 || off + len < 0 ||
static_cast<size_t>(off + len) > b->size()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundException();
#else
return;
#endif
}
stream_->Write(b, off, len);
position_ += len;
}
void FontOutputStream::Write(byte_t* b, int32_t off, int32_t len) {
assert(b);
assert(stream_);
if (off < 0 || len < 0 || off + len < 0) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundException();
#else
return;
#endif
}
stream_->Write(b, off, len);
position_ += len;
}
void FontOutputStream::WriteChar(byte_t c) {
Write(c);
}
void FontOutputStream::WriteUShort(int32_t us) {
Write((byte_t)((us >> 8) & 0xff));
Write((byte_t)(us & 0xff));
}
void FontOutputStream::WriteShort(int32_t s) {
WriteUShort(s);
}
void FontOutputStream::WriteUInt24(int32_t ui) {
Write((byte_t)(ui >> 16) & 0xff);
Write((byte_t)(ui >> 8) & 0xff);
Write((byte_t)ui & 0xff);
}
void FontOutputStream::WriteULong(int64_t ul) {
Write((byte_t)((ul >> 24) & 0xff));
Write((byte_t)((ul >> 16) & 0xff));
Write((byte_t)((ul >> 8) & 0xff));
Write((byte_t)(ul & 0xff));
}
void FontOutputStream::WriteLong(int64_t l) {
WriteULong(l);
}
void FontOutputStream::WriteFixed(int32_t f) {
WriteULong(f);
}
void FontOutputStream::WriteDateTime(int64_t date) {
WriteULong((date >> 32) & 0xffffffff);
WriteULong(date & 0xffffffff);
}
void FontOutputStream::Flush() {
if (stream_) {
stream_->Flush();
}
}
void FontOutputStream::Close() {
if (stream_) {
stream_->Flush();
stream_->Close();
position_ = 0;
}
}
} // namespace sfntly

View File

@ -1,79 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
#include "sfntly/port/type.h"
#include "sfntly/port/output_stream.h"
namespace sfntly {
// An output stream for writing font data.
// The data types used are as listed:
// BYTE 8-bit unsigned integer.
// CHAR 8-bit signed integer.
// USHORT 16-bit unsigned integer.
// SHORT 16-bit signed integer.
// UINT24 24-bit unsigned integer.
// ULONG 32-bit unsigned integer.
// LONG 32-bit signed integer.
// Fixed 32-bit signed fixed-point number (16.16)
// FUNIT Smallest measurable distance in the em space.
// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits.
// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in
// FUnits.
// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14)
// LONGDATETIME Date represented in number of seconds since 12:00 midnight,
// January 1, 1904. The value is represented as a signed 64-bit
// integer.
// Note: The wrapped output stream is *NOT* reference counted (because it's
// meaningless to ref-count an I/O stream).
class FontOutputStream : public OutputStream {
public:
explicit FontOutputStream(OutputStream* os);
virtual ~FontOutputStream();
virtual size_t position() { return position_; }
virtual void Write(byte_t b);
virtual void Write(ByteVector* b);
virtual void Write(ByteVector* b, int32_t off, int32_t len);
virtual void Write(byte_t* b, int32_t off, int32_t len);
virtual void WriteChar(byte_t c);
virtual void WriteUShort(int32_t us);
virtual void WriteShort(int32_t s);
virtual void WriteUInt24(int32_t ui);
virtual void WriteULong(int64_t ul);
virtual void WriteLong(int64_t l);
virtual void WriteFixed(int32_t l);
virtual void WriteDateTime(int64_t date);
// Note: C++ port only.
virtual void Flush();
virtual void Close();
private:
// Note: we do not use the variable name out as in Java because it has
// special meaning in VC++ and will be very confusing.
OutputStream* stream_;
size_t position_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_

View File

@ -1,82 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/growable_memory_byte_array.h"
#include <limits.h>
#include <string.h>
#include <algorithm>
namespace sfntly {
GrowableMemoryByteArray::GrowableMemoryByteArray()
: ByteArray(0, INT_MAX, true) {
// Note: We did not set an initial size of array like Java because STL
// implementation will determine the best strategy.
}
GrowableMemoryByteArray::~GrowableMemoryByteArray() {}
int32_t GrowableMemoryByteArray::CopyTo(OutputStream* os,
int32_t offset,
int32_t length) {
assert(os);
os->Write(&b_, offset, length);
return length;
}
void GrowableMemoryByteArray::InternalPut(int32_t index, byte_t b) {
if ((size_t)index >= b_.size()) {
b_.resize((size_t)(index + 1));
}
b_[index] = b;
}
int32_t GrowableMemoryByteArray::InternalPut(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
if ((size_t)index + length >= b_.size()) {
// Note: We grow one byte more than Java version. VC debuggers shows
// data better this way.
b_.resize((size_t)(index + length + 1));
}
std::copy(b + offset, b + offset + length, b_.begin() + index);
return length;
}
byte_t GrowableMemoryByteArray::InternalGet(int32_t index) {
return b_[index];
}
int32_t GrowableMemoryByteArray::InternalGet(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
memcpy(b + offset, &(b_[0]) + index, length);
return length;
}
void GrowableMemoryByteArray::Close() {
b_.clear();
}
byte_t* GrowableMemoryByteArray::Begin() {
return &(b_[0]);
}
} // namespace sfntly

View File

@ -1,66 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
#include "sfntly/data/byte_array.h"
namespace sfntly {
// Note: This is not really a port of Java version. Instead, this wraps a
// std::vector inside and let it grow by calling resize().
class GrowableMemoryByteArray : public ByteArray,
public RefCounted<GrowableMemoryByteArray> {
public:
GrowableMemoryByteArray();
virtual ~GrowableMemoryByteArray();
virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
// Make gcc -Woverloaded-virtual happy.
virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); }
virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) {
return ByteArray::CopyTo(array, offset, length);
}
virtual int32_t CopyTo(int32_t dst_offset,
ByteArray* array,
int32_t src_offset,
int32_t length) {
return ByteArray::CopyTo(dst_offset, array, src_offset, length);
}
virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); }
protected:
virtual void InternalPut(int32_t index, byte_t b);
virtual int32_t InternalPut(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
virtual byte_t InternalGet(int32_t index);
virtual int32_t InternalGet(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
virtual void Close();
virtual byte_t* Begin();
private:
ByteVector b_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_

View File

@ -1,93 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/memory_byte_array.h"
#include <string.h>
namespace sfntly {
MemoryByteArray::MemoryByteArray(int32_t length)
: ByteArray(0, length), b_(NULL), allocated_(true) {
}
MemoryByteArray::MemoryByteArray(byte_t* b, int32_t filled_length)
: ByteArray(filled_length, filled_length), b_(b), allocated_(false) {
assert(b);
}
MemoryByteArray::~MemoryByteArray() {
Close();
}
int32_t MemoryByteArray::CopyTo(OutputStream* os,
int32_t offset,
int32_t length) {
assert(os);
os->Write(b_, offset, length);
return length;
}
void MemoryByteArray::Init() {
if (allocated_ && b_ == NULL) {
b_ = new byte_t[Size()];
memset(b_, 0, Size());
}
}
void MemoryByteArray::InternalPut(int32_t index, byte_t b) {
Init();
b_[index] = b;
}
int32_t MemoryByteArray::InternalPut(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
assert(b);
Init();
memcpy(b_ + index, b + offset, length);
return length;
}
byte_t MemoryByteArray::InternalGet(int32_t index) {
Init();
return b_[index];
}
int32_t MemoryByteArray::InternalGet(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
assert(b);
Init();
memcpy(b + offset, b_ + index, length);
return length;
}
void MemoryByteArray::Close() {
if (allocated_ && b_) {
delete[] b_;
}
b_ = NULL;
}
byte_t* MemoryByteArray::Begin() {
Init();
return b_;
}
} // namespace sfntly

View File

@ -1,81 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
#include "sfntly/data/byte_array.h"
namespace sfntly {
class MemoryByteArray : public ByteArray, public RefCounted<MemoryByteArray> {
public:
// Construct a new MemoryByteArray with a new array of the size given. It is
// assumed that none of the array is filled and readable.
explicit MemoryByteArray(int32_t length);
// Note: not implemented due to dangerous operations in constructor.
//explicit MemoryByteArray(ByteVector* b);
// Construct a new MemoryByteArray using byte array.
// @param b the byte array that provides the actual storage
// @param filled_length the index of the last byte in the array has data
// Note: This is different from Java version, it does not take over the
// ownership of b. Caller is responsible for handling the lifetime
// of b. C++ port also assumes filled_length is buffer_length since
// there is not a reliable way to identify the actual size of buffer.
MemoryByteArray(byte_t* b, int32_t filled_length);
virtual ~MemoryByteArray();
virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
// Make gcc -Woverloaded-virtual happy.
virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); }
virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) {
return ByteArray::CopyTo(array, offset, length);
}
virtual int32_t CopyTo(int32_t dst_offset,
ByteArray* array,
int32_t src_offset,
int32_t length) {
return ByteArray::CopyTo(dst_offset, array, src_offset, length);
}
virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); }
protected:
virtual void InternalPut(int32_t index, byte_t b);
virtual int32_t InternalPut(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
virtual byte_t InternalGet(int32_t index);
virtual int32_t InternalGet(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
virtual void Close();
virtual byte_t* Begin();
private:
void Init(); // C++ port only, used to allocate memory outside constructor.
byte_t* b_;
bool allocated_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_

View File

@ -1,336 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/readable_font_data.h"
#include <stdio.h>
#include "sfntly/data/memory_byte_array.h"
#include "sfntly/data/writable_font_data.h"
#include "sfntly/port/exception_type.h"
namespace sfntly {
ReadableFontData::ReadableFontData(ByteArray* array)
: FontData(array),
checksum_set_(false),
checksum_(0) {
}
ReadableFontData::~ReadableFontData() {}
// TODO(arthurhsu): re-investigate the memory model of this function. It's
// not too useful without copying, but it's not performance
// savvy to do copying.
CALLER_ATTACH
ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
assert(b);
ByteArrayPtr ba = new MemoryByteArray(b->size());
ba->Put(0, b);
ReadableFontDataPtr wfd = new ReadableFontData(ba);
return wfd.Detach();
}
int64_t ReadableFontData::Checksum() {
AutoLock lock(checksum_lock_);
if (!checksum_set_) {
ComputeChecksum();
}
return checksum_;
}
void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
checksum_range_ = ranges;
checksum_set_ = false; // UNIMPLEMENTED: atomicity
}
int32_t ReadableFontData::ReadUByte(int32_t index) {
int32_t b = array_->Get(BoundOffset(index));
#if !defined (SFNTLY_NO_EXCEPTION)
if (b < 0) {
throw IndexOutOfBoundException(
"Index attempted to be read from is out of bounds", index);
}
#endif
return b;
}
int32_t ReadableFontData::ReadByte(int32_t index) {
int32_t b = array_->Get(BoundOffset(index));
#if !defined (SFNTLY_NO_EXCEPTION)
if (b < 0) {
throw IndexOutOfBoundException(
"Index attempted to be read from is out of bounds", index);
}
#endif
return (b << 24) >> 24;
}
int32_t ReadableFontData::ReadBytes(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
}
int32_t ReadableFontData::ReadChar(int32_t index) {
return ReadUByte(index);
}
int32_t ReadableFontData::ReadUShort(int32_t index) {
return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
}
int32_t ReadableFontData::ReadShort(int32_t index) {
return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
}
int32_t ReadableFontData::ReadUInt24(int32_t index) {
return 0xffffff & (ReadUByte(index) << 16 |
ReadUByte(index + 1) << 8 |
ReadUByte(index + 2));
}
int64_t ReadableFontData::ReadULong(int32_t index) {
return 0xffffffffL & (ReadUByte(index) << 24 |
ReadUByte(index + 1) << 16 |
ReadUByte(index + 2) << 8 |
ReadUByte(index + 3));
}
int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
int64_t ulong = ReadULong(index);
#if !defined (SFNTLY_NO_EXCEPTION)
if ((ulong & 0x80000000) == 0x80000000) {
throw ArithmeticException("Long value too large to fit into an integer.");
}
#endif
return static_cast<int32_t>(ulong);
}
int64_t ReadableFontData::ReadULongLE(int32_t index) {
return 0xffffffffL & (ReadUByte(index) |
ReadUByte(index + 1) << 8 |
ReadUByte(index + 2) << 16 |
ReadUByte(index + 3) << 24);
}
int32_t ReadableFontData::ReadLong(int32_t index) {
return ReadByte(index) << 24 |
ReadUByte(index + 1) << 16 |
ReadUByte(index + 2) << 8 |
ReadUByte(index + 3);
}
int32_t ReadableFontData::ReadFixed(int32_t index) {
return ReadLong(index);
}
int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
}
int32_t ReadableFontData::ReadFWord(int32_t index) {
return ReadShort(index);
}
int32_t ReadableFontData::ReadFUFWord(int32_t index) {
return ReadUShort(index);
}
int32_t ReadableFontData::CopyTo(OutputStream* os) {
return array_->CopyTo(os, BoundOffset(0), Length());
}
int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
return array_->CopyTo(wfd->BoundOffset(0),
wfd->array_,
BoundOffset(0),
Length());
}
int32_t ReadableFontData::CopyTo(ByteArray* ba) {
return array_->CopyTo(ba, BoundOffset(0), Length());
}
int32_t ReadableFontData::SearchUShort(int32_t start_index,
int32_t start_offset,
int32_t end_index,
int32_t end_offset,
int32_t length,
int32_t key) {
int32_t location = 0;
int32_t bottom = 0;
int32_t top = length;
while (top != bottom) {
location = (top + bottom) / 2;
int32_t location_start = ReadUShort(start_index + location * start_offset);
if (key < location_start) {
// location is below current location
top = location;
} else {
// is key below the upper bound?
int32_t location_end = ReadUShort(end_index + location * end_offset);
#if defined (SFNTLY_DEBUG_FONTDATA)
fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
#endif
if (key <= location_end) {
return location;
} else {
// location is above the current location
bottom = location + 1;
}
}
}
return -1;
}
int32_t ReadableFontData::SearchUShort(int32_t start_index,
int32_t start_offset,
int32_t length,
int32_t key) {
int32_t location = 0;
int32_t bottom = 0;
int32_t top = length;
while (top != bottom) {
location = (top + bottom) / 2;
int32_t location_start = ReadUShort(start_index + location * start_offset);
if (key < location_start) {
// location is below current location
top = location;
} else if (key > location_start) {
// location is above current location
bottom = location + 1;
} else {
return location;
}
}
return -1;
}
int32_t ReadableFontData::SearchULong(int32_t start_index,
int32_t start_offset,
int32_t end_index,
int32_t end_offset,
int32_t length,
int32_t key) {
int32_t location = 0;
int32_t bottom = 0;
int32_t top = length;
while (top != bottom) {
location = (top + bottom) / 2;
int32_t location_start = ReadULongAsInt(start_index
+ location * start_offset);
if (key < location_start) {
// location is below current location
top = location;
} else {
// is key below the upper bound?
int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
#if defined (SFNTLY_DEBUG_FONTDATA)
fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
#endif
if (key <= location_end) {
return location;
} else {
// location is above the current location
bottom = location + 1;
}
}
}
return -1;
}
CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
int32_t length) {
if (offset < 0 || offset + length > Size()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundsException(
"Attempt to bind data outside of its limits");
#endif
return NULL;
}
FontDataPtr slice = new ReadableFontData(this, offset, length);
return slice.Detach();
}
CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
if (offset < 0 || offset > Size()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundsException(
"Attempt to bind data outside of its limits");
#endif
return NULL;
}
FontDataPtr slice = new ReadableFontData(this, offset);
return slice.Detach();
}
ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
: FontData(data, offset),
checksum_set_(false),
checksum_(0) {
}
ReadableFontData::ReadableFontData(ReadableFontData* data,
int32_t offset,
int32_t length)
: FontData(data, offset, length),
checksum_set_(false),
checksum_(0) {
}
void ReadableFontData::ComputeChecksum() {
// TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
int64_t sum = 0;
if (checksum_range_.empty()) {
sum = ComputeCheckSum(0, Length());
} else {
for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
low_bound_index += 2) {
int32_t low_bound = checksum_range_[low_bound_index];
int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
Length() :
checksum_range_[low_bound_index + 1];
sum += ComputeCheckSum(low_bound, high_bound);
}
}
checksum_ = sum & 0xffffffffL;
checksum_set_ = true;
}
int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
int32_t high_bound) {
int64_t sum = 0;
// Checksum all whole 4-byte chunks.
for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
sum += ReadULong(i);
}
// Add last fragment if not 4-byte multiple
int32_t off = high_bound & -4;
if (off < high_bound) {
int32_t b3 = ReadUByte(off);
int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
int32_t b0 = 0;
sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
}
return sum;
}
} // namespace sfntly

View File

@ -1,308 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
#include "sfntly/data/font_data.h"
#include "sfntly/port/lock.h"
namespace sfntly {
class WritableFontData;
class OutputStream;
// Writable font data wrapper. Supports reading of data primitives in the
// TrueType / OpenType spec.
// The data types used are as listed:
// BYTE 8-bit unsigned integer.
// CHAR 8-bit signed integer.
// USHORT 16-bit unsigned integer.
// SHORT 16-bit signed integer.
// UINT24 24-bit unsigned integer.
// ULONG 32-bit unsigned integer.
// LONG 32-bit signed integer.
// Fixed 32-bit signed fixed-point number (16.16)
// FUNIT Smallest measurable distance in the em space.
// FWORD 16-bit signed integer (SHORT) that describes a quantity in FUnits.
// UFWORD 16-bit unsigned integer (USHORT) that describes a quantity in
// FUnits.
// F2DOT14 16-bit signed fixed number with the low 14 bits of fraction (2.14)
// LONGDATETIME Date represented in number of seconds since 12:00 midnight,
// January 1, 1904. The value is represented as a signed 64-bit
// integer.
class ReadableFontData : public FontData,
public RefCounted<ReadableFontData> {
public:
explicit ReadableFontData(ByteArray* array);
virtual ~ReadableFontData();
static CALLER_ATTACH ReadableFontData* CreateReadableFontData(ByteVector* b);
// Gets a computed checksum for the data. This checksum uses the OpenType spec
// calculation. Every ULong value (32 bit unsigned) in the data is summed and
// the resulting value is truncated to 32 bits. If the data length in bytes is
// not an integral multiple of 4 then any remaining bytes are treated as the
// start of a 4 byte sequence whose remaining bytes are zero.
// @return the checksum
int64_t Checksum();
// Sets the bounds to use for computing the checksum. These bounds are in
// begin and end pairs. If an odd number is given then the final range is
// assumed to extend to the end of the data. The lengths of each range must be
// a multiple of 4.
// @param ranges the range bounds to use for the checksum
void SetCheckSumRanges(const IntegerList& ranges);
// Read the UBYTE at the given index.
// @param index index into the font data
// @return the UBYTE; -1 if outside the bounds of the font data
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadUByte(int32_t index);
// Read the BYTE at the given index.
// @param index index into the font data
// @return the BYTE
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadByte(int32_t index);
// Read the bytes at the given index into the array.
// @param index index into the font data
// @param b the destination for the bytes read
// @param offset offset in the byte array to place the bytes
// @param length the length of bytes to read
// @return the number of bytes actually read; -1 if the index is outside the
// bounds of the font data
virtual int32_t ReadBytes(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
// Read the CHAR at the given index.
// @param index index into the font data
// @return the CHAR
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadChar(int32_t index);
// Read the USHORT at the given index.
// @param index index into the font data
// @return the USHORT
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadUShort(int32_t index);
// Read the SHORT at the given index.
// @param index index into the font data
// @return the SHORT
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadShort(int32_t index);
// Read the UINT24 at the given index.
// @param index index into the font data
// @return the UINT24
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadUInt24(int32_t index);
// Read the ULONG at the given index.
// @param index index into the font data
// @return the ULONG
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int64_t ReadULong(int32_t index);
// Read the ULONG at the given index as int32_t.
// @param index index into the font data
// @return the ULONG
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadULongAsInt(int32_t index);
// Read the ULONG at the given index, little-endian variant
// @param index index into the font data
// @return the ULONG
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int64_t ReadULongLE(int32_t index);
// Read the LONG at the given index.
// @param index index into the font data
// @return the LONG
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadLong(int32_t index);
// Read the Fixed at the given index.
// @param index index into the font data
// @return the Fixed
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadFixed(int32_t index);
// Read the LONGDATETIME at the given index.
// @param index index into the font data
// @return the LONGDATETIME
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int64_t ReadDateTimeAsLong(int32_t index);
// Read the FWORD at the given index.
// @param index index into the font data
// @return the FWORD
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadFWord(int32_t index);
// Read the UFWORD at the given index.
// @param index index into the font data
// @return the UFWORD
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t ReadFUFWord(int32_t index);
// Note: Not ported because they just throw UnsupportedOperationException()
// in Java.
/*
virtual int32_t ReadFUnit(int32_t index);
virtual int64_t ReadF2Dot14(int32_t index);
*/
// Copy the FontData to an OutputStream.
// @param os the destination
// @return number of bytes copied
// @throws IOException
virtual int32_t CopyTo(OutputStream* os);
// Copy the FontData to a WritableFontData.
// @param wfd the destination
// @return number of bytes copied
// @throws IOException
virtual int32_t CopyTo(WritableFontData* wfd);
// Make gcc -Woverloaded-virtual happy.
virtual int32_t CopyTo(ByteArray* ba);
// Search for the key value in the range tables provided.
// The search looks through the start-end pairs looking for the key value. It
// is assumed that the start-end pairs are both represented by UShort values,
// ranges do not overlap, and are monotonically increasing.
// @param startIndex the position to read the first start value from
// @param startOffset the offset between subsequent start values
// @param endIndex the position to read the first end value from
// @param endOffset the offset between subsequent end values
// @param length the number of start-end pairs
// @param key the value to search for
// @return the index of the start-end pairs in which the key was found; -1
// otherwise
int32_t SearchUShort(int32_t start_index,
int32_t start_offset,
int32_t end_index,
int32_t end_offset,
int32_t length,
int32_t key);
// Search for the key value in the table provided.
// The search looks through the values looking for the key value. It is
// assumed that the are represented by UShort values and are monotonically
// increasing.
// @param startIndex the position to read the first start value from
// @param startOffset the offset between subsequent start values
// @param length the number of start-end pairs
// @param key the value to search for
// @return the index of the start-end pairs in which the key was found; -1
// otherwise
int32_t SearchUShort(int32_t start_index,
int32_t start_offset,
int32_t length,
int32_t key);
// Search for the key value in the range tables provided.
// The search looks through the start-end pairs looking for the key value. It
// is assumed that the start-end pairs are both represented by ULong values
// that can be represented within 31 bits, ranges do not overlap, and are
// monotonically increasing.
// @param startIndex the position to read the first start value from
// @param startOffset the offset between subsequent start values
// @param endIndex the position to read the first end value from
// @param endOffset the offset between subsequent end values
// @param length the number of start-end pairs
// @param key the value to search for
// @return the index of the start-end pairs in which the key was found; -1
// otherwise
int32_t SearchULong(int32_t start_index,
int32_t start_offset,
int32_t end_index,
int32_t end_offset,
int32_t length,
int32_t key);
// TODO(arthurhsu): IMPLEMENT
/*
virtual int32_t ReadFUnit(int32_t index);
virtual int64_t ReadF2Dot14(int32_t index);
virtual int64_t ReadLongDateTime(int32_t index);
*/
// Makes a slice of this FontData. The returned slice will share the data with
// the original FontData.
// @param offset the start of the slice
// @param length the number of bytes in the slice
// @return a slice of the original FontData
// Note: C++ polymorphism requires return type to be consistent
virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length);
// Makes a bottom bound only slice of this array. The returned slice will
// share the data with the original FontData.
// @param offset the start of the slice
// @return a slice of the original FontData
// Note: C++ polymorphism requires return type to be consistent
virtual CALLER_ATTACH FontData* Slice(int32_t offset);
// Not Ported: toString()
protected:
// Constructor. Creates a bounded wrapper of another ReadableFontData from the
// given offset until the end of the original ReadableFontData.
// @param data data to wrap
// @param offset the start of this data's view of the original data
ReadableFontData(ReadableFontData* data, int32_t offset);
// Constructor. Creates a bounded wrapper of another ReadableFontData from the
// given offset until the end of the original ReadableFontData.
// @param data data to wrap
// @param offset the start of this data's view of the original data
// @param length the length of the other FontData to use
ReadableFontData(ReadableFontData* data, int32_t offset, int32_t length);
private:
// Compute the checksum for the font data using any ranges set for the
// calculation.
void ComputeChecksum();
// Do the actual computation of the checksum for a range using the
// TrueType/OpenType checksum algorithm. The range used is from the low bound
// to the high bound in steps of four bytes. If any of the bytes within that 4
// byte segment are not readable then it will considered a zero for
// calculation.
// Only called from within a synchronized method so it does not need to be
// synchronized itself.
// @param lowBound first position to start a 4 byte segment on
// @param highBound last possible position to start a 4 byte segment on
// @return the checksum for the total range
int64_t ComputeCheckSum(int32_t low_bound, int32_t high_bound);
Lock checksum_lock_;
bool checksum_set_;
int64_t checksum_;
IntegerList checksum_range_;
};
typedef Ptr<ReadableFontData> ReadableFontDataPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_

View File

@ -1,201 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/data/writable_font_data.h"
#include "sfntly/data/memory_byte_array.h"
#include "sfntly/data/growable_memory_byte_array.h"
namespace sfntly {
WritableFontData::WritableFontData(ByteArray* ba) : ReadableFontData(ba) {
}
WritableFontData::~WritableFontData() {}
// static
CALLER_ATTACH
WritableFontData* WritableFontData::CreateWritableFontData(int32_t length) {
ByteArrayPtr ba;
if (length > 0) {
ba = new MemoryByteArray(length);
ba->SetFilledLength(length);
} else {
ba = new GrowableMemoryByteArray();
}
WritableFontDataPtr wfd = new WritableFontData(ba);
return wfd.Detach();
}
// TODO(arthurhsu): re-investigate the memory model of this function. It's
// not too useful without copying, but it's not performance
// savvy to do copying.
CALLER_ATTACH
WritableFontData* WritableFontData::CreateWritableFontData(ByteVector* b) {
ByteArrayPtr ba = new GrowableMemoryByteArray();
ba->Put(0, b);
WritableFontDataPtr wfd = new WritableFontData(ba);
return wfd.Detach();
}
int32_t WritableFontData::WriteByte(int32_t index, byte_t b) {
array_->Put(BoundOffset(index), b);
return 1;
}
int32_t WritableFontData::WriteBytes(int32_t index,
byte_t* b,
int32_t offset,
int32_t length) {
return array_->Put(BoundOffset(index),
b,
offset,
BoundLength(index, length));
}
int32_t WritableFontData::WriteBytes(int32_t index, ByteVector* b) {
assert(b);
return WriteBytes(index, &((*b)[0]), 0, b->size());
}
int32_t WritableFontData::WriteBytesPad(int32_t index,
ByteVector* b,
int32_t offset,
int32_t length,
byte_t pad) {
int32_t written =
array_->Put(BoundOffset(index),
&((*b)[0]),
offset,
BoundLength(index,
std::min<int32_t>(length, b->size() - offset)));
written += WritePadding(written + index, length - written, pad);
return written;
}
int32_t WritableFontData::WritePadding(int32_t index, int32_t count) {
return WritePadding(index, count, (byte_t)0);
}
int32_t WritableFontData::WritePadding(int32_t index, int32_t count,
byte_t pad) {
for (int32_t i = 0; i < count; ++i) {
array_->Put(index + i, pad);
}
return count;
}
int32_t WritableFontData::WriteChar(int32_t index, byte_t c) {
return WriteByte(index, c);
}
int32_t WritableFontData::WriteUShort(int32_t index, int32_t us) {
WriteByte(index, (byte_t)((us >> 8) & 0xff));
WriteByte(index + 1, (byte_t)(us & 0xff));
return 2;
}
int32_t WritableFontData::WriteUShortLE(int32_t index, int32_t us) {
WriteByte(index, (byte_t)(us & 0xff));
WriteByte(index + 1, (byte_t)((us >> 8) & 0xff));
return 2;
}
int32_t WritableFontData::WriteShort(int32_t index, int32_t s) {
return WriteUShort(index, s);
}
int32_t WritableFontData::WriteUInt24(int32_t index, int32_t ui) {
WriteByte(index, (byte_t)((ui >> 16) & 0xff));
WriteByte(index + 1, (byte_t)((ui >> 8) & 0xff));
WriteByte(index + 2, (byte_t)(ui & 0xff));
return 3;
}
int32_t WritableFontData::WriteULong(int32_t index, int64_t ul) {
WriteByte(index, (byte_t)((ul >> 24) & 0xff));
WriteByte(index + 1, (byte_t)((ul >> 16) & 0xff));
WriteByte(index + 2, (byte_t)((ul >> 8) & 0xff));
WriteByte(index + 3, (byte_t)(ul & 0xff));
return 4;
}
int32_t WritableFontData::WriteULongLE(int32_t index, int64_t ul) {
WriteByte(index, (byte_t)(ul & 0xff));
WriteByte(index + 1, (byte_t)((ul >> 8) & 0xff));
WriteByte(index + 2, (byte_t)((ul >> 16) & 0xff));
WriteByte(index + 3, (byte_t)((ul >> 24) & 0xff));
return 4;
}
int32_t WritableFontData::WriteLong(int32_t index, int64_t l) {
return WriteULong(index, l);
}
int32_t WritableFontData::WriteFixed(int32_t index, int32_t f) {
return WriteLong(index, f);
}
int32_t WritableFontData::WriteDateTime(int32_t index, int64_t date) {
WriteULong(index, (date >> 32) & 0xffffffff);
WriteULong(index + 4, date & 0xffffffff);
return 8;
}
void WritableFontData::CopyFrom(InputStream* is, int32_t length) {
array_->CopyFrom(is, length);
}
void WritableFontData::CopyFrom(InputStream* is) {
array_->CopyFrom(is);
}
CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset,
int32_t length) {
if (offset < 0 || offset + length > Size()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundsException(
"Attempt to bind data outside of its limits");
#endif
return NULL;
}
FontDataPtr slice = new WritableFontData(this, offset, length);
return slice.Detach();
}
CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset) {
if (offset > Size()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundsException(
"Attempt to bind data outside of its limits");
#endif
return NULL;
}
FontDataPtr slice = new WritableFontData(this, offset);
return slice.Detach();
}
WritableFontData::WritableFontData(WritableFontData* data, int32_t offset)
: ReadableFontData(data, offset) {
}
WritableFontData::WritableFontData(WritableFontData* data,
int32_t offset,
int32_t length)
: ReadableFontData(data, offset, length) {
}
} // namespace sfntly

View File

@ -1,211 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
#define SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
#include "sfntly/data/readable_font_data.h"
namespace sfntly {
// Writable font data wrapper. Supports writing of data primitives in the
// TrueType / OpenType spec.
class WritableFontData : public ReadableFontData {
public:
explicit WritableFontData(ByteArray* ba);
virtual ~WritableFontData();
// Constructs a writable font data object. If the length is specified as
// positive then a fixed size font data object will be created. If the length
// is zero or less then a growable font data object will be created and the
// size will be used as an estimate to help in allocating the original space.
// @param length if length > 0 create a fixed length font data; otherwise
// create a growable font data
// @return a new writable font data
static CALLER_ATTACH WritableFontData* CreateWritableFontData(int32_t length);
// Constructs a writable font data object. The new font data object will wrap
// the bytes passed in to the factory and it will take make a copy of those
// bytes.
// @param b the byte vector to wrap
// @return a new writable font data
static CALLER_ATTACH WritableFontData* CreateWritableFontData(ByteVector* b);
// Write a byte at the given index.
// @param index index into the font data
// @param b the byte to write
// @return the number of bytes written
virtual int32_t WriteByte(int32_t index, byte_t b);
// Write the bytes from the array.
// @param index index into the font data
// @param b the source for the bytes to be written
// @param offset offset in the byte array
// @param length the length of the bytes to be written
// @return the number of bytes actually written; -1 if the index is outside
// the FontData's range
virtual int32_t WriteBytes(int32_t index,
byte_t* b,
int32_t offset,
int32_t length);
// Write the bytes from the array.
// @param index index into the font data
// @param b the source for the bytes to be written
// @return the number of bytes actually written; -1 if the index is outside
// the FontData's range
virtual int32_t WriteBytes(int32_t index, ByteVector* b);
// Write the bytes from the array and pad if necessary.
// Write to the length given using the byte array provided and if there are
// not enough bytes in the array then pad to the requested length using the
// pad byte specified.
// @param index index into the font data
// @param b the source for the bytes to be written
// @param offset offset in the byte array
// @param length the length of the bytes to be written
// @param pad the padding byte to be used if necessary
// @return the number of bytes actually written
virtual int32_t WriteBytesPad(int32_t index,
ByteVector* b,
int32_t offset,
int32_t length,
byte_t pad);
// Writes padding to the FontData. The padding byte written is 0x00.
// @param index index into the font data
// @param count the number of pad bytes to write
// @return the number of pad bytes written
virtual int32_t WritePadding(int32_t index, int32_t count);
// Writes padding to the FontData.
// @param index index into the font data
// @param count the number of pad bytes to write
// @param pad the byte value to use as padding
// @return the number of pad bytes written
virtual int32_t WritePadding(int32_t index, int32_t count, byte_t pad);
// Write the CHAR at the given index.
// @param index index into the font data
// @param c the CHAR
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteChar(int32_t index, byte_t c);
// Write the USHORT at the given index.
// @param index index into the font data
// @param us the USHORT
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteUShort(int32_t index, int32_t us);
// Write the USHORT at the given index in little endian format.
// @param index index into the font data
// @param us the USHORT
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteUShortLE(int32_t index, int32_t us);
// Write the SHORT at the given index.
// @param index index into the font data
// @param s the SHORT
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteShort(int32_t index, int32_t s);
// Write the UINT24 at the given index.
// @param index index into the font data
// @param ui the UINT24
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteUInt24(int32_t index, int32_t ui);
// Write the ULONG at the given index.
// @param index index into the font data
// @param ul the ULONG
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteULong(int32_t index, int64_t ul);
// Write the ULONG at the given index in little endian format.
// @param index index into the font data
// @param ul the ULONG
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteULongLE(int32_t index, int64_t ul);
// Write the LONG at the given index.
// @param index index into the font data
// @param l the LONG
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteLong(int32_t index, int64_t l);
// Write the Fixed at the given index.
// @param index index into the font data
// @param f the Fixed
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteFixed(int32_t index, int32_t f);
// Write the LONGDATETIME at the given index.
// @param index index into the font data
// @param date the LONGDATETIME
// @return the number of bytes actually written
// @throws IndexOutOfBoundsException if index is outside the FontData's range
virtual int32_t WriteDateTime(int32_t index, int64_t date);
// Copy from the InputStream into this FontData.
// @param is the source
// @param length the number of bytes to copy
// @throws IOException
virtual void CopyFrom(InputStream* is, int32_t length);
// Copy everything from the InputStream into this FontData.
// @param is the source
// @throws IOException
virtual void CopyFrom(InputStream* is);
// Makes a slice of this FontData. The returned slice will share the data with
// the original FontData.
// @param offset the start of the slice
// @param length the number of bytes in the slice
// @return a slice of the original FontData
virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length);
// Makes a bottom bound only slice of this array. The returned slice will
// share the data with the original FontData.
// @param offset the start of the slice
// @return a slice of the original FontData
virtual CALLER_ATTACH FontData* Slice(int32_t offset);
private:
// Constructor with a lower bound.
// @param data other WritableFontData object to share data with
// @param offset offset from the other WritableFontData's data
WritableFontData(WritableFontData* data, int32_t offset);
// Constructor with lower bound and a length bound.
// @param data other WritableFontData object to share data with
// @param offset offset from the other WritableFontData's data
// @param length length of other WritableFontData's data to use
WritableFontData(WritableFontData* data, int32_t offset, int32_t length);
};
typedef Ptr<WritableFontData> WritableFontDataPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_

View File

@ -1,568 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/font.h"
#include <stdio.h>
#include <functional>
#include <algorithm>
#include <map>
#include <string>
#include <typeinfo>
#include <iterator>
#include "sfntly/data/font_input_stream.h"
#include "sfntly/font_factory.h"
#include "sfntly/math/fixed1616.h"
#include "sfntly/math/font_math.h"
#include "sfntly/port/exception_type.h"
#include "sfntly/table/core/font_header_table.h"
#include "sfntly/table/core/horizontal_device_metrics_table.h"
#include "sfntly/table/core/horizontal_header_table.h"
#include "sfntly/table/core/horizontal_metrics_table.h"
#include "sfntly/table/core/maximum_profile_table.h"
#include "sfntly/table/truetype/loca_table.h"
#include "sfntly/tag.h"
namespace sfntly {
const int32_t SFNTVERSION_MAJOR = 1;
const int32_t SFNTVERSION_MINOR = 0;
/******************************************************************************
* Font class
******************************************************************************/
Font::~Font() {}
bool Font::HasTable(int32_t tag) {
TableMap::const_iterator result = tables_.find(tag);
TableMap::const_iterator end = tables_.end();
return (result != end);
}
// Changed by Kovid: these four methods cannot be inlined, if they are they
// return incorrect values when compiled with -fPIC
int32_t Font::sfnt_version() { return sfnt_version_; }
ByteVector* Font::digest() { return &digest_; }
int64_t Font::checksum() { return checksum_; }
int32_t Font::num_tables() { return (int32_t)tables_.size(); }
Table* Font::GetTable(int32_t tag) {
if (!HasTable(tag)) {
return NULL;
}
return tables_[tag];
}
const TableMap* Font::GetTableMap() {
return &tables_;
}
void Font::Serialize(OutputStream* os, IntegerList* table_ordering) {
assert(table_ordering);
IntegerList final_table_ordering;
GenerateTableOrdering(table_ordering, &final_table_ordering);
TableHeaderList table_records;
BuildTableHeadersForSerialization(&final_table_ordering, &table_records);
FontOutputStream fos(os);
SerializeHeader(&fos, &table_records);
SerializeTables(&fos, &table_records);
}
Font::Font(int32_t sfnt_version, ByteVector* digest)
: sfnt_version_(sfnt_version) {
// non-trivial assignments that makes debugging hard if placed in
// initialization list
digest_ = *digest;
}
void Font::BuildTableHeadersForSerialization(IntegerList* table_ordering,
TableHeaderList* table_headers) {
assert(table_headers);
assert(table_ordering);
IntegerList final_table_ordering;
GenerateTableOrdering(table_ordering, &final_table_ordering);
int32_t table_offset = Offset::kTableRecordBegin + num_tables() *
Offset::kTableRecordSize;
for (IntegerList::iterator tag = final_table_ordering.begin(),
tag_end = final_table_ordering.end();
tag != tag_end; ++tag) {
if (tables_.find(*tag) == tables_.end()) {
continue;
}
TablePtr table = tables_[*tag];
if (table != NULL) {
HeaderPtr header =
new Header(*tag, table->CalculatedChecksum(), table_offset,
table->header()->length());
table_headers->push_back(header);
table_offset += (table->DataLength() + 3) & ~3;
}
}
}
void Font::SerializeHeader(FontOutputStream* fos,
TableHeaderList* table_headers) {
fos->WriteFixed(sfnt_version_);
fos->WriteUShort(table_headers->size());
int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size());
int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4);
fos->WriteUShort(search_range);
fos->WriteUShort(log2_of_max_power_of_2);
fos->WriteUShort((table_headers->size() * 16) - search_range);
HeaderTagSortedSet sorted_headers;
std::copy(table_headers->begin(),
table_headers->end(),
std::inserter(sorted_headers, sorted_headers.end()));
for (HeaderTagSortedSet::iterator record = sorted_headers.begin(),
record_end = sorted_headers.end();
record != record_end; ++record) {
fos->WriteULong((*record)->tag());
fos->WriteULong((int32_t)((*record)->checksum()));
fos->WriteULong((*record)->offset());
fos->WriteULong((*record)->length());
}
}
void Font::SerializeTables(FontOutputStream* fos,
TableHeaderList* table_headers) {
assert(fos);
assert(table_headers);
for (TableHeaderList::iterator record = table_headers->begin(),
end_of_headers = table_headers->end();
record != end_of_headers; ++record) {
TablePtr target_table = GetTable((*record)->tag());
if (target_table == NULL) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("Table out of sync with font header.");
#endif
return;
}
int32_t table_size = target_table->Serialize(fos);
if (table_size != (*record)->length()) {
assert(false);
}
int32_t filler_size = ((table_size + 3) & ~3) - table_size;
for (int32_t i = 0; i < filler_size; ++i) {
fos->Write(static_cast<byte_t>(0));
}
}
}
void Font::GenerateTableOrdering(IntegerList* default_table_ordering,
IntegerList* table_ordering) {
assert(default_table_ordering);
assert(table_ordering);
table_ordering->clear();
if (default_table_ordering->empty()) {
DefaultTableOrdering(default_table_ordering);
}
typedef std::map<int32_t, bool> Int2Bool;
typedef std::pair<int32_t, bool> Int2BoolEntry;
Int2Bool tables_in_font;
for (TableMap::iterator table = tables_.begin(), table_end = tables_.end();
table != table_end; ++table) {
tables_in_font.insert(Int2BoolEntry(table->first, false));
}
for (IntegerList::iterator tag = default_table_ordering->begin(),
tag_end = default_table_ordering->end();
tag != tag_end; ++tag) {
if (HasTable(*tag)) {
table_ordering->push_back(*tag);
tables_in_font[*tag] = true;
}
}
for (Int2Bool::iterator table = tables_in_font.begin(),
table_end = tables_in_font.end();
table != table_end; ++table) {
if (table->second == false)
table_ordering->push_back(table->first);
}
}
void Font::DefaultTableOrdering(IntegerList* default_table_ordering) {
assert(default_table_ordering);
default_table_ordering->clear();
if (HasTable(Tag::CFF)) {
default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE);
std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE,
default_table_ordering->begin());
return;
}
default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE);
std::copy(TRUE_TYPE_TABLE_ORDERING,
TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE,
default_table_ordering->begin());
}
/******************************************************************************
* Font::Builder class
******************************************************************************/
Font::Builder::~Builder() {}
CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory,
InputStream* is) {
FontBuilderPtr builder = new Builder(factory);
builder->LoadFont(is);
return builder.Detach();
}
CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
FontFactory* factory,
WritableFontData* wfd,
int32_t offset_to_offset_table) {
FontBuilderPtr builder = new Builder(factory);
builder->LoadFont(wfd, offset_to_offset_table);
return builder.Detach();
}
CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
FontFactory* factory) {
FontBuilderPtr builder = new Builder(factory);
return builder.Detach();
}
bool Font::Builder::ReadyToBuild() {
// just read in data with no manipulation
if (table_builders_.empty() && !data_blocks_.empty()) {
return true;
}
// TODO(stuartg): font level checks - required tables etc?
for (TableBuilderMap::iterator table_builder = table_builders_.begin(),
table_builder_end = table_builders_.end();
table_builder != table_builder_end;
++table_builder) {
if (!table_builder->second->ReadyToBuild())
return false;
}
return true;
}
CALLER_ATTACH Font* Font::Builder::Build() {
FontPtr font = new Font(sfnt_version_, &digest_);
if (!table_builders_.empty()) {
// Note: Different from Java. Directly use font->tables_ here to avoid
// STL container copying.
BuildTablesFromBuilders(font, &table_builders_, &font->tables_);
}
table_builders_.clear();
data_blocks_.clear();
return font.Detach();
}
void Font::Builder::SetDigest(ByteVector* digest) {
digest_.clear();
digest_ = *digest;
}
void Font::Builder::ClearTableBuilders() {
table_builders_.clear();
}
bool Font::Builder::HasTableBuilder(int32_t tag) {
return (table_builders_.find(tag) != table_builders_.end());
}
Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) {
if (HasTableBuilder(tag))
return table_builders_[tag];
return NULL;
}
Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) {
HeaderPtr header = new Header(tag);
TableBuilderPtr builder;
builder.Attach(Table::Builder::GetBuilder(header, NULL));
table_builders_.insert(TableBuilderEntry(header->tag(), builder));
return builder;
}
Table::Builder* Font::Builder::NewTableBuilder(int32_t tag,
ReadableFontData* src_data) {
assert(src_data);
WritableFontDataPtr data;
data.Attach(WritableFontData::CreateWritableFontData(src_data->Length()));
// TODO(stuarg): take over original data instead?
src_data->CopyTo(data);
HeaderPtr header = new Header(tag, data->Length());
TableBuilderPtr builder;
builder.Attach(Table::Builder::GetBuilder(header, data));
table_builders_.insert(TableBuilderEntry(tag, builder));
return builder;
}
void Font::Builder::RemoveTableBuilder(int32_t tag) {
TableBuilderMap::iterator target = table_builders_.find(tag);
if (target != table_builders_.end()) {
table_builders_.erase(target);
}
}
Font::Builder::Builder(FontFactory* factory)
: factory_(factory),
sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) {
}
void Font::Builder::LoadFont(InputStream* is) {
// Note: we do not throw exception here for is. This is more of an assertion.
assert(is);
FontInputStream font_is(is);
HeaderOffsetSortedSet records;
ReadHeader(&font_is, &records);
LoadTableData(&records, &font_is, &data_blocks_);
BuildAllTableBuilders(&data_blocks_, &table_builders_);
font_is.Close();
}
void Font::Builder::LoadFont(WritableFontData* wfd,
int32_t offset_to_offset_table) {
// Note: we do not throw exception here for is. This is more of an assertion.
assert(wfd);
HeaderOffsetSortedSet records;
ReadHeader(wfd, offset_to_offset_table, &records);
LoadTableData(&records, wfd, &data_blocks_);
BuildAllTableBuilders(&data_blocks_, &table_builders_);
}
int32_t Font::Builder::SfntWrapperSize() {
return Offset::kSfntHeaderSize +
(Offset::kTableRecordSize * table_builders_.size());
}
void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data,
TableBuilderMap* builder_map) {
for (DataBlockMap::iterator record = table_data->begin(),
record_end = table_data->end();
record != record_end; ++record) {
TableBuilderPtr builder;
builder.Attach(GetTableBuilder(record->first.p_, record->second.p_));
builder_map->insert(TableBuilderEntry(record->first->tag(), builder));
}
InterRelateBuilders(&table_builders_);
}
CALLER_ATTACH
Table::Builder* Font::Builder::GetTableBuilder(Header* header,
WritableFontData* data) {
return Table::Builder::GetBuilder(header, data);
}
void Font::Builder::BuildTablesFromBuilders(Font* font,
TableBuilderMap* builder_map,
TableMap* table_map) {
UNREFERENCED_PARAMETER(font);
InterRelateBuilders(builder_map);
// Now build all the tables.
for (TableBuilderMap::iterator builder = builder_map->begin(),
builder_end = builder_map->end();
builder != builder_end; ++builder) {
TablePtr table;
if (builder->second && builder->second->ReadyToBuild()) {
table.Attach(down_cast<Table*>(builder->second->Build()));
}
if (table == NULL) {
table_map->clear();
#if !defined (SFNTLY_NO_EXCEPTION)
std::string builder_string = "Unable to build table - ";
char* table_name = TagToString(builder->first);
builder_string += table_name;
delete[] table_name;
throw RuntimeException(builder_string.c_str());
#endif
return;
}
table_map->insert(TableMapEntry(table->header()->tag(), table));
}
}
static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) {
if (builder_map) {
TableBuilderMap::iterator target = builder_map->find(tag);
if (target != builder_map->end()) {
return target->second.p_;
}
}
return NULL;
}
void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) {
Table::Builder* raw_head_builder = GetBuilder(builder_map, Tag::head);
FontHeaderTableBuilderPtr header_table_builder;
if (raw_head_builder != NULL) {
header_table_builder =
down_cast<FontHeaderTable::Builder*>(raw_head_builder);
}
Table::Builder* raw_hhea_builder = GetBuilder(builder_map, Tag::hhea);
HorizontalHeaderTableBuilderPtr horizontal_header_builder;
if (raw_head_builder != NULL) {
horizontal_header_builder =
down_cast<HorizontalHeaderTable::Builder*>(raw_hhea_builder);
}
Table::Builder* raw_maxp_builder = GetBuilder(builder_map, Tag::maxp);
MaximumProfileTableBuilderPtr max_profile_builder;
if (raw_maxp_builder != NULL) {
max_profile_builder =
down_cast<MaximumProfileTable::Builder*>(raw_maxp_builder);
}
Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca);
LocaTableBuilderPtr loca_table_builder;
if (raw_loca_builder != NULL) {
loca_table_builder = down_cast<LocaTable::Builder*>(raw_loca_builder);
}
Table::Builder* raw_hmtx_builder = GetBuilder(builder_map, Tag::hmtx);
HorizontalMetricsTableBuilderPtr horizontal_metrics_builder;
if (raw_hmtx_builder != NULL) {
horizontal_metrics_builder =
down_cast<HorizontalMetricsTable::Builder*>(raw_hmtx_builder);
}
#if defined (SFNTLY_EXPERIMENTAL)
Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx);
HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder;
if (raw_hdmx_builder != NULL) {
hdmx_table_builder =
down_cast<HorizontalDeviceMetricsTable::Builder*>(raw_hdmx_builder);
}
#endif
// set the inter table data required to build certain tables
if (horizontal_metrics_builder != NULL) {
if (max_profile_builder != NULL) {
horizontal_metrics_builder->SetNumGlyphs(
max_profile_builder->NumGlyphs());
}
if (horizontal_header_builder != NULL) {
horizontal_metrics_builder->SetNumberOfHMetrics(
horizontal_header_builder->NumberOfHMetrics());
}
}
if (loca_table_builder != NULL) {
if (max_profile_builder != NULL) {
loca_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
}
if (header_table_builder != NULL) {
loca_table_builder->set_format_version(
header_table_builder->IndexToLocFormat());
}
}
#if defined (SFNTLY_EXPERIMENTAL)
// Note: In C++, hdmx_table_builder can be NULL in a subsetter.
if (max_profile_builder != NULL && hdmx_table_builder != NULL) {
hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
}
#endif
}
void Font::Builder::ReadHeader(FontInputStream* is,
HeaderOffsetSortedSet* records) {
assert(records);
sfnt_version_ = is->ReadFixed();
num_tables_ = is->ReadUShort();
search_range_ = is->ReadUShort();
entry_selector_ = is->ReadUShort();
range_shift_ = is->ReadUShort();
for (int32_t table_number = 0; table_number < num_tables_; ++table_number) {
// Need to use temporary vars here. C++ evaluates function parameters from
// right to left and thus breaks the order of input stream.
int32_t tag = is->ReadULongAsInt();
int64_t checksum = is->ReadULong();
int32_t offset = is->ReadULongAsInt();
int32_t length = is->ReadULongAsInt();
HeaderPtr table = new Header(tag, checksum, offset, length);
records->insert(table);
}
}
void Font::Builder::ReadHeader(ReadableFontData* fd,
int32_t offset,
HeaderOffsetSortedSet* records) {
assert(records);
sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion);
num_tables_ = fd->ReadUShort(offset + Offset::kNumTables);
search_range_ = fd->ReadUShort(offset + Offset::kSearchRange);
entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector);
range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift);
int32_t table_offset = offset + Offset::kTableRecordBegin;
for (int32_t table_number = 0;
table_number < num_tables_;
table_number++, table_offset += Offset::kTableRecordSize) {
int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag);
int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum);
int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset);
int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength);
HeaderPtr table = new Header(tag, checksum, offset, length);
records->insert(table);
}
}
void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
FontInputStream* is,
DataBlockMap* table_data) {
assert(table_data);
for (HeaderOffsetSortedSet::iterator table_header = headers->begin(),
table_end = headers->end();
table_header != table_end;
++table_header) {
is->Skip((*table_header)->offset() - is->position());
FontInputStream table_is(is, (*table_header)->length());
WritableFontDataPtr data;
data.Attach(
WritableFontData::CreateWritableFontData((*table_header)->length()));
data->CopyFrom(&table_is, (*table_header)->length());
table_data->insert(DataBlockEntry(*table_header, data));
}
}
void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
WritableFontData* fd,
DataBlockMap* table_data) {
for (HeaderOffsetSortedSet::iterator table_header = headers->begin(),
table_end = headers->end();
table_header != table_end;
++table_header) {
FontDataPtr sliced_data;
sliced_data.Attach(
fd->Slice((*table_header)->offset(), (*table_header)->length()));
WritableFontDataPtr data = down_cast<WritableFontData*>(sliced_data.p_);
table_data->insert(DataBlockEntry(*table_header, data));
}
}
} // namespace sfntly

View File

@ -1,352 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_H_
#define SFNTLY_CPP_SRC_SFNTLY_FONT_H_
#include <vector>
#include "sfntly/port/refcount.h"
#include "sfntly/port/type.h"
#include "sfntly/port/endian.h"
#include "sfntly/data/font_input_stream.h"
#include "sfntly/data/font_output_stream.h"
#include "sfntly/data/writable_font_data.h"
#include "sfntly/table/table.h"
namespace sfntly {
// Note: following constants are embedded in Font class in Java. They are
// extracted out for easier reference from other classes. Offset is the
// one that is kept within class.
// Platform ids. These are used in a number of places within the font whenever
// the platform needs to be specified.
struct PlatformId {
enum {
kUnknown = -1,
kUnicode = 0,
kMacintosh = 1,
kISO = 2,
kWindows = 3,
kCustom = 4
};
};
// Unicode encoding ids. These are used in a number of places within the font
// whenever character encodings need to be specified.
struct UnicodeEncodingId {
enum {
kUnknown = -1,
kUnicode1_0 = 0,
kUnicode1_1 = 1,
kISO10646 = 2,
kUnicode2_0_BMP = 3,
kUnicode2_0 = 4,
kUnicodeVariationSequences = 5
};
};
// Windows encoding ids. These are used in a number of places within the font
// whenever character encodings need to be specified.
struct WindowsEncodingId {
enum {
kUnknown = 0xffffffff,
kSymbol = 0,
kUnicodeUCS2 = 1,
kShiftJIS = 2,
kPRC = 3,
kBig5 = 4,
kWansung = 5,
kJohab = 6,
kUnicodeUCS4 = 10
};
};
// Macintosh encoding ids. These are used in a number of places within the
// font whenever character encodings need to be specified.
struct MacintoshEncodingId {
// Macintosh Platform Encodings
enum {
kUnknown = -1,
kRoman = 0,
kJapanese = 1,
kChineseTraditional = 2,
kKorean = 3,
kArabic = 4,
kHebrew = 5,
kGreek = 6,
kRussian = 7,
kRSymbol = 8,
kDevanagari = 9,
kGurmukhi = 10,
kGujarati = 11,
kOriya = 12,
kBengali = 13,
kTamil = 14,
kTelugu = 15,
kKannada = 16,
kMalayalam = 17,
kSinhalese = 18,
kBurmese = 19,
kKhmer = 20,
kThai = 21,
kLaotian = 22,
kGeorgian = 23,
kArmenian = 24,
kChineseSimplified = 25,
kTibetan = 26,
kMongolian = 27,
kGeez = 28,
kSlavic = 29,
kVietnamese = 30,
kSindhi = 31,
kUninterpreted = 32
};
};
class FontFactory;
// An sfnt container font object. This object is immutable and thread safe. To
// construct one use an instance of Font::Builder.
class Font : public RefCounted<Font> {
public:
// A builder for a font object. The builder allows the for the creation of
// immutable Font objects. The builder is a one use non-thread safe object and
// once the Font object has been created it is no longer usable. To create a
// further Font object new builder will be required.
class Builder : public RefCounted<Builder> {
public:
virtual ~Builder();
static CALLER_ATTACH Builder*
GetOTFBuilder(FontFactory* factory, InputStream* is);
static CALLER_ATTACH Builder*
GetOTFBuilder(FontFactory* factory,
WritableFontData* ba,
int32_t offset_to_offset_table);
static CALLER_ATTACH Builder* GetOTFBuilder(FontFactory* factory);
// Get the font factory that created this font builder.
FontFactory* GetFontFactory() { return factory_; }
// Is the font ready to build?
bool ReadyToBuild();
// Build the Font. After this call this builder will no longer be usable.
CALLER_ATTACH Font* Build();
// Set a unique fingerprint for the font object.
void SetDigest(ByteVector* digest);
// Clear all table builders.
void ClearTableBuilders();
// Does this font builder have the specified table builder.
bool HasTableBuilder(int32_t tag);
// Get the table builder for the given tag. If there is no builder for that
// tag then return a null.
Table::Builder* GetTableBuilder(int32_t tag);
// Creates a new table builder for the table type given by the table id tag.
// This new table has been added to the font and will replace any existing
// builder for that table.
// @return new empty table of the type specified by tag; if tag is not known
// then a generic OpenTypeTable is returned
virtual Table::Builder* NewTableBuilder(int32_t tag);
// Creates a new table builder for the table type given by the table id tag.
// It makes a copy of the data provided and uses that copy for the table.
// This new table has been added to the font and will replace any existing
// builder for that table.
virtual Table::Builder* NewTableBuilder(int32_t tag,
ReadableFontData* src_data);
// Get a map of the table builders in this font builder accessed by table
// tag.
virtual TableBuilderMap* table_builders() { return &table_builders_; }
// Remove the specified table builder from the font builder.
// Note: different from Java: we don't return object in removeTableBuilder
virtual void RemoveTableBuilder(int32_t tag);
// Get the number of table builders in the font builder.
virtual int32_t number_of_table_builders() {
return (int32_t)table_builders_.size();
}
private:
explicit Builder(FontFactory* factory);
virtual void LoadFont(InputStream* is);
virtual void LoadFont(WritableFontData* wfd,
int32_t offset_to_offset_table);
int32_t SfntWrapperSize();
void BuildAllTableBuilders(DataBlockMap* table_data,
TableBuilderMap* builder_map);
CALLER_ATTACH Table::Builder*
GetTableBuilder(Header* header, WritableFontData* data);
void BuildTablesFromBuilders(Font* font,
TableBuilderMap* builder_map,
TableMap* tables);
static void InterRelateBuilders(TableBuilderMap* builder_map);
void ReadHeader(FontInputStream* is,
HeaderOffsetSortedSet* records);
void ReadHeader(ReadableFontData* fd,
int32_t offset,
HeaderOffsetSortedSet* records);
void LoadTableData(HeaderOffsetSortedSet* headers,
FontInputStream* is,
DataBlockMap* table_data);
void LoadTableData(HeaderOffsetSortedSet* headers,
WritableFontData* fd,
DataBlockMap* table_data);
TableBuilderMap table_builders_;
FontFactory* factory_; // dumb pointer, avoid circular refcounting
int32_t sfnt_version_;
int32_t num_tables_;
int32_t search_range_;
int32_t entry_selector_;
int32_t range_shift_;
DataBlockMap data_blocks_;
ByteVector digest_;
};
virtual ~Font();
// Gets the sfnt version set in the sfnt wrapper of the font.
int32_t sfnt_version();
// Gets a copy of the fonts digest that was created when the font was read. If
// no digest was set at creation time then the return result will be null.
ByteVector* digest();
// Get the checksum for this font.
int64_t checksum();
// Get the number of tables in this font.
int32_t num_tables();
// Whether the font has a particular table.
bool HasTable(int32_t tag);
// UNIMPLEMENTED: public Iterator<? extends Table> iterator
// Get the table in this font with the specified id.
// @param tag the identifier of the table
// @return the table specified if it exists; null otherwise
// C++ port: rename table() to GetTable()
Table* GetTable(int32_t tag);
// Get a map of the tables in this font accessed by table tag.
// @return an unmodifiable view of the tables in this font
// Note: renamed tableMap() to GetTableMap()
const TableMap* GetTableMap();
// UNIMPLEMENTED: toString()
// Serialize the font to the output stream.
// @param os the destination for the font serialization
// @param tableOrdering the table ordering to apply
void Serialize(OutputStream* os, IntegerList* table_ordering);
private:
// Offsets to specific elements in the underlying data. These offsets are
// relative to the start of the table or the start of sub-blocks within the
// table.
struct Offset {
enum {
// Offsets within the main directory
kSfntVersion = 0,
kNumTables = 4,
kSearchRange = 6,
kEntrySelector = 8,
kRangeShift = 10,
kTableRecordBegin = 12,
kSfntHeaderSize = 12,
// Offsets within a specific table record
kTableTag = 0,
kTableCheckSum = 4,
kTableOffset = 8,
kTableLength = 12,
kTableRecordSize = 16
};
};
// Note: the two constants are moved to tag.h to avoid VC++ bug.
// static const int32_t CFF_TABLE_ORDERING[];
// static const int32_t TRUE_TYPE_TABLE_ORDERING[];
// Constructor.
// @param sfntVersion the sfnt version
// @param digest the computed digest for the font; null if digest was not
// computed
// Note: Current C++ port does not support SHA digest validation.
Font(int32_t sfnt_version, ByteVector* digest);
// Build the table headers to be used for serialization. These headers will be
// filled out with the data required for serialization. The headers will be
// sorted in the order specified and only those specified will have headers
// generated.
// @param tableOrdering the tables to generate headers for and the order to
// sort them
// @return a list of table headers ready for serialization
void BuildTableHeadersForSerialization(IntegerList* table_ordering,
TableHeaderList* table_headers);
// Searialize the headers.
// @param fos the destination stream for the headers
// @param tableHeaders the headers to serialize
// @throws IOException
void SerializeHeader(FontOutputStream* fos, TableHeaderList* table_headers);
// Serialize the tables.
// @param fos the destination stream for the headers
// @param tableHeaders the headers for the tables to serialize
// @throws IOException
void SerializeTables(FontOutputStream* fos, TableHeaderList* table_headers);
// Generate the full table ordering to used for serialization. The full
// ordering uses the partial ordering as a seed and then adds all remaining
// tables in the font in an undefined order.
// @param defaultTableOrdering the partial ordering to be used as a seed for
// the full ordering
// @param (out) table_ordering the full ordering for serialization
void GenerateTableOrdering(IntegerList* default_table_ordering,
IntegerList* table_ordering);
// Get the default table ordering based on the type of the font.
// @param (out) default_table_ordering the default table ordering
void DefaultTableOrdering(IntegerList* default_table_ordering);
int32_t sfnt_version_;
ByteVector digest_;
int64_t checksum_;
TableMap tables_;
};
typedef Ptr<Font> FontPtr;
typedef std::vector<FontPtr> FontArray;
typedef Ptr<Font::Builder> FontBuilderPtr;
typedef std::vector<FontBuilderPtr> FontBuilderArray;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_H_

View File

@ -1,214 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/font_factory.h"
#include <string.h>
#include "sfntly/tag.h"
namespace sfntly {
FontFactory::~FontFactory() {
}
CALLER_ATTACH FontFactory* FontFactory::GetInstance() {
FontFactoryPtr instance = new FontFactory();
return instance.Detach();
}
void FontFactory::FingerprintFont(bool fingerprint) {
fingerprint_ = fingerprint;
}
bool FontFactory::FingerprintFont() {
return fingerprint_;
}
void FontFactory::LoadFonts(InputStream* is, FontArray* output) {
assert(output);
PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is);
if (IsCollection(pbis)) {
LoadCollection(pbis, output);
return;
}
FontPtr font;
font.Attach(LoadSingleOTF(pbis));
if (font) {
output->push_back(font);
}
}
void FontFactory::LoadFonts(ByteVector* b, FontArray* output) {
WritableFontDataPtr wfd;
wfd.Attach(WritableFontData::CreateWritableFontData(b));
if (IsCollection(wfd)) {
LoadCollection(wfd, output);
return;
}
FontPtr font;
font.Attach(LoadSingleOTF(wfd));
if (font) {
output->push_back(font);
}
}
void FontFactory::LoadFontsForBuilding(InputStream* is,
FontBuilderArray* output) {
PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is);
if (IsCollection(pbis)) {
LoadCollectionForBuilding(pbis, output);
return;
}
FontBuilderPtr builder;
builder.Attach(LoadSingleOTFForBuilding(pbis));
if (builder) {
output->push_back(builder);
}
}
void FontFactory::LoadFontsForBuilding(ByteVector* b,
FontBuilderArray* output) {
WritableFontDataPtr wfd;
wfd.Attach(WritableFontData::CreateWritableFontData(b));
if (IsCollection(wfd)) {
LoadCollectionForBuilding(wfd, output);
return;
}
FontBuilderPtr builder;
builder.Attach(LoadSingleOTFForBuilding(wfd, 0));
if (builder) {
output->push_back(builder);
}
}
void FontFactory::SerializeFont(Font* font, OutputStream* os) {
font->Serialize(os, &table_ordering_);
}
void FontFactory::SetSerializationTableOrdering(
const IntegerList& table_ordering) {
table_ordering_ = table_ordering;
}
CALLER_ATTACH Font::Builder* FontFactory::NewFontBuilder() {
return Font::Builder::GetOTFBuilder(this);
}
CALLER_ATTACH Font* FontFactory::LoadSingleOTF(InputStream* is) {
FontBuilderPtr builder;
builder.Attach(LoadSingleOTFForBuilding(is));
return builder->Build();
}
CALLER_ATTACH Font* FontFactory::LoadSingleOTF(WritableFontData* wfd) {
FontBuilderPtr builder;
builder.Attach(LoadSingleOTFForBuilding(wfd, 0));
return builder->Build();
}
void FontFactory::LoadCollection(InputStream* is, FontArray* output) {
FontBuilderArray ba;
LoadCollectionForBuilding(is, &ba);
output->reserve(ba.size());
for (FontBuilderArray::iterator builder = ba.begin(), builders_end = ba.end();
builder != builders_end; ++builder) {
FontPtr font;
font.Attach((*builder)->Build());
output->push_back(font);
}
}
void FontFactory::LoadCollection(WritableFontData* wfd, FontArray* output) {
FontBuilderArray builders;
LoadCollectionForBuilding(wfd, &builders);
output->reserve(builders.size());
for (FontBuilderArray::iterator builder = builders.begin(),
builders_end = builders.end();
builder != builders_end; ++builder) {
FontPtr font;
font.Attach((*builder)->Build());
output->push_back(font);
}
}
CALLER_ATTACH
Font::Builder* FontFactory::LoadSingleOTFForBuilding(InputStream* is) {
// UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream
Font::Builder* builder = Font::Builder::GetOTFBuilder(this, is);
// UNIMPLEMENTED: setDigest
return builder;
}
CALLER_ATTACH Font::Builder*
FontFactory::LoadSingleOTFForBuilding(WritableFontData* wfd,
int32_t offset_to_offset_table) {
// UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream
Font::Builder* builder =
Font::Builder::GetOTFBuilder(this, wfd, offset_to_offset_table);
// UNIMPLEMENTED: setDigest
return builder;
}
void FontFactory::LoadCollectionForBuilding(InputStream* is,
FontBuilderArray* builders) {
assert(is);
assert(builders);
WritableFontDataPtr wfd;
wfd.Attach(WritableFontData::CreateWritableFontData(is->Available()));
wfd->CopyFrom(is);
LoadCollectionForBuilding(wfd, builders);
}
void FontFactory::LoadCollectionForBuilding(WritableFontData* wfd,
FontBuilderArray* builders) {
int32_t ttc_tag = wfd->ReadULongAsInt(Offset::kTTCTag);
UNREFERENCED_PARAMETER(ttc_tag);
int32_t version = wfd->ReadFixed(Offset::kVersion);
UNREFERENCED_PARAMETER(version);
int32_t num_fonts = wfd->ReadULongAsInt(Offset::kNumFonts);
builders->reserve(num_fonts);
int32_t offset_table_offset = Offset::kOffsetTable;
for (int32_t font_number = 0;
font_number < num_fonts;
font_number++, offset_table_offset += DataSize::kULONG) {
int32_t offset = wfd->ReadULongAsInt(offset_table_offset);
FontBuilderPtr builder;
builder.Attach(LoadSingleOTFForBuilding(wfd, offset));
builders->push_back(builder);
}
}
bool FontFactory::IsCollection(PushbackInputStream* pbis) {
ByteVector tag(4);
pbis->Read(&tag);
pbis->Unread(&tag);
return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]);
}
bool FontFactory::IsCollection(ReadableFontData* rfd) {
ByteVector tag(4);
rfd->ReadBytes(0, &(tag[0]), 0, tag.size());
return Tag::ttcf ==
GenerateTag(tag[0], tag[1], tag[2], tag[3]);
}
FontFactory::FontFactory()
: fingerprint_(false) {
}
} // namespace sfntly

View File

@ -1,140 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
#define SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
#include <vector>
#include "sfntly/port/refcount.h"
#include "sfntly/port/type.h"
#include "sfntly/font.h"
namespace sfntly {
class FontFactory : public RefCounted<FontFactory> {
public:
virtual ~FontFactory();
// Factory method for the construction of a font factory.
static CALLER_ATTACH FontFactory* GetInstance();
// Toggle whether fonts that are loaded are fingerprinted with a SHA-1 hash.
// If a font is fingerprinted then a SHA-1 hash is generated at load time and
// stored in the font. This is useful for uniquely identifying fonts. By
// default this is turned on.
// @param fingerprint whether fingerprinting should be turned on or off
// TODO(arthurhsu): IMPLEMENT: C++ port currently don't do any SHA-1
void FingerprintFont(bool fingerprint);
bool FingerprintFont();
// Load the font(s) from the input stream. The current settings on the factory
// are used during the loading process. One or more fonts are returned if the
// stream contains valid font data. Some font container formats may have more
// than one font and in this case multiple font objects will be returned. If
// the data in the stream cannot be parsed or is invalid an array of size zero
// will be returned.
void LoadFonts(InputStream* is, FontArray* output);
// ByteArray font loading
// Load the font(s) from the byte array. The current settings on the factory
// are used during the loading process. One or more fonts are returned if the
// stream contains valid font data. Some font container formats may have more
// than one font and in this case multiple font objects will be returned. If
// the data in the stream cannot be parsed or is invalid an array of size zero
// will be returned.
void LoadFonts(ByteVector* b, FontArray* output);
// Load the font(s) from the input stream into font builders. The current
// settings on the factory are used during the loading process. One or more
// font builders are returned if the stream contains valid font data. Some
// font container formats may have more than one font and in this case
// multiple font builder objects will be returned. If the data in the stream
// cannot be parsed or is invalid an array of size zero will be returned.
void LoadFontsForBuilding(InputStream* is, FontBuilderArray* output);
// Load the font(s) from the byte array into font builders. The current
// settings on the factory are used during the loading process. One or more
// font builders are returned if the stream contains valid font data. Some
// font container formats may have more than one font and in this case
// multiple font builder objects will be returned. If the data in the stream
// cannot be parsed or is invalid an array of size zero will be returned.
void LoadFontsForBuilding(ByteVector* b, FontBuilderArray* output);
// Font serialization
// Serialize the font to the output stream.
// NOTE: in this port we attempted not to implement I/O stream because dealing
// with cross-platform I/O stream itself is big enough as a project.
// Byte buffer it is.
void SerializeFont(Font* font, OutputStream* os);
// Set the table ordering to be used in serializing a font. The table ordering
// is an ordered list of table ids and tables will be serialized in the order
// given. Any tables whose id is not listed in the ordering will be placed in
// an unspecified order following those listed.
void SetSerializationTableOrdering(const IntegerList& table_ordering);
// Get an empty font builder for creating a new font from scratch.
CALLER_ATTACH Font::Builder* NewFontBuilder();
private:
// Offsets to specific elements in the underlying data. These offsets are
// relative to the start of the table or the start of sub-blocks within the
// table.
struct Offset {
enum {
// Offsets within the main directory.
kTTCTag = 0,
kVersion = 4,
kNumFonts = 8,
kOffsetTable = 12,
// TTC Version 2.0 extensions.
// Offsets from end of OffsetTable.
kulDsigTag = 0,
kulDsigLength = 4,
kulDsigOffset = 8
};
};
FontFactory();
CALLER_ATTACH Font* LoadSingleOTF(InputStream* is);
CALLER_ATTACH Font* LoadSingleOTF(WritableFontData* wfd);
void LoadCollection(InputStream* is, FontArray* output);
void LoadCollection(WritableFontData* wfd, FontArray* output);
CALLER_ATTACH Font::Builder* LoadSingleOTFForBuilding(InputStream* is);
CALLER_ATTACH Font::Builder*
LoadSingleOTFForBuilding(WritableFontData* wfd,
int32_t offset_to_offset_table);
void LoadCollectionForBuilding(InputStream* is, FontBuilderArray* builders);
void LoadCollectionForBuilding(WritableFontData* ba,
FontBuilderArray* builders);
static bool IsCollection(PushbackInputStream* pbis);
static bool IsCollection(ReadableFontData* wfd);
bool fingerprint_;
IntegerList table_ordering_;
};
typedef Ptr<FontFactory> FontFactoryPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_

View File

@ -1,41 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
#define SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
#include "sfntly/port/type.h"
namespace sfntly {
class Fixed1616 {
public:
static inline int32_t Integral(int32_t fixed) {
return (fixed >> 16);
}
static inline int32_t Fractional(int32_t fixed) {
return (fixed & 0xffff);
}
static inline int32_t Fixed(int32_t integral, int32_t fractional) {
return ((integral & 0xffff) << 16) | (fractional & 0xffff);
}
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_

View File

@ -1,49 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
#define SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
#include "sfntly/port/type.h"
namespace sfntly {
class FontMath {
public:
static int32_t Log2(int32_t a) {
int r = 0; // r will be lg(a)
while (a != 0) {
a >>= 1;
r++;
}
return r - 1;
}
// Calculates the amount of padding needed. The values provided need to be in
// the same units. So, if the size is given as the number of bytes then the
// alignment size must also be specified as byte size to align to.
// @param size the size of the data that may need padding
// @param alignmentSize the number of units to align to
// @return the number of units needing to be added for alignment
static int32_t PaddingRequired(int32_t size, int32_t alignment_size) {
int32_t padding = alignment_size - (size % alignment_size);
return padding == alignment_size ? 0 : padding;
}
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_

View File

@ -1,71 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
#if defined (WIN32)
#include <windows.h>
static inline size_t AtomicIncrement(size_t* address) {
#if defined (_WIN64)
return InterlockedIncrement64(reinterpret_cast<LONGLONG*>(address));
#else
return InterlockedIncrement(reinterpret_cast<LONG*>(address));
#endif
}
static inline size_t AtomicDecrement(size_t* address) {
#if defined (_WIN64)
return InterlockedDecrement64(reinterpret_cast<LONGLONG*>(address));
#else
return InterlockedDecrement(reinterpret_cast<LONG*>(address));
#endif
}
#elif defined (__APPLE__)
#include <libkern/OSAtomic.h>
static inline size_t AtomicIncrement(size_t* address) {
return OSAtomicIncrement32Barrier(reinterpret_cast<int32_t*>(address));
}
static inline size_t AtomicDecrement(size_t* address) {
return OSAtomicDecrement32Barrier(reinterpret_cast<int32_t*>(address));
}
// Originally we check __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4, however, there are
// issues that clang not carring over this definition. Therefore we boldly
// assume it's gcc or gcc-compatible here. Compilation shall still fail since
// the intrinsics used are GCC-specific.
#else
#include <stddef.h>
static inline size_t AtomicIncrement(size_t* address) {
return __sync_add_and_fetch(address, 1);
}
static inline size_t AtomicDecrement(size_t* address) {
return __sync_sub_and_fetch(address, 1);
}
#endif // WIN32
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_

View File

@ -1,28 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
#if !defined(SFNTLY_BIG_ENDIAN) && !defined(SFNTLY_LITTLE_ENDIAN)
#if defined (__ppc__) || defined (__ppc64__)
#define SFNTLY_BIG_ENDIAN
#else
#define SFNTLY_LITTLE_ENDIAN
#endif
#endif
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_

View File

@ -1,77 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
#include "sfntly/port/config.h"
#include "sfntly/port/type.h"
namespace sfntly {
static inline uint16_t EndianSwap16(uint16_t value) {
return (uint16_t)((value >> 8) | (value << 8));
}
static inline int32_t EndianSwap32(int32_t value) {
return (((value & 0x000000ff) << 24) |
((value & 0x0000ff00) << 8) |
((value & 0x00ff0000) >> 8) |
((value & 0xff000000) >> 24));
}
static inline uint64_t EndianSwap64(uint64_t value) {
return (((value & 0x00000000000000ffLL) << 56) |
((value & 0x000000000000ff00LL) << 40) |
((value & 0x0000000000ff0000LL) << 24) |
((value & 0x00000000ff000000LL) << 8) |
((value & 0x000000ff00000000LL) >> 8) |
((value & 0x0000ff0000000000LL) >> 24) |
((value & 0x00ff000000000000LL) >> 40) |
((value & 0xff00000000000000LL) >> 56));
}
#ifdef SFNTLY_LITTLE_ENDIAN
#define ToBE16(n) EndianSwap16(n)
#define ToBE32(n) EndianSwap32(n)
#define ToBE64(n) EndianSwap64(n)
#define ToLE16(n) (n)
#define ToLE32(n) (n)
#define ToLE64(n) (n)
#define FromBE16(n) EndianSwap16(n)
#define FromBE32(n) EndianSwap32(n)
#define FromBE64(n) EndianSwap64(n)
#define FromLE16(n) (n)
#define FromLE32(n) (n)
#define FromLE64(n) (n)
#else // SFNTLY_BIG_ENDIAN
#define ToBE16(n) (n)
#define ToBE32(n) (n)
#define ToBE64(n) (n)
#define ToLE16(n) EndianSwap16(n)
#define ToLE32(n) EndianSwap32(n)
#define ToLE64(n) EndianSwap64(n)
#define FromBE16(n) (n)
#define FromBE32(n) (n)
#define FromBE64(n) (n)
#define FromLE16(n) EndianSwap16(n)
#define FromLE32(n) EndianSwap32(n)
#define FromLE64(n) EndianSwap64(n)
#endif
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_

View File

@ -1,125 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Exceptions used in sfntly
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
#if !defined (SFNTLY_NO_EXCEPTION)
#include <exception>
#include <string>
#include <sstream>
namespace sfntly {
class Exception : public std::exception {
public:
Exception() : what_("Unknown exception") {}
explicit Exception(const char* message) throw() { SetMessage(message); }
virtual ~Exception() throw() {}
virtual const char* what() const throw() { return what_.c_str(); }
protected:
void SetMessage(const char* message) throw() {
try {
what_ = message;
} catch (...) {}
}
private:
std::string what_;
};
class IndexOutOfBoundException : public Exception {
public:
IndexOutOfBoundException() throw() : Exception("Index out of bound") {}
explicit IndexOutOfBoundException(const char* message) throw()
: Exception(message) {}
IndexOutOfBoundException(const char* message, int32_t index) throw() {
try {
std::ostringstream msg;
msg << message;
msg << ":";
msg << index;
SetMessage(msg.str().c_str());
} catch (...) {}
}
virtual ~IndexOutOfBoundException() throw() {}
};
class IOException : public Exception {
public:
IOException() throw() : Exception("I/O exception") {}
explicit IOException(const char* message) throw() : Exception(message) {}
virtual ~IOException() throw() {}
};
class ArithmeticException : public Exception {
public:
ArithmeticException() throw() : Exception("Arithmetic exception") {}
explicit ArithmeticException(const char* message) throw()
: Exception(message) {}
virtual ~ArithmeticException() throw() {}
};
class UnsupportedOperationException : public Exception {
public:
UnsupportedOperationException() throw() :
Exception("Operation not supported") {}
explicit UnsupportedOperationException(const char* message) throw()
: Exception(message) {}
virtual ~UnsupportedOperationException() throw() {}
};
class RuntimeException : public Exception {
public:
RuntimeException() throw() : Exception("Runtime exception") {}
explicit RuntimeException(const char* message) throw()
: Exception(message) {}
virtual ~RuntimeException() throw() {}
};
class NoSuchElementException : public Exception {
public:
NoSuchElementException() throw() : Exception("No such element") {}
explicit NoSuchElementException(const char* message) throw()
: Exception(message) {}
virtual ~NoSuchElementException() throw() {}
};
class IllegalArgumentException : public Exception {
public:
IllegalArgumentException() throw() : Exception("Illegal argument") {}
explicit IllegalArgumentException(const char* message) throw()
: Exception(message) {}
virtual ~IllegalArgumentException() throw() {}
};
class IllegalStateException : public Exception {
public:
IllegalStateException() throw() : Exception("Illegal state") {}
explicit IllegalStateException(const char* message) throw()
: Exception(message) {}
virtual ~IllegalStateException() throw() {}
};
} // namespace sfntly
#endif // #if !defined (SFNTLY_NO_EXCEPTION)
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_

View File

@ -1,169 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined (WIN32)
#include <windows.h>
#endif
#include "sfntly/port/file_input_stream.h"
#include "sfntly/port/exception_type.h"
namespace sfntly {
FileInputStream::FileInputStream()
: file_(NULL),
position_(0),
length_(0) {
}
FileInputStream::~FileInputStream() {
Close();
}
int32_t FileInputStream::Available() {
return length_ - position_;
}
void FileInputStream::Close() {
if (file_) {
fclose(file_);
length_ = 0;
position_ = 0;
file_ = NULL;
}
}
void FileInputStream::Mark(int32_t readlimit) {
// NOP
UNREFERENCED_PARAMETER(readlimit);
}
bool FileInputStream::MarkSupported() {
return false;
}
int32_t FileInputStream::Read() {
if (!file_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no opened file");
#endif
return 0;
}
if (feof(file_)) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("eof reached");
#endif
return 0;
}
byte_t value;
size_t length = fread(&value, 1, 1, file_);
position_ += length;
return value;
}
int32_t FileInputStream::Read(ByteVector* b) {
return Read(b, 0, b->size());
}
int32_t FileInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
assert(b);
if (!file_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no opened file");
#endif
return 0;
}
if (feof(file_)) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("eof reached");
#endif
return 0;
}
size_t read_count = std::min<size_t>(length_ - position_, length);
if (b->size() < (size_t)(offset + read_count)) {
b->resize((size_t)(offset + read_count));
}
int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_);
position_ += actual_read;
return actual_read;
}
void FileInputStream::Reset() {
// NOP
}
int64_t FileInputStream::Skip(int64_t n) {
if (!file_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no opened file");
#endif
return 0;
}
int64_t skip_count = 0;
if (n < 0) { // move backwards
skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
position_ -= (size_t)(0 - skip_count);
fseek(file_, position_, SEEK_SET);
} else {
skip_count = std::min<size_t>(length_ - position_, (size_t)n);
position_ += (size_t)skip_count;
fseek(file_, (size_t)skip_count, SEEK_CUR);
}
return skip_count;
}
void FileInputStream::Unread(ByteVector* b) {
Unread(b, 0, b->size());
}
void FileInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
assert(b);
assert(b->size() >= size_t(offset + length));
if (!file_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no opened file");
#endif
return;
}
size_t unread_count = std::min<size_t>(position_, length);
fseek(file_, position_ - unread_count, SEEK_SET);
position_ -= unread_count;
Read(b, offset, length);
fseek(file_, position_ - unread_count, SEEK_SET);
position_ -= unread_count;
}
bool FileInputStream::Open(const char* file_path) {
assert(file_path);
if (file_) {
Close();
}
#if defined (WIN32)
fopen_s(&file_, file_path, "rb");
#else
file_ = fopen(file_path, "rb");
#endif
if (file_ == NULL) {
return false;
}
fseek(file_, 0, SEEK_END);
length_ = ftell(file_);
fseek(file_, 0, SEEK_SET);
return true;
}
} // namespace sfntly

View File

@ -1,57 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
#include <stdio.h>
#include "sfntly/port/input_stream.h"
namespace sfntly {
class FileInputStream : public PushbackInputStream {
public:
FileInputStream();
virtual ~FileInputStream();
// InputStream methods
virtual int32_t Available();
virtual void Close();
virtual void Mark(int32_t readlimit);
virtual bool MarkSupported();
virtual int32_t Read();
virtual int32_t Read(ByteVector* b);
virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length);
virtual void Reset();
virtual int64_t Skip(int64_t n);
// PushbackInputStream methods
virtual void Unread(ByteVector* b);
virtual void Unread(ByteVector* b, int32_t offset, int32_t length);
// Own methods
virtual bool Open(const char* file_path);
private:
FILE* file_;
size_t position_;
size_t length_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_

View File

@ -1,49 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
#include "sfntly/port/type.h"
namespace sfntly {
// C++ equivalent to Java's OutputStream class
class InputStream {
public:
// Make gcc -Wnon-virtual-dtor happy.
virtual ~InputStream() {}
virtual int32_t Available() = 0;
virtual void Close() = 0;
virtual void Mark(int32_t readlimit) = 0;
virtual bool MarkSupported() = 0;
virtual int32_t Read() = 0;
virtual int32_t Read(ByteVector* b) = 0;
virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length) = 0;
virtual void Reset() = 0;
virtual int64_t Skip(int64_t n) = 0;
};
class PushbackInputStream : public InputStream {
public:
virtual void Unread(ByteVector* b) = 0;
virtual void Unread(ByteVector* b, int32_t offset, int32_t length) = 0;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_

View File

@ -1,94 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
#include "sfntly/port/refcount.h"
// Interface of Java iterator.
// This is a forward read-only iterator that represents java.util.Iterator<E>
namespace sfntly {
template <typename ReturnType, typename ContainerBase>
class Iterator : public virtual RefCount {
public:
virtual ~Iterator() {}
virtual ContainerBase* container_base() = 0;
protected:
Iterator() {}
NO_COPY_AND_ASSIGN(Iterator);
};
template <typename ReturnType, typename Container,
typename ContainerBase = Container>
class PODIterator : public Iterator<ReturnType, ContainerBase>,
public RefCounted< PODIterator<ReturnType, Container> > {
public:
explicit PODIterator(Container* container) : container_(container) {}
virtual ~PODIterator() {}
virtual ContainerBase* container_base() {
return static_cast<ContainerBase*>(container_);
}
virtual bool HasNext() = 0;
virtual ReturnType Next() = 0;
virtual void Remove() {
#if !defined (SFNTLY_NO_EXCEPTION)
// Default to no support.
throw UnsupportedOperationException();
#endif
}
protected:
Container* container() { return container_; }
private:
Container* container_; // Dumb pointer is used to avoid circular ref-counting
};
template <typename ReturnType, typename Container,
typename ContainerBase = Container>
class RefIterator : public Iterator<ReturnType, ContainerBase>,
public RefCounted< RefIterator<ReturnType, Container> > {
public:
explicit RefIterator(Container* container) : container_(container) {}
virtual ~RefIterator() {}
virtual ContainerBase* container_base() {
return static_cast<ContainerBase*>(container_);
}
virtual bool HasNext() = 0;
CALLER_ATTACH virtual ReturnType* Next() = 0;
virtual void Remove() {
#if !defined (SFNTLY_NO_EXCEPTION)
// Default to no support.
throw UnsupportedOperationException();
#endif
}
protected:
Container* container() { return container_; }
private:
Container* container_; // Dumb pointer is used to avoid circular ref-counting
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_

View File

@ -1,72 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/port/lock.h"
namespace sfntly {
#if defined (WIN32)
Lock::Lock() {
// The second parameter is the spin count, for short-held locks it avoid the
// contending thread from going to sleep which helps performance greatly.
::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000);
}
Lock::~Lock() {
::DeleteCriticalSection(&os_lock_);
}
bool Lock::Try() {
if (::TryEnterCriticalSection(&os_lock_) != FALSE) {
return true;
}
return false;
}
void Lock::Acquire() {
::EnterCriticalSection(&os_lock_);
}
void Lock::Unlock() {
::LeaveCriticalSection(&os_lock_);
}
#else // We assume it's pthread
Lock::Lock() {
pthread_mutex_init(&os_lock_, NULL);
}
Lock::~Lock() {
pthread_mutex_destroy(&os_lock_);
}
bool Lock::Try() {
return (pthread_mutex_trylock(&os_lock_) == 0);
}
void Lock::Acquire() {
pthread_mutex_lock(&os_lock_);
}
void Lock::Unlock() {
pthread_mutex_unlock(&os_lock_);
}
#endif
} // namespace sfntly

View File

@ -1,76 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
#if defined (WIN32)
#include <windows.h>
#else // Assume pthread.
#include <pthread.h>
#include <errno.h>
#endif
#include "sfntly/port/type.h"
namespace sfntly {
#if defined (WIN32)
typedef CRITICAL_SECTION OSLockType;
#else // Assume pthread.
typedef pthread_mutex_t OSLockType;
#endif
class Lock {
public:
Lock();
~Lock();
// If the lock is not held, take it and return true. If the lock is already
// held by something else, immediately return false.
bool Try();
// Take the lock, blocking until it is available if necessary.
void Acquire();
// Release the lock. This must only be called by the lock's holder: after
// a successful call to Try, or a call to Lock.
void Unlock();
private:
OSLockType os_lock_;
NO_COPY_AND_ASSIGN(Lock);
};
// A helper class that acquires the given Lock while the AutoLock is in scope.
class AutoLock {
public:
explicit AutoLock(Lock& lock) : lock_(lock) {
lock_.Acquire();
}
~AutoLock() {
lock_.Unlock();
}
private:
Lock& lock_;
NO_COPY_AND_ASSIGN(AutoLock);
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_

View File

@ -1,147 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined (WIN32)
#include <windows.h>
#endif
#include <string.h>
#include "sfntly/port/memory_input_stream.h"
#include "sfntly/port/exception_type.h"
namespace sfntly {
MemoryInputStream::MemoryInputStream()
: buffer_(NULL),
position_(0),
length_(0) {
}
MemoryInputStream::~MemoryInputStream() {
Close();
}
int32_t MemoryInputStream::Available() {
return length_ - position_;
}
void MemoryInputStream::Close() {
}
void MemoryInputStream::Mark(int32_t readlimit) {
// NOP
UNREFERENCED_PARAMETER(readlimit);
}
bool MemoryInputStream::MarkSupported() {
return false;
}
int32_t MemoryInputStream::Read() {
if (!buffer_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no memory attached");
#endif
return 0;
}
if (position_ >= length_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("eof reached");
#endif
return 0;
}
byte_t value = buffer_[position_++];
return value;
}
int32_t MemoryInputStream::Read(ByteVector* b) {
return Read(b, 0, b->size());
}
int32_t MemoryInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
assert(b);
if (!buffer_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no memory attached");
#endif
return 0;
}
if (position_ >= length_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("eof reached");
#endif
return 0;
}
size_t read_count = std::min<size_t>(length_ - position_, length);
if (b->size() < (size_t)(offset + read_count)) {
b->resize((size_t)(offset + read_count));
}
memcpy(&((*b)[offset]), buffer_ + position_, read_count);
position_ += read_count;
return read_count;
}
void MemoryInputStream::Reset() {
// NOP
}
int64_t MemoryInputStream::Skip(int64_t n) {
if (!buffer_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no memory attached");
#endif
return 0;
}
int64_t skip_count = 0;
if (n < 0) { // move backwards
skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
position_ -= (size_t)(0 - skip_count);
} else {
skip_count = std::min<size_t>(length_ - position_, (size_t)n);
position_ += (size_t)skip_count;
}
return skip_count;
}
void MemoryInputStream::Unread(ByteVector* b) {
Unread(b, 0, b->size());
}
void MemoryInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
assert(b);
assert(b->size() >= size_t(offset + length));
if (!buffer_) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IOException("no memory attached");
#endif
return;
}
size_t unread_count = std::min<size_t>(position_, length);
position_ -= unread_count;
Read(b, offset, length);
position_ -= unread_count;
}
bool MemoryInputStream::Attach(const byte_t* buffer, size_t length) {
assert(buffer);
assert(length);
buffer_ = buffer;
length_ = length;
return true;
}
} // namespace sfntly

View File

@ -1,57 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
#include <stdio.h>
#include "sfntly/port/input_stream.h"
namespace sfntly {
class MemoryInputStream : public PushbackInputStream {
public:
MemoryInputStream();
virtual ~MemoryInputStream();
// InputStream methods
virtual int32_t Available();
virtual void Close();
virtual void Mark(int32_t readlimit);
virtual bool MarkSupported();
virtual int32_t Read();
virtual int32_t Read(ByteVector* b);
virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length);
virtual void Reset();
virtual int64_t Skip(int64_t n);
// PushbackInputStream methods
virtual void Unread(ByteVector* b);
virtual void Unread(ByteVector* b, int32_t offset, int32_t length);
// Own methods
virtual bool Attach(const byte_t* buffer, size_t length);
private:
const byte_t* buffer_;
size_t position_;
size_t length_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_

View File

@ -1,72 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/port/memory_output_stream.h"
namespace sfntly {
MemoryOutputStream::MemoryOutputStream() {
}
MemoryOutputStream::~MemoryOutputStream() {
}
void MemoryOutputStream::Write(ByteVector* buffer) {
store_.insert(store_.end(), buffer->begin(), buffer->end());
}
void MemoryOutputStream::Write(ByteVector* buffer,
int32_t offset,
int32_t length) {
assert(buffer);
if (offset >= 0 && length > 0) {
store_.insert(store_.end(),
buffer->begin() + offset,
buffer->begin() + offset + length);
} else {
#if !defined(SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundException();
#endif
}
}
void MemoryOutputStream::Write(byte_t* buffer, int32_t offset, int32_t length) {
assert(buffer);
if (offset >= 0 && length > 0) {
store_.insert(store_.end(), buffer + offset, buffer + offset + length);
} else {
#if !defined(SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundException();
#endif
}
}
void MemoryOutputStream::Write(byte_t b) {
store_.push_back(b);
}
byte_t* MemoryOutputStream::Get() {
if (store_.empty()) {
return NULL;
}
return &(store_[0]);
}
size_t MemoryOutputStream::Size() {
return store_.size();
}
} // namespace sfntly

View File

@ -1,51 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
#include <cstddef>
#include <vector>
#include "sfntly/port/type.h"
#include "sfntly/port/output_stream.h"
namespace sfntly {
// OutputStream backed by STL vector
class MemoryOutputStream : public OutputStream {
public:
MemoryOutputStream();
virtual ~MemoryOutputStream();
virtual void Close() {} // no-op
virtual void Flush() {} // no-op
virtual void Write(ByteVector* buffer);
virtual void Write(ByteVector* buffer, int32_t offset, int32_t length);
virtual void Write(byte_t* buffer, int32_t offset, int32_t length);
virtual void Write(byte_t b);
byte_t* Get();
size_t Size();
private:
std::vector<byte_t> store_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_

View File

@ -1,46 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
#include "sfntly/port/type.h"
namespace sfntly {
// C++ equivalent to Java's OutputStream class
class OutputStream {
public:
// Make gcc -Wnon-virtual-dtor happy.
virtual ~OutputStream() {}
virtual void Close() = 0;
virtual void Flush() = 0;
virtual void Write(ByteVector* buffer) = 0;
virtual void Write(byte_t b) = 0;
// Note: C++ port offered both versions of Write() here. The first one is
// better because it does check bounds. The second one is there for
// performance concerns.
virtual void Write(ByteVector* buffer, int32_t offset, int32_t length) = 0;
// Note: Caller is responsible for the boundary of buffer.
virtual void Write(byte_t* buffer, int32_t offset, int32_t length) = 0;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_

View File

@ -1,277 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Object reference count and smart pointer implementation.
// Smart pointer usage in sfntly:
//
// sfntly carries a smart pointer implementation like COM. Ref-countable object
// type inherits from RefCounted<>, which have AddRef and Release just like
// IUnknown (but no QueryInterface). Use a Ptr<> based smart pointer to hold
// the object so that the object ref count is handled correctly.
//
// class Foo : public RefCounted<Foo> {
// public:
// static Foo* CreateInstance() {
// Ptr<Foo> obj = new Foo(); // ref count = 1
// return obj.Detach();
// }
// };
// typedef Ptr<Foo> FooPtr; // common short-hand notation
// FooPtr obj;
// obj.Attach(Foo::CreatedInstance()); // ref count = 1
// {
// FooPtr obj2 = obj; // ref count = 2
// } // ref count = 1, obj2 out of scope
// obj.Release(); // ref count = 0, object destroyed
// Notes on usage:
// 1. Virtual inherit from RefCount interface in base class if smart pointers
// are going to be defined.
// 2. All RefCounted objects must be instantiated on the heap. Allocating the
// object on stack will cause crash.
// 3. Be careful when you have complex inheritance. For example,
// class A : public RefCounted<A>;
// class B : public A, public RefCounted<B>;
// In this case the smart pointer is pretty dumb and don't count on it to
// nicely destroy your objects as designed. Try refactor your code like
// class I; // the common interface and implementations
// class A : public I, public RefCounted<A>; // A specific implementation
// class B : public I, public RefCounted<B>; // B specific implementation
// 4. Smart pointers here are very bad candidates for function parameters. Use
// dumb pointers in function parameter list.
// 5. When down_cast is performed on a dangling pointer due to bugs in code,
// VC++ will generate SEH which is not handled well in VC++ debugger. One
// can use WinDBG to run it and get the faulting stack.
// 6. Idioms for heap object as return value
// Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); }
// Foo* passthru() { FooPtr obj = createFoo(), return obj; }
// FooPtr end_scope_pointer;
// end_scope_pointer.Attach(passThrough);
// If you are not passing that object back, you are the end of scope.
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
#if !defined (NDEBUG)
#define ENABLE_OBJECT_COUNTER
// #define REF_COUNT_DEBUGGING
#endif
#if defined (REF_COUNT_DEBUGGING)
#include <stdio.h>
#include <typeinfo>
#endif
#include "sfntly/port/atomic.h"
#include "sfntly/port/type.h"
// Special tag for functions that requires caller to attach instead of using
// assignment operators.
#define CALLER_ATTACH
#if defined (REF_COUNT_DEBUGGING)
#define DEBUG_OUTPUT(a) \
fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \
typeid(this).name(), object_counter_, object_id_, ref_count_)
#else
#define DEBUG_OUTPUT(a)
#endif
#if defined (_MSC_VER)
// VC 2008/2010 incorrectly gives this warning for pure virtual functions
// in virtual inheritance. The only way to get around it is to disable it.
#pragma warning(disable:4250)
#endif
namespace sfntly {
class RefCount {
public:
// Make gcc -Wnon-virtual-dtor happy.
virtual ~RefCount() {}
virtual size_t AddRef() const = 0;
virtual size_t Release() const = 0;
};
template <typename T>
class NoAddRefRelease : public T {
public:
NoAddRefRelease();
~NoAddRefRelease();
private:
virtual size_t AddRef() const = 0;
virtual size_t Release() const = 0;
};
template <typename TDerived>
class RefCounted : virtual public RefCount {
public:
RefCounted() : ref_count_(0) {
#if defined (ENABLE_OBJECT_COUNTER)
object_id_ = AtomicIncrement(&next_id_);
AtomicIncrement(&object_counter_);
DEBUG_OUTPUT("C ");
#endif
}
RefCounted(const RefCounted<TDerived>&) : ref_count_(0) {}
virtual ~RefCounted() {
#if defined (ENABLE_OBJECT_COUNTER)
AtomicDecrement(&object_counter_);
DEBUG_OUTPUT("D ");
#endif
}
RefCounted<TDerived>& operator=(const RefCounted<TDerived>&) {
// Each object maintains own ref count, don't propagate.
return *this;
}
virtual size_t AddRef() const {
size_t new_count = AtomicIncrement(&ref_count_);
DEBUG_OUTPUT("A ");
return new_count;
}
virtual size_t Release() const {
size_t new_ref_count = AtomicDecrement(&ref_count_);
DEBUG_OUTPUT("R ");
if (new_ref_count == 0) {
// A C-style is used to cast away const-ness and to derived.
// lint does not like this but this is how it works.
delete (TDerived*)(this);
}
return new_ref_count;
}
mutable size_t ref_count_; // reference count of current object
#if defined (ENABLE_OBJECT_COUNTER)
static size_t object_counter_;
static size_t next_id_;
mutable size_t object_id_;
#endif
};
#if defined (ENABLE_OBJECT_COUNTER)
template <typename TDerived> size_t RefCounted<TDerived>::object_counter_ = 0;
template <typename TDerived> size_t RefCounted<TDerived>::next_id_ = 0;
#endif
// semi-smart pointer for RefCount derived objects, similar to CComPtr
template <typename T>
class Ptr {
public:
Ptr() : p_(NULL) {
}
// This constructor shall not be explicit.
// lint does not like this but this is how it works.
Ptr(T* pT) : p_(NULL) {
*this = pT;
}
Ptr(const Ptr<T>& p) : p_(NULL) {
*this = p;
}
~Ptr() {
Release();
}
T* operator=(T* pT) {
if (p_ == pT) {
return p_;
}
if (pT) {
RefCount* p = static_cast<RefCount*>(pT);
if (p == NULL) {
return NULL;
}
p->AddRef(); // always AddRef() before Release()
}
Release();
p_ = pT;
return p_;
}
T* operator=(const Ptr<T>& p) {
if (p_ == p.p_) {
return p_;
}
return operator=(p.p_);
}
operator T*&() {
return p_;
}
T& operator*() const {
return *p_; // It can throw!
}
NoAddRefRelease<T>* operator->() const {
return (NoAddRefRelease<T>*)p_; // It can throw!
}
bool operator!() const {
return (p_ == NULL);
}
bool operator<(const Ptr<T>& p) const {
return (p_ < p.p_);
}
bool operator!=(T* pT) const {
return !operator==(pT);
}
bool operator==(T* pT) const {
return (p_ == pT);
}
size_t Release() const {
size_t ref_count = 0;
if (p_) {
RefCount* p = static_cast<RefCount*>(p_);
if (p) {
ref_count = p->Release();
}
p_ = NULL;
}
return ref_count;
}
void Attach(T* pT) {
if (p_ != pT) {
Release();
p_ = pT;
}
}
T* Detach() {
T* pT = p_;
p_ = NULL;
return pT;
}
mutable T* p_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_

View File

@ -1,102 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
#define SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
#include <assert.h>
#if defined (_MSC_VER) && (_MSC_VER < 1600)
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned __int16 uint16_t;
typedef signed __int16 int16_t;
typedef unsigned __int32 uint32_t;
typedef signed __int32 int32_t;
typedef unsigned __int64 uint64_t;
typedef signed __int64 int64_t;
// Definitions to avoid ICU redefinition issue
#define U_HAVE_INT8_T 1
#define U_HAVE_UINT8_T 1
#define U_HAVE_INT16_T 1
#define U_HAVE_UINT16_T 1
#define U_HAVE_INT32_T 1
#define U_HAVE_UINT32_T 1
#define U_HAVE_INT64_T 1
#define U_HAVE_UINT64_T 1
#else
#include <stdint.h>
#endif
#include <cstddef>
#include <vector>
#include <set>
namespace sfntly {
typedef uint8_t byte_t;
typedef uint16_t word_t;
typedef uint32_t dword_t;
typedef uint64_t qword_t;
typedef std::vector<byte_t> ByteVector;
typedef std::vector<int32_t> IntegerList;
typedef std::set<int32_t> IntegerSet;
// A macro to disallow the copy constructor and operator= functions.
// This should be used in the private: declarations for a class.
#define NO_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
} // namespace sfntly
// Make google3 happy since it prohibits RTTI.
template<typename To, typename From>
inline To implicit_cast(From const &f) {
return f;
}
template<typename To, typename From> // use like this: down_cast<T*>(foo);
inline To down_cast(From* f) { // so we only accept pointers
// Ensures that To is a sub-type of From *. This test is here only
// for compile-time type checking, and has no overhead in an
// optimized build at run-time, as it will be optimized away
// completely.
#if defined (_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4127) // disable "conditional expression is constant"
#endif
if (false) {
implicit_cast<From*, To>(0);
}
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
// The following code is the only place for RTTI. It is done so to allow
// additional type checking when SFNTLY_TYPE_VERIFICATION is defined.
#if defined (SFNTLY_TYPE_VERIFICATION)
assert(f == NULL || dynamic_cast<To>(f) != NULL);
#endif
return static_cast<To>(f);
}
#if !defined(WIN32)
#define UNREFERENCED_PARAMETER(p) do { (void)p; } while (0)
#endif
#endif // SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_

View File

@ -1,171 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/big_glyph_metrics.h"
namespace sfntly {
/******************************************************************************
* BigGlyphMetrics class
******************************************************************************/
BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data)
: GlyphMetrics(data) {
}
BigGlyphMetrics::~BigGlyphMetrics() {
}
int32_t BigGlyphMetrics::Height() {
return data_->ReadByte(Offset::kHeight);
}
int32_t BigGlyphMetrics::Width() {
return data_->ReadByte(Offset::kWidth);
}
int32_t BigGlyphMetrics::HoriBearingX() {
return data_->ReadByte(Offset::kHoriBearingX);
}
int32_t BigGlyphMetrics::HoriBearingY() {
return data_->ReadByte(Offset::kHoriBearingY);
}
int32_t BigGlyphMetrics::HoriAdvance() {
return data_->ReadByte(Offset::kHoriAdvance);
}
int32_t BigGlyphMetrics::VertBearingX() {
return data_->ReadByte(Offset::kVertBearingX);
}
int32_t BigGlyphMetrics::VertBearingY() {
return data_->ReadByte(Offset::kVertBearingY);
}
int32_t BigGlyphMetrics::VertAdvance() {
return data_->ReadByte(Offset::kVertAdvance);
}
/******************************************************************************
* BigGlyphMetrics::Builder class
******************************************************************************/
BigGlyphMetrics::Builder::Builder(WritableFontData* data)
: GlyphMetrics::Builder(data) {
}
BigGlyphMetrics::Builder::Builder(ReadableFontData* data)
: GlyphMetrics::Builder(data) {
}
BigGlyphMetrics::Builder::~Builder() {
}
int32_t BigGlyphMetrics::Builder::Height() {
return InternalReadData()->ReadByte(Offset::kHeight);
}
void BigGlyphMetrics::Builder::SetHeight(byte_t height) {
InternalWriteData()->WriteByte(Offset::kHeight, height);
}
int32_t BigGlyphMetrics::Builder::Width() {
return InternalReadData()->ReadByte(Offset::kWidth);
}
void BigGlyphMetrics::Builder::SetWidth(byte_t width) {
InternalWriteData()->WriteByte(Offset::kWidth, width);
}
int32_t BigGlyphMetrics::Builder::HoriBearingX() {
return InternalReadData()->ReadByte(Offset::kHoriBearingX);
}
void BigGlyphMetrics::Builder::SetHoriBearingX(byte_t bearing) {
InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing);
}
int32_t BigGlyphMetrics::Builder::HoriBearingY() {
return InternalReadData()->ReadByte(Offset::kHoriBearingY);
}
void BigGlyphMetrics::Builder::SetHoriBearingY(byte_t bearing) {
InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing);
}
int32_t BigGlyphMetrics::Builder::HoriAdvance() {
return InternalReadData()->ReadByte(Offset::kHoriAdvance);
}
void BigGlyphMetrics::Builder::SetHoriAdvance(byte_t advance) {
InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance);
}
int32_t BigGlyphMetrics::Builder::VertBearingX() {
return InternalReadData()->ReadByte(Offset::kVertBearingX);
}
void BigGlyphMetrics::Builder::SetVertBearingX(byte_t bearing) {
InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing);
}
int32_t BigGlyphMetrics::Builder::VertBearingY() {
return InternalReadData()->ReadByte(Offset::kVertBearingY);
}
void BigGlyphMetrics::Builder::SetVertBearingY(byte_t bearing) {
InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing);
}
int32_t BigGlyphMetrics::Builder::VertAdvance() {
return InternalReadData()->ReadByte(Offset::kVertAdvance);
}
void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) {
InternalWriteData()->WriteByte(Offset::kVertAdvance, advance);
}
CALLER_ATTACH FontDataTable*
BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) {
BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
return output.Detach();
}
void BigGlyphMetrics::Builder::SubDataSet() {
// NOP.
}
int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() {
return 0;
}
bool BigGlyphMetrics::Builder::SubReadyToSerialize() {
return false;
}
int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) {
return Data()->CopyTo(new_data);
}
// static
CALLER_ATTACH
BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() {
WritableFontDataPtr data;
data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength));
BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data);
return output.Detach();
}
} // namespace sfntly

View File

@ -1,96 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
#include "sfntly/table/bitmap/glyph_metrics.h"
namespace sfntly {
class BigGlyphMetrics : public GlyphMetrics,
public RefCounted<BigGlyphMetrics> {
public:
struct Offset {
enum {
kMetricsLength = 8,
kHeight = 0,
kWidth = 1,
kHoriBearingX = 2,
kHoriBearingY = 3,
kHoriAdvance = 4,
kVertBearingX = 5,
kVertBearingY = 6,
kVertAdvance = 7,
};
};
class Builder : public GlyphMetrics::Builder,
public RefCounted<Builder> {
public:
// Constructor scope altered to public because C++ does not allow base
// class to instantiate derived class with protected constructors.
explicit Builder(WritableFontData* data);
explicit Builder(ReadableFontData* data);
virtual ~Builder();
int32_t Height();
void SetHeight(byte_t height);
int32_t Width();
void SetWidth(byte_t width);
int32_t HoriBearingX();
void SetHoriBearingX(byte_t bearing);
int32_t HoriBearingY();
void SetHoriBearingY(byte_t bearing);
int32_t HoriAdvance();
void SetHoriAdvance(byte_t advance);
int32_t VertBearingX();
void SetVertBearingX(byte_t bearing);
int32_t VertBearingY();
void SetVertBearingY(byte_t bearing);
int32_t VertAdvance();
void SetVertAdvance(byte_t advance);
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
virtual void SubDataSet();
virtual int32_t SubDataSizeToSerialize();
virtual bool SubReadyToSerialize();
virtual int32_t SubSerialize(WritableFontData* new_data);
// Static instantiation function.
static CALLER_ATTACH Builder* CreateBuilder();
};
explicit BigGlyphMetrics(ReadableFontData* data);
virtual ~BigGlyphMetrics();
int32_t Height();
int32_t Width();
int32_t HoriBearingX();
int32_t HoriBearingY();
int32_t HoriAdvance();
int32_t VertBearingX();
int32_t VertBearingY();
int32_t VertAdvance();
};
typedef Ptr<BigGlyphMetrics> BigGlyphMetricsPtr;
typedef Ptr<BigGlyphMetrics::Builder> BigGlyphMetricsBuilderPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_

View File

@ -1,101 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 = the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/bitmap_glyph.h"
#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
namespace sfntly {
/******************************************************************************
* BitmapGlyph class
******************************************************************************/
BitmapGlyph::~BitmapGlyph() {
}
CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data,
int32_t format) {
BitmapGlyphPtr glyph;
BitmapGlyphBuilderPtr builder;
builder.Attach(Builder::CreateGlyphBuilder(data, format));
if (builder) {
glyph.Attach(down_cast<BitmapGlyph*>(builder->Build()));
}
return glyph;
}
BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format)
: SubTable(data), format_(format) {
}
/******************************************************************************
* BitmapGlyph::Builder class
******************************************************************************/
BitmapGlyph::Builder::~Builder() {
}
CALLER_ATTACH BitmapGlyph::Builder*
BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data,
int32_t format) {
BitmapGlyphBuilderPtr builder;
switch (format) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
builder = new SimpleBitmapGlyph::Builder(data, format);
break;
case 8:
case 9:
builder = new CompositeBitmapGlyph::Builder(data, format);
break;
}
return builder.Detach();
}
BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
: SubTable::Builder(data), format_(format) {
}
BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
: SubTable::Builder(data), format_(format) {
}
CALLER_ATTACH
FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
UNREFERENCED_PARAMETER(data);
return NULL;
}
void BitmapGlyph::Builder::SubDataSet() {
// NOP
}
int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() {
return InternalReadData()->Length();
}
bool BitmapGlyph::Builder::SubReadyToSerialize() {
return true;
}
int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) {
return InternalReadData()->CopyTo(new_data);
}
} // namespace sfntly

View File

@ -1,119 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 = the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
#include <vector>
#include <map>
#include "sfntly/table/subtable.h"
namespace sfntly {
class BitmapGlyph : public SubTable {
public:
struct Offset {
enum {
// header
kVersion = 0,
kSmallGlyphMetricsLength = 5,
kBigGlyphMetricsLength = 8,
// format 1
kGlyphFormat1_imageData = kSmallGlyphMetricsLength,
// format 2
kGlyphFormat2_imageData = kSmallGlyphMetricsLength,
// format 3
// format 4
// format 5
kGlyphFormat5_imageData = 0,
// format 6
kGlyphFormat6_imageData = kBigGlyphMetricsLength,
// format 7
kGlyphFormat7_imageData = kBigGlyphMetricsLength,
// format 8
kGlyphFormat8_numComponents = kSmallGlyphMetricsLength + 1,
kGlyphFormat8_componentArray = kGlyphFormat8_numComponents +
DataSize::kUSHORT,
// format 9
kGlyphFormat9_numComponents = kBigGlyphMetricsLength,
kGlyphFormat9_componentArray = kGlyphFormat9_numComponents +
DataSize::kUSHORT,
// ebdtComponent
kEbdtComponentLength = DataSize::kUSHORT + 2 * DataSize::kCHAR,
kEbdtComponent_glyphCode = 0,
kEbdtComponent_xOffset = 2,
kEbdtComponent_yOffset = 3,
};
};
// TODO(stuartg): builder is not functional at all
// - need to add subclasses for each type of bitmap glyph
class Builder : public SubTable::Builder {
public:
virtual ~Builder();
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
virtual void SubDataSet();
virtual int32_t SubDataSizeToSerialize();
virtual bool SubReadyToSerialize();
virtual int32_t SubSerialize(WritableFontData* new_data);
int32_t format() { return format_; }
static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data,
int32_t format);
protected:
Builder(WritableFontData* data, int32_t format);
Builder(ReadableFontData* data, int32_t format);
private:
int32_t format_;
};
virtual ~BitmapGlyph();
static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data,
int32_t format);
int32_t format() { return format_; }
// UNIMPLEMENTED: toString()
protected:
BitmapGlyph(ReadableFontData* data, int32_t format);
private:
int32_t format_;
};
typedef Ptr<BitmapGlyph> BitmapGlyphPtr;
typedef Ptr<BitmapGlyph::Builder> BitmapGlyphBuilderPtr;
typedef std::map<int32_t, BitmapGlyphBuilderPtr> BitmapGlyphBuilderMap;
typedef std::vector<BitmapGlyphBuilderMap> BitmapGlyphBuilderList;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_

View File

@ -1,68 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/bitmap_glyph_info.h"
namespace sfntly {
BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id,
int32_t block_offset,
int32_t start_offset,
int32_t length,
int32_t format)
: glyph_id_(glyph_id),
relative_(true),
block_offset_(block_offset),
start_offset_(start_offset),
length_(length),
format_(format) {
}
BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id,
int32_t start_offset,
int32_t length,
int32_t format)
: glyph_id_(glyph_id),
relative_(false),
block_offset_(0),
start_offset_(start_offset),
length_(length),
format_(format) {
}
bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const {
return (format_ == rhs.format_ &&
glyph_id_ == rhs.glyph_id_ &&
length_ == rhs.length_ &&
offset() == rhs.offset());
}
bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) {
if (rhs == NULL) {
return this == NULL;
}
return (format_ == rhs->format() &&
glyph_id_ == rhs->glyph_id() &&
length_ == rhs->length() &&
offset() == rhs->offset());
}
bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs,
BitmapGlyphInfo* rhs) {
return lhs->start_offset() > rhs->start_offset();
}
} // namespace sfntly

View File

@ -1,85 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
#include <vector>
#include <map>
#include "sfntly/table/subtable.h"
namespace sfntly {
// An immutable class holding bitmap glyph information.
class BitmapGlyphInfo : public RefCounted<BitmapGlyphInfo> {
public:
// Constructor for a relative located glyph. The glyph's position in the EBDT
// table is a combination of it's block offset and it's own start offset.
// @param glyphId the glyph id
// @param blockOffset the offset of the block to which the glyph belongs
// @param startOffset the offset of the glyph within the block
// @param length the byte length
// @param format the glyph image format
BitmapGlyphInfo(int32_t glyph_id,
int32_t block_offset,
int32_t start_offset,
int32_t length,
int32_t format);
// Constructor for an absolute located glyph. The glyph's position in the EBDT
// table is only given by it's own start offset.
// @param glyphId the glyph id
// @param startOffset the offset of the glyph within the block
// @param length the byte length
// @param format the glyph image format
BitmapGlyphInfo(int32_t glyph_id,
int32_t start_offset,
int32_t length,
int32_t format);
int32_t glyph_id() const { return glyph_id_; }
bool relative() const { return relative_; }
int32_t block_offset() const { return block_offset_; }
int32_t offset() const { return block_offset() + start_offset(); }
int32_t start_offset() const { return start_offset_; }
int32_t length() const { return length_; }
int32_t format() const { return format_; }
// UNIMPLEMENTED: hashCode()
bool operator==(const BitmapGlyphInfo& rhs) const;
bool operator==(BitmapGlyphInfo* rhs);
private:
int32_t glyph_id_;
bool relative_;
int32_t block_offset_;
int32_t start_offset_;
int32_t length_;
int32_t format_;
};
typedef Ptr<BitmapGlyphInfo> BitmapGlyphInfoPtr;
typedef std::map<int32_t, BitmapGlyphInfoPtr> BitmapGlyphInfoMap;
typedef std::vector<BitmapGlyphInfoMap> BitmapLocaList;
class StartOffsetComparator {
public:
bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs);
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_

View File

@ -1,604 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 = the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/bitmap_size_table.h"
#include <stdio.h>
#include <stdlib.h>
#include "sfntly/math/font_math.h"
#include "sfntly/table/bitmap/eblc_table.h"
#include "sfntly/table/bitmap/index_sub_table_format1.h"
#include "sfntly/table/bitmap/index_sub_table_format2.h"
#include "sfntly/table/bitmap/index_sub_table_format3.h"
#include "sfntly/table/bitmap/index_sub_table_format4.h"
#include "sfntly/table/bitmap/index_sub_table_format5.h"
namespace sfntly {
/******************************************************************************
* BitmapSizeTable class
******************************************************************************/
BitmapSizeTable::~BitmapSizeTable() {
}
int32_t BitmapSizeTable::IndexSubTableArrayOffset() {
return data_->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
}
int32_t BitmapSizeTable::IndexTableSize() {
return data_->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexTableSize);
}
int32_t BitmapSizeTable::NumberOfIndexSubTables() {
return NumberOfIndexSubTables(data_, 0);
}
int32_t BitmapSizeTable::ColorRef() {
return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef);
}
int32_t BitmapSizeTable::StartGlyphIndex() {
return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
}
int32_t BitmapSizeTable::EndGlyphIndex() {
return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
}
int32_t BitmapSizeTable::PpemX() {
return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX);
}
int32_t BitmapSizeTable::PpemY() {
return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY);
}
int32_t BitmapSizeTable::BitDepth() {
return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth);
}
int32_t BitmapSizeTable::FlagsAsInt() {
return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags);
}
IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) {
IndexSubTableList* subtable_list = GetIndexSubTableList();
if (index >= 0 && (size_t)index < subtable_list->size()) {
return (*subtable_list)[index];
}
return NULL;
}
int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) {
IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphOffset(glyph_id);
}
int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) {
IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphLength(glyph_id);
}
CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) {
IndexSubTable* sub_table = SearchIndexSubTables(glyph_id);
if (sub_table == NULL) {
return NULL;
}
return sub_table->GlyphInfo(glyph_id);
}
int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) {
IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->image_format();
}
BitmapSizeTable::BitmapSizeTable(ReadableFontData* data,
ReadableFontData* master_data)
: SubTable(data, master_data) {
}
// static
int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data,
int32_t table_offset) {
return data->ReadULongAsInt(table_offset +
EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables);
}
IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) {
// would be faster to binary search but too many size tables don't have
// sorted subtables
#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
return BinarySearchIndexSubTables(glyph_id);
#else
return LinearSearchIndexSubTables(glyph_id);
#endif
}
IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) {
IndexSubTableList* subtable_list = GetIndexSubTableList();
for (IndexSubTableList::iterator b = subtable_list->begin(),
e = subtable_list->end(); b != e; b++) {
if ((*b)->first_glyph_index() <= glyph_id &&
(*b)->last_glyph_index() >= glyph_id) {
return *b;
}
}
return NULL;
}
IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) {
IndexSubTableList* subtable_list = GetIndexSubTableList();
int32_t index = 0;
int32_t bottom = 0;
int32_t top = subtable_list->size();
while (top != bottom) {
index = (top + bottom) / 2;
IndexSubTable* subtable = (*subtable_list)[index];
if (glyph_id < subtable->first_glyph_index()) {
// Location beow current location
top = index;
} else {
if (glyph_id <= subtable->last_glyph_index()) {
return subtable;
} else {
bottom = index + 1;
}
}
}
return NULL;
}
CALLER_ATTACH
IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) {
return IndexSubTable::CreateIndexSubTable(master_read_data(),
IndexSubTableArrayOffset(),
index);
}
IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() {
AutoLock lock(index_subtables_lock_);
if (index_subtables_.empty()) {
for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) {
IndexSubTablePtr table;
table.Attach(CreateIndexSubTable(i));
index_subtables_.push_back(table);
}
}
return &index_subtables_;
}
/******************************************************************************
* BitmapSizeTable::Builder class
******************************************************************************/
BitmapSizeTable::Builder::~Builder() {
}
CALLER_ATTACH
FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) {
BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data());
return output.Detach();
}
void BitmapSizeTable::Builder::SubDataSet() {
Revert();
}
int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() {
IndexSubTableBuilderList* builders = IndexSubTableBuilders();
if (builders->empty()) {
return 0;
}
int32_t size = EblcTable::Offset::kBitmapSizeTableLength;
bool variable = false;
for (IndexSubTableBuilderList::iterator b = builders->begin(),
e = builders->end(); b != e; b++) {
size += EblcTable::Offset::kIndexSubTableEntryLength;
int32_t sub_table_size = (*b)->SubDataSizeToSerialize();
int32_t padding = FontMath::PaddingRequired(abs(sub_table_size),
DataSize::kULONG);
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "subtable size=%d\n", sub_table_size);
#endif
variable = (sub_table_size > 0) ? variable : true;
size += abs(sub_table_size) + padding;
}
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size);
#endif
return variable ? -size : size;
}
bool BitmapSizeTable::Builder::SubReadyToSerialize() {
if (IndexSubTableBuilders()->empty()) {
return false;
}
return true;
}
int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) {
SetNumberOfIndexSubTables(IndexSubTableBuilders()->size());
int32_t size = InternalReadData()->CopyTo(new_data);
return size;
}
CALLER_ATTACH BitmapSizeTable::Builder*
BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data,
ReadableFontData* master_data) {
BitmapSizeTableBuilderPtr output =
new BitmapSizeTable::Builder(data, master_data);
return output.Detach();
}
CALLER_ATTACH BitmapSizeTable::Builder*
BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data,
ReadableFontData* master_data) {
BitmapSizeTableBuilderPtr output =
new BitmapSizeTable::Builder(data, master_data);
return output.Detach();
}
int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() {
return InternalReadData()->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
}
void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) {
InternalWriteData()->WriteULong(
EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset);
}
int32_t BitmapSizeTable::Builder::IndexTableSize() {
return InternalReadData()->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexTableSize);
}
void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) {
InternalWriteData()->WriteULong(
EblcTable::Offset::kBitmapSizeTable_indexTableSize, size);
}
int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() {
return GetIndexSubTableBuilders()->size();
}
int32_t BitmapSizeTable::Builder::ColorRef() {
return InternalReadData()->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_colorRef);
}
int32_t BitmapSizeTable::Builder::StartGlyphIndex() {
return InternalReadData()->ReadUShort(
EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
}
int32_t BitmapSizeTable::Builder::EndGlyphIndex() {
return InternalReadData()->ReadUShort(
EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
}
int32_t BitmapSizeTable::Builder::PpemX() {
return InternalReadData()->ReadByte(
EblcTable::Offset::kBitmapSizeTable_ppemX);
}
int32_t BitmapSizeTable::Builder::PpemY() {
return InternalReadData()->ReadByte(
EblcTable::Offset::kBitmapSizeTable_ppemY);
}
int32_t BitmapSizeTable::Builder::BitDepth() {
return InternalReadData()->ReadByte(
EblcTable::Offset::kBitmapSizeTable_bitDepth);
}
int32_t BitmapSizeTable::Builder::FlagsAsInt() {
return InternalReadData()->ReadChar(
EblcTable::Offset::kBitmapSizeTable_flags);
}
IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder(
int32_t index) {
IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders();
return sub_table_list->at(index);
}
CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo(
int32_t glyph_id) {
IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id);
if (sub_table == NULL) {
return NULL;
}
return sub_table->GlyphInfo(glyph_id);
}
int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) {
IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphOffset(glyph_id);
}
int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) {
IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphLength(glyph_id);
}
int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) {
IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->image_format();
}
IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() {
return GetIndexSubTableBuilders();
}
CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator*
BitmapSizeTable::Builder::GetIterator() {
Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> output =
new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this);
return output.Detach();
}
void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) {
assert(output);
Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> it;
it.Attach(GetIterator());
while (it->HasNext()) {
BitmapGlyphInfoPtr info;
info.Attach(it->Next());
(*output)[info->glyph_id()] = info;
}
}
void BitmapSizeTable::Builder::Revert() {
index_sub_tables_.clear();
set_model_changed(false);
}
BitmapSizeTable::Builder::Builder(WritableFontData* data,
ReadableFontData* master_data)
: SubTable::Builder(data, master_data) {
}
BitmapSizeTable::Builder::Builder(ReadableFontData* data,
ReadableFontData* master_data)
: SubTable::Builder(data, master_data) {
}
void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) {
InternalWriteData()->WriteULong(
EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count);
}
IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables(
int32_t glyph_id) {
// would be faster to binary search but too many size tables don't have
// sorted subtables
#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
return BinarySearchIndexSubTables(glyph_id);
#else
return LinearSearchIndexSubTables(glyph_id);
#endif
}
IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables(
int32_t glyph_id) {
IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
for (IndexSubTableBuilderList::iterator b = subtable_list->begin(),
e = subtable_list->end();
b != e; b++) {
if ((*b)->first_glyph_index() <= glyph_id &&
(*b)->last_glyph_index() >= glyph_id) {
return *b;
}
}
return NULL;
}
IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables(
int32_t glyph_id) {
IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
int32_t index = 0;
int32_t bottom = 0;
int32_t top = subtable_list->size();
while (top != bottom) {
index = (top + bottom) / 2;
IndexSubTable::Builder* subtable = subtable_list->at(index);
if (glyph_id < subtable->first_glyph_index()) {
// Location beow current location
top = index;
} else {
if (glyph_id <= subtable->last_glyph_index()) {
return subtable;
} else {
bottom = index + 1;
}
}
}
return NULL;
}
IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() {
if (index_sub_tables_.empty()) {
Initialize(InternalReadData());
set_model_changed();
}
return &index_sub_tables_;
}
void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) {
index_sub_tables_.clear();
if (data) {
int32_t number_of_index_subtables =
BitmapSizeTable::NumberOfIndexSubTables(data, 0);
index_sub_tables_.resize(number_of_index_subtables);
for (int32_t i = 0; i < number_of_index_subtables; ++i) {
index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i));
}
}
}
CALLER_ATTACH IndexSubTable::Builder*
BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) {
return IndexSubTable::Builder::CreateBuilder(master_read_data(),
IndexSubTableArrayOffset(),
index);
}
/******************************************************************************
* BitmapSizeTable::Builder::BitmapGlyphInfoIterator class
******************************************************************************/
BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
BitmapSizeTable::Builder* container)
: RefIterator<BitmapGlyphInfo, BitmapSizeTable::Builder>(container) {
sub_table_iter_ = container->IndexSubTableBuilders()->begin();
sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
}
bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() {
if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) {
return true;
}
while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) {
sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
if (HasNext(sub_table_glyph_info_iter_)) {
return true;
}
}
return false;
}
CALLER_ATTACH
BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() {
if (!HasNext()) {
// Note: In C++, we do not throw exception when there's no element.
return NULL;
}
return Next(sub_table_glyph_info_iter_);
}
bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext(
BitmapGlyphInfoIter* iterator_base) {
if (iterator_base) {
switch (iterator_base->container_base()->index_format()) {
case 1: {
IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 2: {
IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 3: {
IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 4: {
IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 5: {
IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
default:
break;
}
}
return false;
}
CALLER_ATTACH
BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next(
BitmapGlyphInfoIter* iterator_base) {
if (iterator_base) {
switch (iterator_base->container_base()->index_format()) {
case 1: {
IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 2: {
IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 3: {
IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 4: {
IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 5: {
IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
default:
break;
}
}
return NULL;
}
} // namespace sfntly

View File

@ -1,173 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 = the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
#include "sfntly/port/lock.h"
#include "sfntly/table/bitmap/bitmap_glyph_info.h"
#include "sfntly/table/bitmap/index_sub_table.h"
namespace sfntly {
// Binary search would be faster but many fonts have index subtables that
// aren't sorted.
// Note: preprocessor define is used to avoid const expression warnings in C++
// code.
#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0
class BitmapSizeTable : public SubTable,
public RefCounted<BitmapSizeTable> {
public:
class Builder : public SubTable::Builder,
public RefCounted<Builder> {
public:
class BitmapGlyphInfoIterator :
public RefIterator<BitmapGlyphInfo, Builder> {
public:
explicit BitmapGlyphInfoIterator(Builder* container);
virtual ~BitmapGlyphInfoIterator() {}
virtual bool HasNext();
CALLER_ATTACH virtual BitmapGlyphInfo* Next();
private:
bool HasNext(BitmapGlyphInfoIter* iterator_base);
CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base);
IndexSubTableBuilderList::iterator sub_table_iter_;
BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_;
};
virtual ~Builder();
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
virtual void SubDataSet();
virtual int32_t SubDataSizeToSerialize();
virtual bool SubReadyToSerialize();
virtual int32_t SubSerialize(WritableFontData* new_data);
static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
ReadableFontData* master_data);
static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
ReadableFontData* master_data);
// Gets the subtable array offset as set in the original table as read from
// the font file. This value cannot be explicitly set and will be generated
// during table building.
// @return the subtable array offset
int32_t IndexSubTableArrayOffset();
// Sets the subtable array offset. This is used only during the building
// process when the objects are being serialized.
// @param offset the offset to the index subtable array
void SetIndexSubTableArrayOffset(int32_t offset);
// Gets the subtable array size as set in the original table as read from
// the font file. This value cannot be explicitly set and will be generated
// during table building.
// @return the subtable array size
int32_t IndexTableSize();
// Sets the subtable size. This is used only during the building process
// when the objects are being serialized.
// @param size the offset to the index subtable array
void SetIndexTableSize(int32_t size);
int32_t NumberOfIndexSubTables();
int32_t ColorRef();
// TODO(stuartg): SBitLineMetrics hori();
// TODO(stuartg): SBitLineMetrics vert();
int32_t StartGlyphIndex();
int32_t EndGlyphIndex();
int32_t PpemX();
int32_t PpemY();
int32_t BitDepth();
int32_t FlagsAsInt();
IndexSubTable::Builder* IndexSubTableBuilder(int32_t index);
CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
int32_t GlyphOffset(int32_t glyph_id);
int32_t GlyphLength(int32_t glyph_id);
int32_t GlyphFormat(int32_t glyph_id);
IndexSubTableBuilderList* IndexSubTableBuilders();
// Note: renamed from iterator(), type is the derived type.
CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator();
void GenerateLocaMap(BitmapGlyphInfoMap* output);
protected:
void Revert();
private:
Builder(WritableFontData* data, ReadableFontData* master_data);
Builder(ReadableFontData* data, ReadableFontData* master_data);
void SetNumberOfIndexSubTables(int32_t count);
IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id);
IndexSubTable::Builder* LinearSearchIndexSubTables(int32_t glyph_id);
IndexSubTable::Builder* BinarySearchIndexSubTables(int32_t glyph_id);
IndexSubTableBuilderList* GetIndexSubTableBuilders();
void Initialize(ReadableFontData* data);
CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder(
int32_t index);
IndexSubTableBuilderList index_sub_tables_;
};
virtual ~BitmapSizeTable();
int32_t IndexSubTableArrayOffset();
int32_t IndexTableSize();
int32_t NumberOfIndexSubTables();
int32_t ColorRef();
// TODO(stuartg): SBitLineMetrics hori();
// TODO(stuartg): SBitLineMetrics vert();
int32_t StartGlyphIndex();
int32_t EndGlyphIndex();
int32_t PpemX();
int32_t PpemY();
int32_t BitDepth();
int32_t FlagsAsInt();
// Note: renamed from indexSubTable()
IndexSubTable* GetIndexSubTable(int32_t index);
int32_t GlyphOffset(int32_t glyph_id);
int32_t GlyphLength(int32_t glyph_id);
CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
int32_t GlyphFormat(int32_t glyph_id);
protected:
BitmapSizeTable(ReadableFontData* data,
ReadableFontData* master_data);
private:
static int32_t NumberOfIndexSubTables(ReadableFontData* data,
int32_t table_offset);
IndexSubTable* SearchIndexSubTables(int32_t glyph_id);
IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id);
IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id);
CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index);
IndexSubTableList* GetIndexSubTableList();
Lock index_subtables_lock_;
IndexSubTableList index_subtables_;
};
typedef Ptr<BitmapSizeTable> BitmapSizeTablePtr;
typedef std::vector<BitmapSizeTablePtr> BitmapSizeTableList;
typedef Ptr<BitmapSizeTable::Builder> BitmapSizeTableBuilderPtr;
typedef std::vector<BitmapSizeTableBuilderPtr> BitmapSizeTableBuilderList;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_

View File

@ -1,109 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 = the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
namespace sfntly {
/******************************************************************************
* CompositeBitmapGlyph class
******************************************************************************/
CompositeBitmapGlyph::CompositeBitmapGlyph(ReadableFontData* data,
int32_t format)
: BitmapGlyph(data, format) {
Initialize(format);
}
CompositeBitmapGlyph::~CompositeBitmapGlyph() {
}
int32_t CompositeBitmapGlyph::NumComponents() {
return data_->ReadUShort(num_components_offset_);
}
CompositeBitmapGlyph::Component CompositeBitmapGlyph::GetComponent(
int32_t component_num) const {
int32_t component_offset = component_array_offset_ +
component_num * Offset::kEbdtComponentLength;
return CompositeBitmapGlyph::Component(
data_->ReadUShort(component_offset + Offset::kEbdtComponent_glyphCode),
data_->ReadChar(component_offset + Offset::kEbdtComponent_xOffset),
data_->ReadChar(component_offset + Offset::kEbdtComponent_yOffset));
}
void CompositeBitmapGlyph::Initialize(int32_t format) {
if (format == 8) {
num_components_offset_ = Offset::kGlyphFormat8_numComponents;
component_array_offset_ = Offset::kGlyphFormat8_componentArray;
} else if (format == 9) {
num_components_offset_ = Offset::kGlyphFormat9_numComponents;
component_array_offset_ = Offset::kGlyphFormat9_componentArray;
} else {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IllegalStateException("Attempt to create a Composite Bitmap Glyph "
"with a non-composite format.");
#endif
}
}
/******************************************************************************
* CompositeBitmapGlyph::Component class
******************************************************************************/
CompositeBitmapGlyph::Component::Component(const Component& rhs)
: glyph_code_(rhs.glyph_code_),
x_offset_(rhs.x_offset_),
y_offset_(rhs.y_offset_) {
}
bool CompositeBitmapGlyph::Component::operator==(
const CompositeBitmapGlyph::Component& rhs) {
return glyph_code_ == rhs.glyph_code_;
}
CompositeBitmapGlyph::Component& CompositeBitmapGlyph::Component::operator=(
const CompositeBitmapGlyph::Component& rhs) {
glyph_code_ = rhs.glyph_code_;
x_offset_ = rhs.x_offset_;
y_offset_ = rhs.y_offset_;
return *this;
}
CompositeBitmapGlyph::Component::Component(int32_t glyph_code,
int32_t x_offset,
int32_t y_offset)
: glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) {
}
/******************************************************************************
* CompositeBitmapGlyph::Builder class
******************************************************************************/
CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
: BitmapGlyph::Builder(data, format) {
}
CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
: BitmapGlyph::Builder(data, format) {
}
CompositeBitmapGlyph::Builder::~Builder() {
}
CALLER_ATTACH FontDataTable*
CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
Ptr<CompositeBitmapGlyph> glyph = new CompositeBitmapGlyph(data, format());
return glyph.Detach();
}
} // namespace sfntly

View File

@ -1,75 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 = the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
#include "sfntly/table/bitmap/bitmap_glyph.h"
namespace sfntly {
class CompositeBitmapGlyph : public BitmapGlyph,
public RefCounted<CompositeBitmapGlyph> {
public:
class Component {
public:
Component(const Component& rhs);
int32_t glyph_code() { return glyph_code_; }
int32_t x_offset() { return x_offset_; }
int32_t y_offset() { return y_offset_; }
// UNIMPLEMENTED: int hashCode()
bool operator==(const Component& rhs);
Component& operator=(const Component& rhs);
protected:
Component(int32_t glyph_code, int32_t x_offset, int32_t y_offset);
private:
int32_t glyph_code_;
int32_t x_offset_;
int32_t y_offset_;
friend class CompositeBitmapGlyph;
};
class Builder : public BitmapGlyph::Builder,
public RefCounted<Builder> {
public:
Builder(WritableFontData* data, int32_t format);
Builder(ReadableFontData* data, int32_t format);
virtual ~Builder();
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
};
CompositeBitmapGlyph(ReadableFontData* data, int32_t format);
virtual ~CompositeBitmapGlyph();
int32_t NumComponents();
// Note: returned immutable object over stack.
Component GetComponent(int32_t component_num) const;
private:
void Initialize(int32_t format);
int32_t num_components_offset_;
int32_t component_array_offset_;
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_

View File

@ -1,236 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/ebdt_table.h"
#include <stdlib.h>
#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
namespace sfntly {
/******************************************************************************
* EbdtTable class
******************************************************************************/
EbdtTable::~EbdtTable() {
}
int32_t EbdtTable::Version() {
return data_->ReadFixed(Offset::kVersion);
}
CALLER_ATTACH
BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) {
ReadableFontDataPtr glyph_data;
glyph_data.Attach(down_cast<ReadableFontData*>(data_->Slice(offset, length)));
return BitmapGlyph::CreateGlyph(glyph_data, format);
}
EbdtTable::EbdtTable(Header* header, ReadableFontData* data)
: SubTableContainerTable(header, data) {
}
/******************************************************************************
* EbdtTable::Builder class
******************************************************************************/
EbdtTable::Builder::Builder(Header* header, WritableFontData* data)
: SubTableContainerTable::Builder(header, data) {
}
EbdtTable::Builder::Builder(Header* header, ReadableFontData* data)
: SubTableContainerTable::Builder(header, data) {
}
EbdtTable::Builder::~Builder() {
}
CALLER_ATTACH FontDataTable*
EbdtTable::Builder::SubBuildTable(ReadableFontData* data) {
FontDataTablePtr table = new EbdtTable(header(), data);
return table.Detach();
}
void EbdtTable::Builder::SubDataSet() {
Revert();
}
int32_t EbdtTable::Builder::SubDataSizeToSerialize() {
if (glyph_builders_.empty()) {
return 0;
}
bool fixed = true;
int32_t size = Offset::kHeaderLength;
for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
builder_end = glyph_builders_.end();
builder_map != builder_end;
builder_map++) {
for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
glyph_entry_end = builder_map->end();
glyph_entry != glyph_entry_end;
glyph_entry++) {
int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize();
size += abs(glyph_size);
fixed = (glyph_size <= 0) ? false : fixed;
}
}
return (fixed ? 1 : -1) * size;
}
bool EbdtTable::Builder::SubReadyToSerialize() {
if (glyph_builders_.empty()) {
return false;
}
return true;
}
int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) {
int32_t size = 0;
size += new_data->WriteFixed(Offset::kVersion, kVersion);
for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
builder_end = glyph_builders_.end();
builder_map != builder_end;
builder_map++) {
for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
glyph_entry_end = builder_map->end();
glyph_entry != glyph_entry_end;
glyph_entry++) {
WritableFontDataPtr slice;
slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
size += glyph_entry->second->SubSerialize(slice);
}
}
return size;
}
void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) {
assert(loca_list);
Revert();
glyph_loca_.resize(loca_list->size());
std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin());
}
void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) {
assert(output);
output->clear();
if (glyph_builders_.empty()) {
if (glyph_loca_.empty()) {
return;
}
}
int start_offset = Offset::kHeaderLength;
for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
builder_end = glyph_builders_.end();
builder_map != builder_end;
builder_map++) {
BitmapGlyphInfoMap new_loca_map;
int32_t glyph_offset = 0;
for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
glyph_end = builder_map->end();
glyph_entry != glyph_end;
glyph_entry++) {
BitmapGlyphBuilderPtr builder = glyph_entry->second;
int32_t size = builder->SubDataSizeToSerialize();
BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first,
start_offset + glyph_offset, size, builder->format());
new_loca_map[glyph_entry->first] = info;
glyph_offset += size;
}
start_offset += glyph_offset;
output->push_back(new_loca_map);
}
}
BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() {
return GetGlyphBuilders();
}
void EbdtTable::Builder::SetGlyphBuilders(
BitmapGlyphBuilderList* glyph_builders) {
glyph_builders_.clear();
std::copy(glyph_builders->begin(), glyph_builders->end(),
glyph_builders_.begin());
set_model_changed();
}
void EbdtTable::Builder::Revert() {
glyph_loca_.clear();
glyph_builders_.clear();
set_model_changed(false);
}
CALLER_ATTACH
EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header,
WritableFontData* data) {
Ptr<EbdtTable::Builder> builder;
builder = new Builder(header, data);
return builder.Detach();
}
CALLER_ATTACH
EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header,
ReadableFontData* data) {
Ptr<EbdtTable::Builder> builder;
builder = new Builder(header, data);
return builder.Detach();
}
BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() {
if (glyph_builders_.empty()) {
if (glyph_loca_.empty()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IllegalStateException(
"Loca values not set - unable to parse glyph data.");
#endif
return NULL;
}
Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_);
set_model_changed();
}
return &glyph_builders_;
}
void EbdtTable::Builder::Initialize(ReadableFontData* data,
BitmapLocaList* loca_list,
BitmapGlyphBuilderList* output) {
assert(loca_list);
assert(output);
output->clear();
if (data) {
for (BitmapLocaList::iterator loca_map = loca_list->begin(),
loca_end = loca_list->end();
loca_map != loca_end; loca_map++) {
BitmapGlyphBuilderMap glyph_builder_map;
for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(),
entry_end = loca_map->end();
entry != entry_end; entry++) {
BitmapGlyphInfoPtr info = entry->second;
ReadableFontDataPtr slice;
slice.Attach(down_cast<ReadableFontData*>(data->Slice(
info->offset(), info->length())));
BitmapGlyphBuilderPtr glyph_builder;
glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder(
slice, info->format()));
glyph_builder_map[entry->first] = glyph_builder;
}
output->push_back(glyph_builder_map);
}
}
}
} // namespace sfntly

View File

@ -1,108 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
#include "sfntly/table/bitmap/bitmap_glyph.h"
#include "sfntly/table/bitmap/bitmap_glyph_info.h"
#include "sfntly/table/subtable_container_table.h"
namespace sfntly {
class EbdtTable : public SubTableContainerTable,
public RefCounted<EbdtTable> {
public:
struct Offset {
enum {
kVersion = 0,
kHeaderLength = DataSize::kFixed,
};
};
class Builder : public SubTableContainerTable::Builder,
public RefCounted<Builder> {
public:
// Constructor scope altered to public because C++ does not allow base
// class to instantiate derived class with protected constructors.
Builder(Header* header, WritableFontData* data);
Builder(Header* header, ReadableFontData* data);
virtual ~Builder();
virtual int32_t SubSerialize(WritableFontData* new_data);
virtual bool SubReadyToSerialize();
virtual int32_t SubDataSizeToSerialize();
virtual void SubDataSet();
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
void SetLoca(BitmapLocaList* loca_list);
void GenerateLocaList(BitmapLocaList* output);
// Gets the List of glyph builders for the glyph table builder. These may be
// manipulated in any way by the caller and the changes will be reflected in
// the final glyph table produced.
// If there is no current data for the glyph builder or the glyph builders
// have not been previously set then this will return an empty glyph builder
// List. If there is current data (i.e. data read from an existing font) and
// the loca list has not been set or is null, empty, or invalid, then an
// empty glyph builder List will be returned.
// @return the list of glyph builders
BitmapGlyphBuilderList* GlyphBuilders();
// Replace the internal glyph builders with the one provided. The provided
// list and all contained objects belong to this builder.
// This call is only required if the entire set of glyphs in the glyph
// table builder are being replaced. If the glyph builder list provided from
// the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified
// then those changes will already be reflected in the glyph table builder.
// @param glyphBuilders the new glyph builders
void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders);
void Revert();
// Create a new builder using the header information and data provided.
// @param header the header information
// @param data the data holding the table
static CALLER_ATTACH Builder* CreateBuilder(Header* header,
WritableFontData* data);
static CALLER_ATTACH Builder* CreateBuilder(Header* header,
ReadableFontData* data);
private:
BitmapGlyphBuilderList* GetGlyphBuilders();
static void Initialize(ReadableFontData* data,
BitmapLocaList* loca_list,
BitmapGlyphBuilderList* output);
static const int32_t kVersion = 0x00020000; // TODO(stuartg): const/enum
BitmapLocaList glyph_loca_;
BitmapGlyphBuilderList glyph_builders_;
};
virtual ~EbdtTable();
int32_t Version();
CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset,
int32_t length,
int32_t format);
protected:
EbdtTable(Header* header, ReadableFontData* data);
};
typedef Ptr<EbdtTable> EbdtTablePtr;
typedef Ptr<EbdtTable::Builder> EbdtTableBuilderPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_

View File

@ -1,313 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/eblc_table.h"
#include <stdio.h>
#include <stdlib.h>
#include "sfntly/math/font_math.h"
namespace sfntly {
/******************************************************************************
* EblcTable class
******************************************************************************/
int32_t EblcTable::Version() {
return data_->ReadFixed(Offset::kVersion);
}
int32_t EblcTable::NumSizes() {
return data_->ReadULongAsInt(Offset::kNumSizes);
}
BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) {
if (index < 0 || index > NumSizes()) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundException(
"Size table index is outside the range of tables.");
#endif
return NULL;
}
BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList();
if (bitmap_size_table_list) {
return (*bitmap_size_table_list)[index];
}
return NULL;
}
EblcTable::EblcTable(Header* header, ReadableFontData* data)
: SubTableContainerTable(header, data) {
}
BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() {
AutoLock lock(bitmap_size_table_lock_);
if (bitmap_size_table_.empty()) {
CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_);
}
return &bitmap_size_table_;
}
// static
void EblcTable::CreateBitmapSizeTable(ReadableFontData* data,
int32_t num_sizes,
BitmapSizeTableList* output) {
assert(data);
assert(output);
for (int32_t i = 0; i < num_sizes; ++i) {
ReadableFontDataPtr new_data;
new_data.Attach(down_cast<ReadableFontData*>(
data->Slice(Offset::kBitmapSizeTableArrayStart +
i * Offset::kBitmapSizeTableLength,
Offset::kBitmapSizeTableLength)));
BitmapSizeTableBuilderPtr size_builder;
size_builder.Attach(
BitmapSizeTable::Builder::CreateBuilder(new_data, data));
BitmapSizeTablePtr size;
size.Attach(down_cast<BitmapSizeTable*>(size_builder->Build()));
output->push_back(size);
}
}
/******************************************************************************
* EblcTable::Builder class
******************************************************************************/
EblcTable::Builder::Builder(Header* header, WritableFontData* data)
: SubTableContainerTable::Builder(header, data) {
}
EblcTable::Builder::Builder(Header* header, ReadableFontData* data)
: SubTableContainerTable::Builder(header, data) {
}
EblcTable::Builder::~Builder() {
}
int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) {
// header
int32_t size = new_data->WriteFixed(0, kVersion);
size += new_data->WriteULong(size, size_table_builders_.size());
// calculate the offsets
// offset to the start of the size table array
int32_t size_table_start_offset = size;
// walking offset in the size table array
int32_t size_table_offset = size_table_start_offset;
// offset to the start of the whole index subtable block
int32_t sub_table_block_start_offset = size_table_offset +
size_table_builders_.size() * Offset::kBitmapSizeTableLength;
// walking offset in the index subtable
// points to the start of the current subtable block
int32_t current_sub_table_block_start_offset = sub_table_block_start_offset;
#if defined (SFNTLY_DEBUG_BITMAP)
int32_t size_index = 0;
#endif
for (BitmapSizeTableBuilderList::iterator
size_builder = size_table_builders_.begin(),
size_builder_end = size_table_builders_.end();
size_builder != size_builder_end; size_builder++) {
(*size_builder)->SetIndexSubTableArrayOffset(
current_sub_table_block_start_offset);
IndexSubTableBuilderList* index_sub_table_builder_list =
(*size_builder)->IndexSubTableBuilders();
// walking offset within the current subTable array
int32_t index_sub_table_array_offset = current_sub_table_block_start_offset;
// walking offset within the subTable entries
int32_t index_sub_table_offset = index_sub_table_array_offset +
index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength;
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ",
size_index, size_table_offset,
current_sub_table_block_start_offset);
fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset);
size_index++;
int32_t sub_table_index = 0;
#endif
for (IndexSubTableBuilderList::iterator
index_sub_table_builder = index_sub_table_builder_list->begin(),
index_sub_table_builder_end = index_sub_table_builder_list->end();
index_sub_table_builder != index_sub_table_builder_end;
index_sub_table_builder++) {
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index,
(*index_sub_table_builder)->index_format());
fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n",
index_sub_table_array_offset, index_sub_table_offset);
sub_table_index++;
#endif
// array entry
index_sub_table_array_offset += new_data->WriteUShort(
index_sub_table_array_offset,
(*index_sub_table_builder)->first_glyph_index());
index_sub_table_array_offset += new_data->WriteUShort(
index_sub_table_array_offset,
(*index_sub_table_builder)->last_glyph_index());
index_sub_table_array_offset += new_data->WriteULong(
index_sub_table_array_offset,
index_sub_table_offset - current_sub_table_block_start_offset);
// index sub table
WritableFontDataPtr slice_index_sub_table;
slice_index_sub_table.Attach(down_cast<WritableFontData*>(
new_data->Slice(index_sub_table_offset)));
int32_t current_sub_table_size =
(*index_sub_table_builder)->SubSerialize(slice_index_sub_table);
int32_t padding = FontMath::PaddingRequired(current_sub_table_size,
DataSize::kULONG);
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n",
current_sub_table_size, padding);
#endif
index_sub_table_offset += current_sub_table_size;
index_sub_table_offset +=
new_data->WritePadding(index_sub_table_offset, padding);
}
// serialize size table
(*size_builder)->SetIndexTableSize(
index_sub_table_offset - current_sub_table_block_start_offset);
WritableFontDataPtr slice_size_table;
slice_size_table.Attach(down_cast<WritableFontData*>(
new_data->Slice(size_table_offset)));
size_table_offset += (*size_builder)->SubSerialize(slice_size_table);
current_sub_table_block_start_offset = index_sub_table_offset;
}
return size + current_sub_table_block_start_offset;
}
bool EblcTable::Builder::SubReadyToSerialize() {
if (size_table_builders_.empty()) {
return false;
}
for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
e = size_table_builders_.end();
b != e; b++) {
if (!(*b)->SubReadyToSerialize()) {
return false;
}
}
return true;
}
int32_t EblcTable::Builder::SubDataSizeToSerialize() {
if (size_table_builders_.empty()) {
return 0;
}
int32_t size = Offset::kHeaderLength;
bool variable = false;
#if defined (SFNTLY_DEBUG_BITMAP)
size_t size_index = 0;
#endif
for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
e = size_table_builders_.end();
b != e; b++) {
int32_t size_builder_size = (*b)->SubDataSizeToSerialize();
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n",
size_index++, size_builder_size, size_builder_size);
#endif
variable = size_builder_size > 0 ? variable : true;
size += abs(size_builder_size);
}
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "eblc size=%d\n", size);
#endif
return variable ? -size : size;
}
void EblcTable::Builder::SubDataSet() {
Revert();
}
BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() {
return GetSizeList();
}
void EblcTable::Builder::Revert() {
size_table_builders_.clear();
set_model_changed(false);
}
void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) {
assert(output);
BitmapSizeTableBuilderList* size_builder_list = GetSizeList();
output->clear();
#if defined (SFNTLY_DEBUG_BITMAP)
int32_t size_index = 0;
#endif
for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(),
e = size_builder_list->end();
b != e; b++) {
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "size table = %d\n", size_index++);
#endif
BitmapGlyphInfoMap loca_map;
(*b)->GenerateLocaMap(&loca_map);
output->push_back(loca_map);
}
}
CALLER_ATTACH
FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) {
Ptr<EblcTable> new_table = new EblcTable(header(), data);
return new_table.Detach();
}
// static
CALLER_ATTACH EblcTable::Builder*
EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) {
Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
return new_builder.Detach();
}
// static
CALLER_ATTACH EblcTable::Builder*
EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) {
Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
return new_builder.Detach();
}
BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() {
if (size_table_builders_.empty()) {
Initialize(InternalReadData(), &size_table_builders_);
set_model_changed();
}
return &size_table_builders_;
}
void EblcTable::Builder::Initialize(ReadableFontData* data,
BitmapSizeTableBuilderList* output) {
assert(output);
if (data) {
int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes);
for (int32_t i = 0; i < num_sizes; ++i) {
ReadableFontDataPtr new_data;
new_data.Attach(down_cast<ReadableFontData*>(
data->Slice(Offset::kBitmapSizeTableArrayStart +
i * Offset::kBitmapSizeTableLength,
Offset::kBitmapSizeTableLength)));
BitmapSizeTableBuilderPtr size_builder;
size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder(
new_data, data));
output->push_back(size_builder);
}
}
}
} // namespace sfntly

View File

@ -1,194 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
#include "sfntly/port/lock.h"
#include "sfntly/table/bitmap/big_glyph_metrics.h"
#include "sfntly/table/bitmap/bitmap_glyph.h"
#include "sfntly/table/bitmap/bitmap_size_table.h"
#include "sfntly/table/subtable_container_table.h"
namespace sfntly {
class EblcTable : public SubTableContainerTable,
public RefCounted<EblcTable> {
public:
struct Offset {
enum {
// header
kVersion = 0,
kNumSizes = 4,
kHeaderLength = kNumSizes + DataSize::kULONG,
// bitmapSizeTable
kBitmapSizeTableArrayStart = kHeaderLength,
kBitmapSizeTableLength = 48,
kBitmapSizeTable_indexSubTableArrayOffset = 0,
kBitmapSizeTable_indexTableSize = 4,
kBitmapSizeTable_numberOfIndexSubTables = 8,
kBitmapSizeTable_colorRef = 12,
kBitmapSizeTable_hori = 16,
kBitmapSizeTable_vert = 28,
kBitmapSizeTable_startGlyphIndex = 40,
kBitmapSizeTable_endGlyphIndex = 42,
kBitmapSizeTable_ppemX = 44,
kBitmapSizeTable_ppemY = 45,
kBitmapSizeTable_bitDepth = 46,
kBitmapSizeTable_flags = 47,
// sbitLineMetrics
kSbitLineMetricsLength = 12,
kSbitLineMetrics_ascender = 0,
kSbitLineMetrics_descender = 1,
kSbitLineMetrics_widthMax = 2,
kSbitLineMetrics_caretSlopeNumerator = 3,
kSbitLineMetrics_caretSlopeDenominator = 4,
kSbitLineMetrics_caretOffset = 5,
kSbitLineMetrics_minOriginSB = 6,
kSbitLineMetrics_minAdvanceSB = 7,
kSbitLineMetrics_maxBeforeBL = 8,
kSbitLineMetrics_minAfterBL = 9,
kSbitLineMetrics_pad1 = 10,
kSbitLineMetrics_pad2 = 11,
// indexSubTable
kIndexSubTableEntryLength = 8,
kIndexSubTableEntry_firstGlyphIndex = 0,
kIndexSubTableEntry_lastGlyphIndex = 2,
kIndexSubTableEntry_additionalOffsetToIndexSubTable = 4,
// indexSubHeader
kIndexSubHeaderLength = 8,
kIndexSubHeader_indexFormat = 0,
kIndexSubHeader_imageFormat = 2,
kIndexSubHeader_imageDataOffset = 4,
// indexSubTable - all offset relative to the subtable start
// indexSubTable1
kIndexSubTable1_offsetArray = kIndexSubHeaderLength,
kIndexSubTable1_builderDataSize = kIndexSubHeaderLength,
// kIndexSubTable2
kIndexSubTable2Length = kIndexSubHeaderLength +
DataSize::kULONG +
BitmapGlyph::Offset::kBigGlyphMetricsLength,
kIndexSubTable2_imageSize = kIndexSubHeaderLength,
kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize +
DataSize::kULONG,
kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics +
BigGlyphMetrics::Offset::kMetricsLength,
// kIndexSubTable3
kIndexSubTable3_offsetArray = kIndexSubHeaderLength,
kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray,
// kIndexSubTable4
kIndexSubTable4_numGlyphs = kIndexSubHeaderLength,
kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs +
DataSize::kULONG,
kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT,
kIndexSubTable4_codeOffsetPair_glyphCode = 0,
kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT,
kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray,
// kIndexSubTable5
kIndexSubTable5_imageSize = kIndexSubHeaderLength,
kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize +
DataSize::kULONG,
kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics +
BitmapGlyph::Offset::kBigGlyphMetricsLength,
kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs +
DataSize::kULONG,
kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray,
// codeOffsetPair
kCodeOffsetPairLength = 2 * DataSize::kUSHORT,
kCodeOffsetPair_glyphCode = 0,
kCodeOffsetPair_offset = DataSize::kUSHORT,
};
};
class Builder : public SubTableContainerTable::Builder,
public RefCounted<Builder> {
public:
// Constructor scope altered to public because C++ does not allow base
// class to instantiate derived class with protected constructors.
Builder(Header* header, WritableFontData* data);
Builder(Header* header, ReadableFontData* data);
virtual ~Builder();
virtual int32_t SubSerialize(WritableFontData* new_data);
virtual bool SubReadyToSerialize();
virtual int32_t SubDataSizeToSerialize();
virtual void SubDataSet();
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
BitmapSizeTableBuilderList* BitmapSizeBuilders();
void Revert();
// Generates the loca list for the EBDT table. The list is intended to be
// used by the EBDT to allow it to parse the glyph data and generate glyph
// objects. After returning from this method the list belongs to the caller.
// The list entries are in the same order as the size table builders are at
// the time of this call.
// @return the list of loca maps with one for each size table builder
void GenerateLocaList(BitmapLocaList* output);
// Create a new builder using the header information and data provided.
// @param header the header information
// @param data the data holding the table
static CALLER_ATTACH Builder* CreateBuilder(Header* header,
WritableFontData* data);
static CALLER_ATTACH Builder* CreateBuilder(Header* header,
ReadableFontData* data);
private:
BitmapSizeTableBuilderList* GetSizeList();
void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output);
static const int32_t kVersion = 0x00020000;
BitmapSizeTableBuilderList size_table_builders_;
};
int32_t Version();
int32_t NumSizes();
// UNIMPLEMENTED: toString()
BitmapSizeTable* GetBitmapSizeTable(int32_t index);
static const int32_t NOTDEF = -1;
protected:
EblcTable(Header* header, ReadableFontData* data);
private:
BitmapSizeTableList* GetBitmapSizeTableList();
static void CreateBitmapSizeTable(ReadableFontData* data,
int32_t num_sizes,
BitmapSizeTableList* output);
Lock bitmap_size_table_lock_;
BitmapSizeTableList bitmap_size_table_;
};
typedef Ptr<EblcTable> EblcTablePtr;
typedef Ptr<EblcTable::Builder> EblcTableBuilderPtr;
}
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_

View File

@ -1,107 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/ebsc_table.h"
namespace sfntly {
/******************************************************************************
* EbscTable class
******************************************************************************/
EbscTable::~EbscTable() {
}
int32_t EbscTable::Version() {
return data_->ReadFixed(Offset::kVersion);
}
int32_t EbscTable::NumSizes() {
return data_->ReadULongAsInt(Offset::kNumSizes);
}
EbscTable::EbscTable(Header* header, ReadableFontData* data)
: Table(header, data) {
}
/******************************************************************************
* EbscTable::BitmapScaleTable class
******************************************************************************/
EbscTable::BitmapScaleTable::~BitmapScaleTable() {
}
EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data)
: SubTable(data) {
}
int32_t EbscTable::BitmapScaleTable::PpemX() {
return data_->ReadByte(Offset::kBitmapScaleTable_ppemX);
}
int32_t EbscTable::BitmapScaleTable::PpemY() {
return data_->ReadByte(Offset::kBitmapScaleTable_ppemY);
}
int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() {
return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX);
}
int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() {
return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY);
}
/******************************************************************************
* EbscTable::Builder class
******************************************************************************/
EbscTable::Builder::~Builder() {
}
CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder(
Header* header, WritableFontData* data) {
EbscTableBuilderPtr builder = new EbscTable::Builder(header, data);
return builder.Detach();
}
EbscTable::Builder::Builder(Header* header, WritableFontData* data)
: Table::Builder(header, data) {
}
EbscTable::Builder::Builder(Header* header, ReadableFontData* data)
: Table::Builder(header, data) {
}
CALLER_ATTACH
FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) {
EbscTablePtr output = new EbscTable(header(), data);
return output.Detach();
}
void EbscTable::Builder::SubDataSet() {
// NOP
}
int32_t EbscTable::Builder::SubDataSizeToSerialize() {
return 0;
}
bool EbscTable::Builder::SubReadyToSerialize() {
return false;
}
int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) {
UNREFERENCED_PARAMETER(new_data);
return 0;
}
} // namespace sfntly

View File

@ -1,101 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
#include "sfntly/table/bitmap/eblc_table.h"
namespace sfntly {
class EbscTable : public Table,
public RefCounted<EbscTable> {
public:
struct Offset {
enum {
// header
kVersion = 0,
kNumSizes = DataSize::kFixed,
kHeaderLength = kNumSizes + DataSize::kULONG,
kBitmapScaleTableStart = kHeaderLength,
// bitmapScaleTable
kBitmapScaleTable_hori = 0,
kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength,
kBitmapScaleTable_ppemX = kBitmapScaleTable_vert +
EblcTable::Offset::kSbitLineMetricsLength,
kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE,
kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY +
DataSize::kBYTE,
kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX +
DataSize::kBYTE,
kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY +
DataSize::kBYTE,
};
};
class BitmapScaleTable : public SubTable,
public RefCounted<BitmapScaleTable> {
public:
virtual ~BitmapScaleTable();
int32_t PpemX();
int32_t PpemY();
int32_t SubstitutePpemX();
int32_t SubstitutePpemY();
protected:
// Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength)
explicit BitmapScaleTable(ReadableFontData* data);
};
// TODO(stuartg): currently the builder just builds from initial data
// - need to make fully working but few if any examples to test with
class Builder : public Table::Builder,
public RefCounted<Builder> {
public:
virtual ~Builder();
static CALLER_ATTACH Builder* CreateBuilder(Header* header,
WritableFontData* data);
protected:
Builder(Header* header, WritableFontData* data);
Builder(Header* header, ReadableFontData* data);
virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
virtual void SubDataSet();
virtual int32_t SubDataSizeToSerialize();
virtual bool SubReadyToSerialize();
virtual int32_t SubSerialize(WritableFontData* new_data);
};
virtual ~EbscTable();
int32_t Version();
int32_t NumSizes();
// Note: renamed from bitmapScaleTable
CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index);
private:
EbscTable(Header* header, ReadableFontData* data);
friend class Builder;
};
typedef Ptr<EbscTable> EbscTablePtr;
typedef Ptr<EbscTable::Builder> EbscTableBuilderPtr;
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_

View File

@ -1,39 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/glyph_metrics.h"
namespace sfntly {
GlyphMetrics::~GlyphMetrics() {
}
GlyphMetrics::GlyphMetrics(ReadableFontData* data)
: SubTable(data) {
}
GlyphMetrics::Builder::~Builder() {
}
GlyphMetrics::Builder::Builder(WritableFontData* data)
: SubTable::Builder(data) {
}
GlyphMetrics::Builder::Builder(ReadableFontData* data)
: SubTable::Builder(data) {
}
} // namespace sfntly

View File

@ -1,43 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
#include "sfntly/table/subtable.h"
namespace sfntly {
class GlyphMetrics : public SubTable {
public:
virtual ~GlyphMetrics();
protected:
class Builder : public SubTable::Builder {
public:
virtual ~Builder();
protected:
explicit Builder(WritableFontData* data);
explicit Builder(ReadableFontData* data);
};
explicit GlyphMetrics(ReadableFontData* data);
};
} // namespace sfntly
#endif // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_

View File

@ -1,278 +0,0 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sfntly/table/bitmap/index_sub_table.h"
#include "sfntly/table/bitmap/eblc_table.h"
#include "sfntly/table/bitmap/index_sub_table_format1.h"
#include "sfntly/table/bitmap/index_sub_table_format2.h"
#include "sfntly/table/bitmap/index_sub_table_format3.h"
#include "sfntly/table/bitmap/index_sub_table_format4.h"
#include "sfntly/table/bitmap/index_sub_table_format5.h"
namespace sfntly {
/******************************************************************************
* IndexSubTable class
******************************************************************************/
CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) {
int32_t loca = CheckGlyphRange(glyph_id);
if (loca == -1) {
return NULL;
}
if (GlyphStartOffset(glyph_id) == -1) {
return NULL;
}
BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id,
image_data_offset(),
GlyphStartOffset(glyph_id),
GlyphLength(glyph_id),
image_format());
return output.Detach();
}
int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) {
int32_t glyph_start_offset = GlyphStartOffset(glyph_id);
if (glyph_start_offset == -1) {
return -1;
}
return image_data_offset() + glyph_start_offset;
}
// static
CALLER_ATTACH IndexSubTable*
IndexSubTable::CreateIndexSubTable(ReadableFontData* data,
int32_t offset_to_index_sub_table_array,
int32_t array_index) {
IndexSubTableBuilderPtr builder;
builder.Attach(IndexSubTable::Builder::CreateBuilder(
data, offset_to_index_sub_table_array, array_index));
return down_cast<IndexSubTable*>(builder->Build());
}
IndexSubTable::IndexSubTable(ReadableFontData* data,
int32_t first_glyph_index,
int32_t last_glyph_index)
: SubTable(data),
first_glyph_index_(first_glyph_index),
last_glyph_index_(last_glyph_index) {
index_format_ =
data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
image_format_ =
data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
image_data_offset_ =
data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
}
int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) {
return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index());
}
// static
int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id,
int32_t first_glyph_id,
int32_t last_glyph_id) {
if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) {
#if !defined (SFNTLY_NO_EXCEPTION)
throw IndexOutOfBoundException("Glyph ID is outside of the allowed range.");
#endif
return -1;
}
return glyph_id - first_glyph_id;
}
/******************************************************************************
* IndexSubTable::Builder class
******************************************************************************/
IndexSubTable::Builder::~Builder() {
}
void IndexSubTable::Builder::Revert() {
set_model_changed(false);
Initialize(InternalReadData());
}
CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo(
int32_t glyph_id) {
BitmapGlyphInfoPtr glyph_info =
new BitmapGlyphInfo(glyph_id,
image_data_offset(),
GlyphStartOffset(glyph_id),
GlyphLength(glyph_id),
image_format());
return glyph_info.Detach();
}
int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) {
return image_data_offset() + GlyphStartOffset(glyph_id);
}
// static
CALLER_ATTACH IndexSubTable::Builder*
IndexSubTable::Builder::CreateBuilder(int32_t index_format) {
switch (index_format) {
case Format::FORMAT_1:
return IndexSubTableFormat1::Builder::CreateBuilder();
case Format::FORMAT_2:
return IndexSubTableFormat2::Builder::CreateBuilder();
case Format::FORMAT_3:
return IndexSubTableFormat3::Builder::CreateBuilder();
case Format::FORMAT_4:
return IndexSubTableFormat4::Builder::CreateBuilder();
case Format::FORMAT_5:
return IndexSubTableFormat5::Builder::CreateBuilder();
default:
#if !defined (SFNTLY_NO_EXCEPTION)
throw IllegalArgumentException("Invalid index subtable format");
#endif
return NULL;
}
}
// static
CALLER_ATTACH IndexSubTable::Builder*
IndexSubTable::Builder::CreateBuilder(ReadableFontData* data,
int32_t offset_to_index_sub_table_array, int32_t array_index) {
int32_t index_sub_table_entry_offset =
offset_to_index_sub_table_array +
array_index * EblcTable::Offset::kIndexSubTableEntryLength;
int32_t first_glyph_index =
data->ReadUShort(index_sub_table_entry_offset +
EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex);
int32_t last_glyph_index =
data->ReadUShort(index_sub_table_entry_offset +
EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex);
int32_t additional_offset_to_index_subtable = data->ReadULongAsInt(
index_sub_table_entry_offset +
EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable);
int32_t index_sub_table_offset = offset_to_index_sub_table_array +
additional_offset_to_index_subtable;
int32_t index_format = data->ReadUShort(index_sub_table_offset);
switch (index_format) {
case 1:
return IndexSubTableFormat1::Builder::CreateBuilder(
data, index_sub_table_offset, first_glyph_index, last_glyph_index);
case 2:
return IndexSubTableFormat2::Builder::CreateBuilder(
data, index_sub_table_offset, first_glyph_index, last_glyph_index);
case 3:
return IndexSubTableFormat3::Builder::CreateBuilder(
data, index_sub_table_offset, first_glyph_index, last_glyph_index);
case 4:
return IndexSubTableFormat4::Builder::CreateBuilder(
data, index_sub_table_offset, first_glyph_index, last_glyph_index);
case 5:
return IndexSubTableFormat5::Builder::CreateBuilder(
data, index_sub_table_offset, first_glyph_index, last_glyph_index);
default:
// Unknown format and unable to process.
#if !defined (SFNTLY_NO_EXCEPTION)
throw IllegalArgumentException("Invalid Index Subtable Format");
#endif
break;
}
return NULL;
}
CALLER_ATTACH
FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) {
UNREFERENCED_PARAMETER(data);
return NULL;
}
void IndexSubTable::Builder::SubDataSet() {
// NOP
}
int32_t IndexSubTable::Builder::SubDataSizeToSerialize() {
return 0;
}
bool IndexSubTable::Builder::SubReadyToSerialize() {
return false;
}
int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) {
UNREFERENCED_PARAMETER(new_data);
return 0;
}
IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format)
: SubTable::Builder(data_size),
first_glyph_index_(0),
last_glyph_index_(0),
index_format_(index_format),
image_format_(0),
image_data_offset_(0) {
}
IndexSubTable::Builder::Builder(int32_t index_format,
int32_t image_format,
int32_t image_data_offset,
int32_t data_size)
: SubTable::Builder(data_size),
first_glyph_index_(0),
last_glyph_index_(0),
index_format_(index_format),
image_format_(image_format),
image_data_offset_(image_data_offset) {
}
IndexSubTable::Builder::Builder(WritableFontData* data,
int32_t first_glyph_index,
int32_t last_glyph_index)
: SubTable::Builder(data),
first_glyph_index_(first_glyph_index),
last_glyph_index_(last_glyph_index) {
Initialize(data);
}
IndexSubTable::Builder::Builder(ReadableFontData* data,
int32_t first_glyph_index,
int32_t last_glyph_index)
: SubTable::Builder(data),
first_glyph_index_(first_glyph_index),
last_glyph_index_(last_glyph_index) {
Initialize(data);
}
int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) {
return IndexSubTable::CheckGlyphRange(glyph_id,
first_glyph_index(),
last_glyph_index());
}
int32_t IndexSubTable::Builder::SerializeIndexSubHeader(
WritableFontData* data) {
int32_t size =
data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat,
index_format());
size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat,
image_format());
size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset,
image_data_offset());
return size;
}
void IndexSubTable::Builder::Initialize(ReadableFontData* data) {
index_format_ =
data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
image_format_ =
data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
image_data_offset_ =
data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
}
} // namespace sfntly

Some files were not shown because too many files have changed in this diff Show More