mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-12-29 00:00:20 -05:00
Sync to trunk.
This commit is contained in:
commit
5d3f97064f
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'],
|
||||
),
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -91,7 +91,6 @@ class Plugins(collections.Mapping):
|
||||
'speedup',
|
||||
'freetype',
|
||||
'woff',
|
||||
'sfntly',
|
||||
]
|
||||
if iswindows:
|
||||
plugins.extend(['winutil', 'wpd', 'winfonts'])
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
284
src/calibre/ebooks/oeb/transforms/subset.py
Normal file
284
src/calibre/ebooks/oeb/transforms/subset.py
Normal 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
|
||||
|
||||
|
||||
@ -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']
|
||||
|
||||
@ -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&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>
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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>&Subset all embedded fonts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -403,7 +403,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
return
|
||||
|
||||
all_locations = OrderedDict(ConfigWidget.LOCATIONS)
|
||||
plugin_action = plugin.load_actual_plugin(self.gui)
|
||||
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])
|
||||
|
||||
@ -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):
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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'] = " & ".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,
|
||||
genre_tag_set[genre],
|
||||
"%s/Genre_%s.html" % (self.content_dir,
|
||||
genre))
|
||||
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],
|
||||
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.
|
||||
|
||||
|
||||
@ -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'):
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -309,8 +309,11 @@ class WindowsAtomicFolderMove(object):
|
||||
handle = h
|
||||
break
|
||||
if handle is None:
|
||||
raise ValueError(u'The file %r did not exist when this move'
|
||||
' operation was started'%path)
|
||||
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):
|
||||
|
||||
74
src/calibre/utils/fonts/sfnt/__init__.py
Normal file
74
src/calibre/utils/fonts/sfnt/__init__.py
Normal 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)
|
||||
|
||||
153
src/calibre/utils/fonts/sfnt/cff.py
Normal file
153
src/calibre/utils/fonts/sfnt/cff.py
Normal 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'
|
||||
]
|
||||
# }}}
|
||||
|
||||
11
src/calibre/utils/fonts/sfnt/cff/__init__.py
Normal file
11
src/calibre/utils/fonts/sfnt/cff/__init__.py
Normal 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'
|
||||
|
||||
|
||||
|
||||
200
src/calibre/utils/fonts/sfnt/cff/dict_data.py
Normal file
200
src/calibre/utils/fonts/sfnt/cff/dict_data.py
Normal 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()),
|
||||
]
|
||||
|
||||
159
src/calibre/utils/fonts/sfnt/cff/table.py
Normal file
159
src/calibre/utils/fonts/sfnt/cff/table.py
Normal 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'
|
||||
]
|
||||
# }}}
|
||||
|
||||
236
src/calibre/utils/fonts/sfnt/cmap.py
Normal file
236
src/calibre/utils/fonts/sfnt/cmap.py
Normal 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
|
||||
|
||||
127
src/calibre/utils/fonts/sfnt/container.py
Normal file
127
src/calibre/utils/fonts/sfnt/container.py
Normal 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])
|
||||
|
||||
15
src/calibre/utils/fonts/sfnt/errors.py
Normal file
15
src/calibre/utils/fonts/sfnt/errors.py
Normal 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
|
||||
|
||||
88
src/calibre/utils/fonts/sfnt/glyf.py
Normal file
88
src/calibre/utils/fonts/sfnt/glyf.py
Normal 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
|
||||
|
||||
55
src/calibre/utils/fonts/sfnt/head.py
Normal file
55
src/calibre/utils/fonts/sfnt/head.py
Normal 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)
|
||||
|
||||
|
||||
66
src/calibre/utils/fonts/sfnt/loca.py
Normal file
66
src/calibre/utils/fonts/sfnt/loca.py
Normal 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)
|
||||
|
||||
|
||||
49
src/calibre/utils/fonts/sfnt/maxp.py
Normal file
49
src/calibre/utils/fonts/sfnt/maxp.py
Normal 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)
|
||||
|
||||
|
||||
|
||||
@ -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 = {}
|
||||
|
||||
while unresolved_glyphs:
|
||||
glyph_id = unresolved_glyphs.pop()
|
||||
try:
|
||||
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']
|
||||
|
||||
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()
|
||||
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))
|
||||
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))
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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_;
|
||||
};
|
||||
@ -212,7 +212,11 @@ class SearchQueryParser(object):
|
||||
# another search.
|
||||
def _parse(self, query, candidates=None):
|
||||
self.recurse_level += 1
|
||||
res = self._parser.parseString(query)[0]
|
||||
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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user