[Complex Text Layouts] Add third-party TextServer dependencies (ICU, HarfBuzz, Graphite).

This commit is contained in:
bruvzg 2020-08-11 12:10:23 +03:00
parent 493da99269
commit b9f441e81e
No known key found for this signature in database
GPG Key ID: FCED35F1CECE0D3A
734 changed files with 361362 additions and 4 deletions

View File

@ -174,6 +174,33 @@ Copyright: 2015-2020 Google, Inc.
2002, NVIDIA Corporation.
License: glslang
Files: ./thirdparty/graphite/
Comment: Graphite engine
Copyright: 2010, SIL International
License: MPL-2.0
Files: ./thirdparty/harfbuzz/
Comment: HarfBuzz text shaping library
Copyright: 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
2018,2019,2020 Ebrahim Byagowi
2019,2020 Facebook, Inc.
2012 Mozilla Foundation
2011 Codethink Limited
2008,2010 Nokia Corporation and/or its subsidiary(-ies)
2009 Keith Stribley
2009 Martin Hosken and SIL International
2007 Chris Wilson
2006 Behdad Esfahbod
2005 David Turner
2004,2007,2008,2009,2010 Red Hat, Inc.
1998-2004 David Turner and Werner Lemberg
License: HarfBuzz
Files: ./thirdparty/icu4c/
Comment: International Components for Unicode
Copyright: 1991-2020, Unicode
License: Unicode
Files: ./thirdparty/jpeg_compressor/
Comment: jpeg-compressor
Copyright: 2012, Rich Geldreich
@ -1180,6 +1207,46 @@ License: FTL
Robert Wilhelm <robert.wilhelm@freetype.org>
Werner Lemberg <werner.lemberg@freetype.org>
License: HarfBuzz
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
For parts of HarfBuzz that are licensed under different licenses see individual
files names COPYING in subdirectories where applicable.
.
Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
Copyright (C) 2018,2019,2020 Ebrahim Byagowi
Copyright (C) 2019,2020 Facebook, Inc.
Copyright (C) 2012 Mozilla Foundation
Copyright (C) 2011 Codethink Limited
Copyright (C) 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2009 Keith Stribley
Copyright (C) 2009 Martin Hosken and SIL International
Copyright (C) 2007 Chris Wilson
Copyright (C) 2006 Behdad Esfahbod
Copyright (C) 2005 David Turner
Copyright (C) 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright (C) 1998-2004 David Turner and Werner Lemberg
.
For full copyright notices consult the individual files in the package.
.
.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the
above copyright notice and the following two paragraphs appear in
all copies of this software.
.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
.
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
License: MPL-2.0
Mozilla Public License Version 2.0
==================================
@ -1650,6 +1717,41 @@ License: Tamsyn
In no event will the author be held liable for damages arising from the use
of this font.
License: Unicode
COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later)
.
Copyright (C) 1991-2020 Unicode, Inc. All rights reserved.
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Unicode data files and any associated documentation
(the "Data Files") or Unicode software and any associated documentation
(the "Software") to deal in the Data Files or Software
without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, and/or sell copies of
the Data Files or Software, and to permit persons to whom the Data Files
or Software are furnished to do so, provided that either
(a) this copyright and permission notice appear with all copies
of the Data Files or Software, or
(b) this copyright and permission notice appear in associated
Documentation.
.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
License: Zlib
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View File

@ -144,6 +144,9 @@ opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundle
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
opts.Add(BoolVariable("builtin_freetype", "Use the built-in FreeType library", True))
opts.Add(BoolVariable("builtin_glslang", "Use the built-in glslang library", True))
opts.Add(BoolVariable("builtin_graphite", "Use the built-in Graphite library", True))
opts.Add(BoolVariable("builtin_harfbuzz", "Use the built-in HarfBuzz library", True))
opts.Add(BoolVariable("builtin_icu", "Use the built-in ICU library", True))
opts.Add(BoolVariable("builtin_libogg", "Use the built-in libogg library", True))
opts.Add(BoolVariable("builtin_libpng", "Use the built-in libpng library", True))
opts.Add(BoolVariable("builtin_libtheora", "Use the built-in libtheora library", True))

View File

@ -0,0 +1,419 @@
#!/usr/bin/env python
Import("env")
Import("env_modules")
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
# Thirdparty source files
thirdparty_dir = "#thirdparty/harfbuzz/"
thirdparty_sources = [
"src/hb-aat-layout.cc",
"src/hb-aat-map.cc",
"src/hb-blob.cc",
"src/hb-buffer-serialize.cc",
"src/hb-buffer.cc",
"src/hb-common.cc",
#'src/hb-coretext.cc',
#'src/hb-directwrite.cc',
"src/hb-draw.cc",
"src/hb-face.cc",
"src/hb-fallback-shape.cc",
"src/hb-font.cc",
"src/hb-ft.cc",
#'src/hb-gdi.cc',
#'src/hb-glib.cc',
#'src/hb-gobject-structs.cc',
"src/hb-graphite2.cc",
"src/hb-icu.cc",
"src/hb-map.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
"src/hb-ot-cff2-table.cc",
"src/hb-ot-color.cc",
"src/hb-ot-face.cc",
"src/hb-ot-font.cc",
"src/hb-ot-layout.cc",
"src/hb-ot-map.cc",
"src/hb-ot-math.cc",
"src/hb-ot-meta.cc",
"src/hb-ot-metrics.cc",
"src/hb-ot-name.cc",
"src/hb-ot-shape-complex-arabic.cc",
"src/hb-ot-shape-complex-default.cc",
"src/hb-ot-shape-complex-hangul.cc",
"src/hb-ot-shape-complex-hebrew.cc",
"src/hb-ot-shape-complex-indic-table.cc",
"src/hb-ot-shape-complex-indic.cc",
"src/hb-ot-shape-complex-khmer.cc",
"src/hb-ot-shape-complex-myanmar.cc",
"src/hb-ot-shape-complex-thai.cc",
"src/hb-ot-shape-complex-use-table.cc",
"src/hb-ot-shape-complex-use.cc",
"src/hb-ot-shape-complex-vowel-constraints.cc",
"src/hb-ot-shape-fallback.cc",
"src/hb-ot-shape-normalize.cc",
"src/hb-ot-shape.cc",
"src/hb-ot-tag.cc",
"src/hb-ot-var.cc",
"src/hb-set.cc",
"src/hb-shape-plan.cc",
"src/hb-shape.cc",
"src/hb-shaper.cc",
"src/hb-static.cc",
"src/hb-style.cc",
"src/hb-subset-cff-common.cc",
"src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc",
"src/hb-subset-input.cc",
"src/hb-subset-plan.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",
#'src/hb-uniscribe.cc'
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
if env["platform"] == "javascript":
if env["threads_enabled"]:
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
else:
env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
env_harfbuzz.Append(
CPPPATH=[
"#thirdparty/harfbuzz/src",
"#thirdparty/freetype/include",
"#thirdparty/graphite/include",
"#thirdparty/icu4c/common/",
]
)
env_harfbuzz.Append(
CCFLAGS=["-DHAVE_ICU_BUILTIN", "-DHAVE_ICU", "-DHAVE_FREETYPE", "-DHAVE_GRAPHITE2", "-DGRAPHITE2_STATIC",]
)
env_harfbuzz.disable_warnings()
env_thirdparty = env_harfbuzz.Clone()
env_thirdparty.disable_warnings()
lib = env_thirdparty.add_library("harfbuzz_builtin", thirdparty_sources)
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
# LIBS contains first SCons Library objects ("SCons.Node.FS.File object")
# and then plain strings for system library. We insert between the two.
inserted = False
for idx, linklib in enumerate(env["LIBS"]):
if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
env["LIBS"].insert(idx, lib)
inserted = True
break
if not inserted:
env.Append(LIBS=[lib])
if env["builtin_graphite"]:
env_graphite = env_modules.Clone()
# Thirdparty source files
thirdparty_dir = "#thirdparty/graphite/"
thirdparty_sources = [
"src/gr_char_info.cpp",
"src/gr_face.cpp",
"src/gr_features.cpp",
"src/gr_font.cpp",
"src/gr_logging.cpp",
"src/gr_segment.cpp",
"src/gr_slot.cpp",
"src/CmapCache.cpp",
"src/Code.cpp",
"src/Collider.cpp",
"src/Decompressor.cpp",
"src/Face.cpp",
#'src/FileFace.cpp',
"src/FeatureMap.cpp",
"src/Font.cpp",
"src/GlyphCache.cpp",
"src/GlyphFace.cpp",
"src/Intervals.cpp",
"src/Justifier.cpp",
"src/NameTable.cpp",
"src/Pass.cpp",
"src/Position.cpp",
"src/Segment.cpp",
"src/Silf.cpp",
"src/Slot.cpp",
"src/Sparse.cpp",
"src/TtfUtil.cpp",
"src/UtfCodec.cpp",
"src/FileFace.cpp",
"src/json.cpp",
]
if not env_graphite.msvc:
thirdparty_sources += ["src/direct_machine.cpp"]
else:
thirdparty_sources += ["src/call_machine.cpp"]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_graphite.Append(CPPPATH=["#thirdparty/graphite/src", "#thirdparty/graphite/include"])
env_graphite.Append(CCFLAGS=["-DGRAPHITE2_STATIC", "-DGRAPHITE2_NTRACING", "-DGRAPHITE2_NFILEFACE"])
env_graphite.disable_warnings()
env_thirdparty = env_graphite.Clone()
env_thirdparty.disable_warnings()
lib = env_thirdparty.add_library("graphite_builtin", thirdparty_sources)
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
# LIBS contains first SCons Library objects ("SCons.Node.FS.File object")
# and then plain strings for system library. We insert between the two.
inserted = False
for idx, linklib in enumerate(env["LIBS"]):
if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
env["LIBS"].insert(idx, lib)
inserted = True
break
if not inserted:
env.Append(LIBS=[lib])
if env["builtin_icu"]:
env_icu = env_modules.Clone()
# Thirdparty source files
thirdparty_dir = "#thirdparty/icu4c/"
# Thirdparty source files
thirdparty_sources = [
"common/appendable.cpp",
"common/bmpset.cpp",
"common/brkeng.cpp",
"common/brkiter.cpp",
"common/bytesinkutil.cpp",
"common/bytestream.cpp",
"common/bytestrie.cpp",
"common/bytestriebuilder.cpp",
"common/bytestrieiterator.cpp",
"common/caniter.cpp",
"common/characterproperties.cpp",
"common/chariter.cpp",
"common/charstr.cpp",
"common/cmemory.cpp",
"common/cstr.cpp",
"common/cstring.cpp",
"common/cwchar.cpp",
"common/dictbe.cpp",
"common/dictionarydata.cpp",
"common/dtintrv.cpp",
"common/edits.cpp",
"common/errorcode.cpp",
"common/filteredbrk.cpp",
"common/filterednormalizer2.cpp",
"common/icudataver.cpp",
"common/icuplug.cpp",
"common/loadednormalizer2impl.cpp",
"common/localebuilder.cpp",
"common/localematcher.cpp",
"common/localeprioritylist.cpp",
"common/locavailable.cpp",
"common/locbased.cpp",
"common/locdispnames.cpp",
"common/locdistance.cpp",
"common/locdspnm.cpp",
"common/locid.cpp",
"common/loclikely.cpp",
"common/loclikelysubtags.cpp",
"common/locmap.cpp",
"common/locresdata.cpp",
"common/locutil.cpp",
"common/lsr.cpp",
"common/messagepattern.cpp",
"common/normalizer2.cpp",
"common/normalizer2impl.cpp",
"common/normlzr.cpp",
"common/parsepos.cpp",
"common/patternprops.cpp",
"common/pluralmap.cpp",
"common/propname.cpp",
"common/propsvec.cpp",
"common/punycode.cpp",
"common/putil.cpp",
"common/rbbi.cpp",
"common/rbbi_cache.cpp",
"common/rbbidata.cpp",
"common/rbbinode.cpp",
"common/rbbirb.cpp",
"common/rbbiscan.cpp",
"common/rbbisetb.cpp",
"common/rbbistbl.cpp",
"common/rbbitblb.cpp",
"common/resbund.cpp",
"common/resbund_cnv.cpp",
"common/resource.cpp",
"common/restrace.cpp",
"common/ruleiter.cpp",
"common/schriter.cpp",
"common/serv.cpp",
"common/servlk.cpp",
"common/servlkf.cpp",
"common/servls.cpp",
"common/servnotf.cpp",
"common/servrbf.cpp",
"common/servslkf.cpp",
"common/sharedobject.cpp",
"common/simpleformatter.cpp",
"common/static_unicode_sets.cpp",
"common/stringpiece.cpp",
"common/stringtriebuilder.cpp",
"common/uarrsort.cpp",
"common/ubidi.cpp",
"common/ubidi_props.cpp",
"common/ubidiln.cpp",
"common/ubiditransform.cpp",
"common/ubidiwrt.cpp",
"common/ubrk.cpp",
"common/ucase.cpp",
"common/ucasemap.cpp",
"common/ucasemap_titlecase_brkiter.cpp",
"common/ucat.cpp",
"common/uchar.cpp",
"common/ucharstrie.cpp",
"common/ucharstriebuilder.cpp",
"common/ucharstrieiterator.cpp",
"common/uchriter.cpp",
"common/ucln_cmn.cpp",
"common/ucmndata.cpp",
"common/ucnv.cpp",
"common/ucnv2022.cpp",
"common/ucnv_bld.cpp",
"common/ucnv_cb.cpp",
"common/ucnv_cnv.cpp",
"common/ucnv_ct.cpp",
"common/ucnv_err.cpp",
"common/ucnv_ext.cpp",
"common/ucnv_io.cpp",
"common/ucnv_lmb.cpp",
"common/ucnv_set.cpp",
"common/ucnv_u16.cpp",
"common/ucnv_u32.cpp",
"common/ucnv_u7.cpp",
"common/ucnv_u8.cpp",
"common/ucnvbocu.cpp",
"common/ucnvdisp.cpp",
"common/ucnvhz.cpp",
"common/ucnvisci.cpp",
"common/ucnvlat1.cpp",
"common/ucnvmbcs.cpp",
"common/ucnvscsu.cpp",
"common/ucnvsel.cpp",
"common/ucol_swp.cpp",
"common/ucptrie.cpp",
"common/ucurr.cpp",
"common/udata.cpp",
"common/udatamem.cpp",
"common/udataswp.cpp",
"common/uenum.cpp",
"common/uhash.cpp",
"common/uhash_us.cpp",
"common/uidna.cpp",
"common/uinit.cpp",
"common/uinvchar.cpp",
"common/uiter.cpp",
"common/ulist.cpp",
"common/uloc.cpp",
"common/uloc_keytype.cpp",
"common/uloc_tag.cpp",
"common/umapfile.cpp",
"common/umath.cpp",
"common/umutablecptrie.cpp",
"common/umutex.cpp",
"common/unames.cpp",
"common/unifiedcache.cpp",
"common/unifilt.cpp",
"common/unifunct.cpp",
"common/uniset.cpp",
"common/uniset_closure.cpp",
"common/uniset_props.cpp",
"common/unisetspan.cpp",
"common/unistr.cpp",
"common/unistr_case.cpp",
"common/unistr_case_locale.cpp",
"common/unistr_cnv.cpp",
"common/unistr_props.cpp",
"common/unistr_titlecase_brkiter.cpp",
"common/unorm.cpp",
"common/unormcmp.cpp",
"common/uobject.cpp",
"common/uprops.cpp",
"common/ures_cnv.cpp",
"common/uresbund.cpp",
"common/uresdata.cpp",
"common/usc_impl.cpp",
"common/uscript.cpp",
"common/uscript_props.cpp",
"common/uset.cpp",
"common/uset_props.cpp",
"common/usetiter.cpp",
"common/ushape.cpp",
"common/usprep.cpp",
"common/ustack.cpp",
"common/ustr_cnv.cpp",
"common/ustr_titlecase_brkiter.cpp",
"common/ustr_wcs.cpp",
"common/ustrcase.cpp",
"common/ustrcase_locale.cpp",
"common/ustrenum.cpp",
"common/ustrfmt.cpp",
"common/ustring.cpp",
"common/ustrtrns.cpp",
"common/utext.cpp",
"common/utf_impl.cpp",
"common/util.cpp",
"common/util_props.cpp",
"common/utrace.cpp",
"common/utrie.cpp",
"common/utrie2.cpp",
"common/utrie2_builder.cpp",
"common/utrie_swap.cpp",
"common/uts46.cpp",
"common/utypes.cpp",
"common/uvector.cpp",
"common/uvectr32.cpp",
"common/uvectr64.cpp",
"common/wintz.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
thirdparty_sources += ["icu_data/icudata_stub.cpp"]
env_icu.Append(CPPPATH=["#thirdparty/icu4c/common/"])
env_icu.Append(
CXXFLAGS=["-DU_STATIC_IMPLEMENTATION", "-DU_COMMON_IMPLEMENTATION", "-DPKGDATA_MODE=static",]
)
env_icu.disable_warnings()
env_thirdparty = env_icu.Clone()
env_thirdparty.disable_warnings()
lib = env_thirdparty.add_library("icu_builtin", thirdparty_sources)
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
# LIBS contains first SCons Library objects ("SCons.Node.FS.File object")
# and then plain strings for system library. We insert between the two.
inserted = False
for idx, linklib in enumerate(env["LIBS"]):
if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
env["LIBS"].insert(idx, lib)
inserted = True
break
if not inserted:
env.Append(LIBS=[lib])
env_text_server_adv = env_modules.Clone()
env_text_server_adv.Append(
CPPPATH=[
"#thirdparty/harfbuzz/src",
"#thirdparty/freetype/include",
"#thirdparty/graphite/include",
"#thirdparty/icu4c/common/",
]
)
env_text_server_adv.add_source_files(env.modules_sources, "*.cpp")

View File

@ -0,0 +1,5 @@
def can_build(env, platform):
return True
def configure(env):
pass

View File

@ -0,0 +1,63 @@
/*************************************************************************/
/* icudata_stub.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "unicode/udata.h"
#include "unicode/utypes.h"
#include "unicode/uversion.h"
typedef struct {
uint16_t header_size;
uint8_t magic_1, magic_2;
UDataInfo info;
char padding[8];
uint32_t count, reserved;
int fake_name_and_data[4];
} ICU_data_header;
extern "C" U_EXPORT const ICU_data_header U_ICUDATA_ENTRY_POINT = {
32,
0xDA, 0x27,
{ sizeof(UDataInfo),
0,
#if U_IS_BIG_ENDIAN
1,
#else
0,
#endif
U_CHARSET_FAMILY,
sizeof(UChar),
0,
{ 0x54, 0x6F, 0x43, 0x50 },
{ 1, 0, 0, 0 },
{ 0, 0, 0, 0 } },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
0, 0,
{ 0, 0, 0, 0 }
};

View File

@ -215,7 +215,7 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
# Disable exceptions and rtti on non-tools (template) builds
if env["tools"]:
if env["tools"] or env["builtin_icu"]:
env.Append(CXXFLAGS=["-frtti"])
else:
env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])

View File

@ -71,6 +71,8 @@ def configure(env):
)
# Tools need more memory. Initial stack memory in bytes. See `src/settings.js` in emscripten repository (will be renamed to INITIAL_MEMORY).
env.Append(LINKFLAGS=["-s", "TOTAL_MEMORY=33554432"])
elif env["builtin_icu"]:
env.Append(CCFLAGS=["-frtti"])
else:
# Disable exceptions and rtti on non-tools (template) builds
# These flags help keep the file size down.

View File

@ -205,14 +205,31 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
if (
env["builtin_freetype"]
or env["builtin_libpng"]
or env["builtin_zlib"]
or env["builtin_graphite"]
or env["builtin_harfbuzz"]
):
env["builtin_freetype"] = True
env["builtin_libpng"] = True
env["builtin_zlib"] = True
env["builtin_graphite"] = True
env["builtin_harfbuzz"] = True
if not env["builtin_freetype"]:
env.ParseConfig("pkg-config freetype2 --cflags --libs")
if not env["builtin_graphite"]:
env.ParseConfig("pkg-config graphite2 --cflags --libs")
if not env["builtin_icu"]:
env.ParseConfig("pkg-config icu-uc --cflags --libs")
if not env["builtin_harfbuzz"]:
env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs")
if not env["builtin_libpng"]:
env.ParseConfig("pkg-config libpng16 --cflags --libs")

View File

@ -138,14 +138,31 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
if (
env["builtin_freetype"]
or env["builtin_libpng"]
or env["builtin_zlib"]
or env["builtin_graphite"]
or env["builtin_harfbuzz"]
):
env["builtin_freetype"] = True
env["builtin_libpng"] = True
env["builtin_zlib"] = True
env["builtin_graphite"] = True
env["builtin_harfbuzz"] = True
if not env["builtin_freetype"]:
env.ParseConfig("pkg-config freetype2 --cflags --libs")
if not env["builtin_graphite"]:
env.ParseConfig("pkg-config graphite2 --cflags --libs")
if not env["builtin_icu"]:
env.ParseConfig("pkg-config icu-uc --cflags --libs")
if not env["builtin_harfbuzz"]:
env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs")
if not env["builtin_libpng"]:
env.ParseConfig("pkg-config libpng16 --cflags --libs")
@ -233,7 +250,17 @@ def configure(env):
env.Append(CPPDEFINES=["SERVER_ENABLED", "UNIX_ENABLED"])
if platform.system() == "Darwin":
env.Append(LINKFLAGS=["-framework", "Cocoa", "-framework", "Carbon", "-lz", "-framework", "IOKit"])
env.Append(
LINKFLAGS=[
"-framework",
"Cocoa",
"-framework",
"Carbon",
"-lz",
"-framework",
"IOKit",
]
)
env.Append(LIBS=["pthread"])

33
thirdparty/README.md vendored
View File

@ -184,6 +184,39 @@ Files extracted from upstream source:
Patches in the `patches` directory should be re-applied after updates.
## Graphite engine
- Upstream: https://github.com/silnrsi/graphite
- Version: 1.3.14
- License: MPL-2.0
Files extracted from upstream source:
- the `include` folder
- the `src` folder
- `COPYING`, `ChangeLog`
## HarfBuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 2.7.2
- License: HarfBuzz
Files extracted from upstream source:
- the `src` folder
- `AUTHORS`, `COPYING`, `NEWS`, `THANKS`
## International Components for Unicode
- Upstream: https://github.com/unicode-org/icu
- Version: 68.1
- License: Unicode
Files extracted from upstream source:
- the `common` folder
- `APIChangeReport.md`, `LICENSE`
Files generated from upstream source:
- the `icudt68l.dat` built with the provided `godot_data.json` config file (see https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md for instructions)
## jpeg-compressor

26
thirdparty/graphite/COPYING vendored Normal file
View File

@ -0,0 +1,26 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, you may use this library under the terms of the Mozilla
Public License (http://mozilla.org/MPL) or under the GNU General Public
License, as published by the Free Sofware Foundation; either version
2 of the license or (at your option) any later version.
*/

238
thirdparty/graphite/ChangeLog vendored Normal file
View File

@ -0,0 +1,238 @@
1.3.14
. Bug fixes
. Allow features to be hidden (for aliases)
. Move to python3
. Rename doc files from .txt to .asc
1.3.13
. Resolve minor spacing issue in rtl non-overlap kerning
. python3 for graphite.py
. Better fuzzing
. Better building on windows
1.3.12
. Graphite no longer does dumb rendering for fonts with no smarts
. Segment caching code removed. Anything attempting to use the segment cache gets given a regular face instead
. Add libfuzzer support
. Builds now require C++11
. Improvements to Windows 64 bit builds
. Support different versions of python including 32 bit and python 3
. Various minor bug fixes
1.3.11
. Fixes due to security review
. Minor collision avoidance fixes
. Fix LZ4 decompressor against high compression
1.3.10
. Address floating point build parameters to give consistent positioning results across platforms
. Various bug fixes
1.3.9
. Add Collision COLL_ISSPACE to allow for visible spaces in collision avoidance
. Add segment and pass direction information to tracing output
. Bug fix rule length testing in 32-bit
. Increase slanted margin distances for collision avoidance
. Change kerning algorithm to simple outline expansion. Seems to make no visible difference.
. Add trace2svg to test tools
1.3.8
. Various bug fixes arising from fuzzing
. Fix regression that stopped piglatin from working
. Make collision avoidance kerning give more regular results
. Minor modification to clustering algorithm to handle variable width chars
1.3.7
. Bug fixes
. Start to deprecate SegCache. This will be going away in a later release.
1.3.6
. Bug fixes
1.3.5
. Bug fixes
. Security bug fix
. Fix ARM misalignment problem
. Track latest cmake
1.3.4
. Transition from Mercurial to Git
. Bug fixes
. Fix Collision Kerning ignoring some diacritics
. Handle pass bits 16-31 to speed up fonts with > 16 passes
. Various minor fuzz bug fixes
. Make Coverity happy
. Add GR_FALLTHROUGH macro for clang c++11
1.3.3
. Slight speed up in Collision Avoidance
. Remove dead bidi code
. Bug fixes
. Between pass bidi reorderings and at the end
. Decompressor fuzz bugs
. Other fuzz bugs
1.3.2
. Remove full bidi. All segments are assumed to be single directioned.
. Bug fixes:
. Decompressor corner cases
. Various fuzz bugs
1.3.1
. Deprecation warning: Full bidi support is about to be deprecated. Make contact
if this impacts you.
. Change compression block format slightly to conform to LZ4
. Bug fixes:
. Handle mono direction text with diacritics consistently. Fonts
now see the direction they expect consistently and bidi now
gives expected results.
. Fixed lots of fuzz bugs
. Coverity cleanups
. Build now works for clang and/or asan and/or afl etc.
1.3.0
. Add collision avoidance
. Shift Collider
. Kern Collider
. Octabox outlines and subboxes
. Add compressed Silf and Glat table support
. Bug fixes:
. Stop loops forming in the child, sibling tree
. Handle bidi mirroring correctly if no bidi occurring
1.2.4
. Face failure now has error code reporting via debug logging
. can now call gr_start_logging(NULL, fname)
. gr2fonttest --alltrace added
. Format 14 table support
. Not done. To be handled entirely in the compiler
. Bidi support for Unicode 6.3 Isolating direction controls
. Fonts no longer require a glyf/loca table. In such cases the bounding box is always 0.
. Clang ASAN build support added for testing.
. Handle out of memory sanely.
. Documentation improvements
. Bug fixes:
. Enforce fonts having to store glyph attributes by monotonically increasing attribute number
. zeropadding was not getting called on feature tags
. automatic associations for unassociated characters
. use direct engine on Mac
. various extreme case reading 1 past the end errors fixed
. remove tabs from sources so that it becomes readable again
1.2.3
. Bug fixes only:
. fix byte swapping when testing cmap subtable lengths
. work around armel compilation problems with conditional operators
. fix pseudoglyph support for advance and bbox
1.2.2
. Add support for passKeySlot (makes Charis 2x faster) up to 32 passes
. Add telemetry output to json if enabled in build GRAPHITE2_TELEMETRY
. Shrink font memory footprint particularly in the fsm
. Add -S to comparerenderer
. Bug fixes:
. Fix shift.x being reversed for rtl text
. Fix faulty fallback justification
. Fix bad cmap handling
. Support compiling on old Solaris where bidi attributes clash with register names
. Follow the crowd in using Windows.h
1.2.1
. Bug fixes:
. Allow glyph reattachment
. Allow signed glyph attributes
. Various build problems with MacOS, old gcc versions, etc.
. Various overrun read errors fixed
1.2.0
. API Changes:
. Added Windows friendly gr_start_logging and gr_stop_logging, now per face
. Added gr_make_face_with_ops, gr_make_face_with_seg_cache_and_ops
. Added gr_make_font_with_ops
. Added gr_face_is_char_supported
. Added gr_face_info to give info to apps about face capabilities
. Deprecated gr_make_face, gr_make_face_with_seg_cache, gr_make_font_with_advance_fn
. Deprecated graphite_start_logging and graphite_stop_logging
. These functions are stubbed now and do nothing, but do compile and link.
. Bump API version to 3
. Add C# wrapper to contrib
. Handle justification information in a font and do something useful with it
. Builds clang clean (has done for a while)
. Bug fixes
. Windows build and bug fixes
. Add extra information to json debug output
. Added windows build documentation
. Added freetype sample code and test
1.1.3
. Default build has GRAPHITE2_COMPARE_RENDERER to OFF to reduce dependencies
. Builds on Mac with clang
. Debug output improvements
. Tidy up perl wrappers
. Fuzz tester improvements
. Various bug fixes for bad font handling
1.1.2
. Support feature ids < 4 chars when space padded for inclusion in FF 14.
. More fuzztesting and removal of causes of valgrind bad reads and sigabrts
. Remove contrib/android into its own repo (http://hg.palaso.org/grandroid)
. Update comparerenderer to latest harfbuzzng api
1.1.1
. Missing Log.h included
. perl wrappers updated
1.1.0
. Refactored debug output to use json
. Renamed VM_MACHINE_TYPE to GRAPHITE2_VM_TYPE
. Renamed DISABLE_SEGCACHE to GRAPHITE2_NSEGCACE
. Renamed DISBALE_FILE_FACE to GRAPHITE2_NFILEFACE
. Renamed ENABLE_COMPARE_RENDERER to GRAPHTIE2_COMPARE_RENDERER
. Renamed DOXYGEN_CONFIG to GRAPHITE2_DOXYGEN_CONFIG
. Renamed GR2_CUSTOM_HEADER to GRAPHITE2_CUSTOM_HEADER
. Renamed GR2_EXPORTING to GRAPHITE2_EXPORTING
. Added GRAPHITE2_STATIC for static only builds
. Added GRAPHITE2_NTRACING to compile out tracing code
. Documented GRAPHITE2_{EXPORTING,STATIC,NTRACING} in hacking.txt
. Bump libtool version to 2.1.0
. dumb font rendering works
. slot user attributes are now signed rather than unsigned
. add support for long class maps
. Rename perl library to avoid nameclash on Windows
. Various robustness fixes
. Moved internal .h files into src/inc
. Parallelise fuzztest
. General build improvements, particularly on Windows
1.0.3
. Fix UTF16 surrogate support
. script and lang tags may be space padded or null padded
. Remove need for WORDS_BIGENDIAN, do it all automatically
. Remove all #include <new>. Use CLASS_NEW_DELETE instead.
. Fix comparerenderer to work with current hbng
. Add valgrind to fuzztest to ensure good memory use at all times
. Fix new fuzztest exposed bugs.
. Fix bugs exposed by Mozilla security review
. Add continuous integration build on Windows support
1.0.2
. Fix Windows build
. Comparerenderer uses hbng enforcing ot rendering
. Add Bidi .hasChar support and refactor mirroring code
. Make cmake default Release rather than debug
. Don't compile in a boat load of TtfUtil that isn't used, saving 15% of binary
. Chase the FSF around its latest office moves
. WORDS_BIGENDIAN is set at the top so tests now pass on ppc, etc.
. More words in the manual
1.0.1
. Release is the default build in cmake now.
. Refactor cmake build to not rebuild things so much.
. Include a missing file
. Remove -nostdlibs, making gcc happy everywhere
. Update comparerenderer to latest hbng interface
. Add changelog
1.0.0
. First major release of perfect code!

View File

@ -0,0 +1,389 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms
of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
General Public License, as published by the Free Software Foundation,
either version 2 of the License or (at your option) any later version.
*/
#pragma once
#include "graphite2/Types.h"
#define GR2_VERSION_MAJOR 1
#define GR2_VERSION_MINOR 3
#define GR2_VERSION_BUGFIX 14
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct gr_face gr_face;
typedef struct gr_font gr_font;
typedef struct gr_feature_ref gr_feature_ref;
typedef struct gr_feature_val gr_feature_val;
/**
* Returns version information on this engine
*/
GR2_API void gr_engine_version(int *nMajor, int *nMinor, int *nBugFix);
/**
* The Face Options allow the application to require that certain tables are
* read during face construction. This may be of concern if the appFaceHandle
* used in the gr_get_table_fn may change.
* The values can be combined
*/
enum gr_face_options {
/** No preload, no cmap caching, fail if the graphite tables are invalid */
gr_face_default = 0,
/** Dumb rendering will be enabled if the graphite tables are invalid. @deprecated Since 1.311 */
gr_face_dumbRendering = 1,
/** preload glyphs at construction time */
gr_face_preloadGlyphs = 2,
/** Cache the lookup from code point to glyph ID at construction time */
gr_face_cacheCmap = 4,
/** Preload everything */
gr_face_preloadAll = gr_face_preloadGlyphs | gr_face_cacheCmap
};
/** Holds information about a particular Graphite silf table that has been loaded */
struct gr_faceinfo {
gr_uint16 extra_ascent; /**< The extra_ascent in the GDL, in design units */
gr_uint16 extra_descent; /**< The extra_descent in the GDL, in design units */
gr_uint16 upem; /**< The design units for the font */
enum gr_space_contextuals {
gr_space_unknown = 0, /**< no information is known. */
gr_space_none = 1, /**< the space character never occurs in any rules. */
gr_space_left_only = 2, /**< the space character only occurs as the first element in a rule. */
gr_space_right_only = 3, /**< the space character only occurs as the last element in a rule. */
gr_space_either_only = 4, /**< the space character only occurs as the only element in a rule. */
gr_space_both = 5, /**< the space character may occur as the first or last element of a rule. */
gr_space_cross = 6 /**< the space character occurs in a rule not as a first or last element. */
} space_contextuals;
unsigned int has_bidi_pass : 1; /**< the table specifies that a bidirectional pass should run */
unsigned int line_ends : 1; /**< there are line end contextuals somewhere */
unsigned int justifies : 1; /**< there are .justify properties set somewhere on some glyphs */
};
typedef struct gr_faceinfo gr_faceinfo;
/** type describing function to retrieve font table information
*
* @return a pointer to the table in memory. The pointed to memory must exist as
* long as the gr_face which makes the call.
* @param appFaceHandle is the unique information passed to gr_make_face()
* @param name is a 32bit tag to the table name.
* @param len returned by this function to say how long the table is in memory.
*/
typedef const void *(*gr_get_table_fn)(const void* appFaceHandle, unsigned int name, size_t *len);
/** type describing function to release any resources allocated by the above get_table table function
*
* @param appFaceHandle is the unique information passed to gr_make_face()
* @param pointer to table memory returned by get_table.
*/
typedef void (*gr_release_table_fn)(const void* appFaceHandle, const void *table_buffer);
/** struct housing function pointers to manage font table buffers for the graphite engine. */
struct gr_face_ops
{
/** size in bytes of this structure */
size_t size;
/** a pointer to a function to request a table from the client. */
gr_get_table_fn get_table;
/** is a pointer to a function to notify the client the a table can be released.
* This can be NULL to signify that the client does not wish to do any release handling. */
gr_release_table_fn release_table;
};
typedef struct gr_face_ops gr_face_ops;
/** Create a gr_face object given application information and a table functions.
*
* @return gr_face or NULL if the font fails to load for some reason.
* @param appFaceHandle This is application specific information that is passed
* to the getTable function. The appFaceHandle must stay
* alive as long as the gr_face is alive.
* @param face_ops Pointer to face specific callback structure for table
* management. Must stay alive for the duration of the
* call only.
* @param faceOptions Bitfield describing various options. See enum gr_face_options for details.
*/
GR2_API gr_face* gr_make_face_with_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *face_ops, unsigned int faceOptions);
/** @deprecated Since v1.2.0 in favour of gr_make_face_with_ops.
* Create a gr_face object given application information and a getTable function.
*
* @return gr_face or NULL if the font fails to load for some reason.
* @param appFaceHandle This is application specific information that is passed
* to the getTable function. The appFaceHandle must stay
* alive as long as the gr_face is alive.
* @param getTable Callback function to get table data.
* @param faceOptions Bitfield describing various options. See enum gr_face_options for details.
*/
GR2_DEPRECATED_API gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn getTable, unsigned int faceOptions);
/** @deprecated Since 1.3.7 this function is now an alias for gr_make_face_with_ops().
*
* Create a gr_face object given application information, with subsegmental caching support
*
* @return gr_face or NULL if the font fails to load.
* @param appFaceHandle is a pointer to application specific information that is passed to getTable.
* This may not be NULL and must stay alive as long as the gr_face is alive.
* @param face_ops Pointer to face specific callback structure for table management. Must stay
* alive for the duration of the call only.
* @param segCacheMaxSize Unused.
* @param faceOptions Bitfield of values from enum gr_face_options
*/
GR2_DEPRECATED_API gr_face* gr_make_face_with_seg_cache_and_ops(const void* appFaceHandle, const gr_face_ops *face_ops, unsigned int segCacheMaxSize, unsigned int faceOptions);
/** @deprecated Since 1.3.7 this function is now an alias for gr_make_face().
*
* Create a gr_face object given application information, with subsegmental caching support.
* This function is deprecated as of v1.2.0 in favour of gr_make_face_with_seg_cache_and_ops.
*
* @return gr_face or NULL if the font fails to load.
* @param appFaceHandle is a pointer to application specific information that is passed to getTable.
* This may not be NULL and must stay alive as long as the gr_face is alive.
* @param getTable The function graphite calls to access font table data
* @param segCacheMaxSize How large the segment cache is.
* @param faceOptions Bitfield of values from enum gr_face_options
*/
GR2_DEPRECATED_API gr_face* gr_make_face_with_seg_cache(const void* appFaceHandle, gr_get_table_fn getTable, unsigned int segCacheMaxSize, unsigned int faceOptions);
/** Convert a tag in a string into a gr_uint32
*
* @return gr_uint32 tag, zero padded
* @param str a nul terminated string of which at most the first 4 characters are read
*/
GR2_API gr_uint32 gr_str_to_tag(const char *str);
/** Convert a gr_uint32 tag into a string
*
* @param tag contains the tag to convert
* @param str is a pointer to a char array of at least size 4 bytes. The first 4 bytes of this array
* will be overwritten by this function. No nul is appended.
*/
GR2_API void gr_tag_to_str(gr_uint32 tag, char *str);
/** Get feature values for a given language or default
*
* @return a copy of the default feature values for a given language. The application must call
* gr_featureval_destroy() to free this object when done.
* @param pFace The font face to get feature values from
* @param langname The language tag to get feature values for. If there is no such language or
* langname is 0, the default feature values for the font are returned.
* langname is right 0 padded and assumes lowercase. Thus the en langauge
* would be 0x656E0000. Langname may also be space padded, thus 0x656E2020.
*/
GR2_API gr_feature_val* gr_face_featureval_for_lang(const gr_face* pFace, gr_uint32 langname);
/** Get feature reference for a given feature id from a face
*
* @return a feature reference corresponding to the given id. This data is part of the gr_face and
* will be freed when the face is destroyed.
* @param pFace Font face to get information on.
* @param featId Feature id tag to get reference to.
*/
GR2_API const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId);
/** Returns number of feature references in a face **/
GR2_API gr_uint16 gr_face_n_fref(const gr_face* pFace);
/** Returns feature reference at given index in face **/
GR2_API const gr_feature_ref* gr_face_fref(const gr_face* pFace, gr_uint16 i);
/** Return number of languages the face knows about **/
GR2_API unsigned short gr_face_n_languages(const gr_face* pFace);
/** Returns a language id corresponding to a language of given index in the face **/
GR2_API gr_uint32 gr_face_lang_by_index(const gr_face* pFace, gr_uint16 i);
/** Destroy the given face and free its memory **/
GR2_API void gr_face_destroy(gr_face *face);
/** Returns the number of glyphs in the face **/
GR2_API unsigned short gr_face_n_glyphs(const gr_face* pFace);
/** Returns a faceinfo for the face and script **/
GR2_API const gr_faceinfo *gr_face_info(const gr_face *pFace, gr_uint32 script);
/** Returns whether the font supports a given Unicode character
*
* @return true if the character is supported.
* @param pFace face to test within
* @param usv Unicode Scalar Value of character to test
* @param script Tag of script for selecting which set of pseudo glyphs to test. May be NULL.
*/
GR2_API int gr_face_is_char_supported(const gr_face *pFace, gr_uint32 usv, gr_uint32 script);
#ifndef GRAPHITE2_NFILEFACE
/** Create gr_face from a font file
*
* @return gr_face that accesses a font file directly. Returns NULL on failure.
* @param filename Full path and filename to font file
* @param faceOptions Bitfile from enum gr_face_options to control face options.
*/
GR2_API gr_face* gr_make_file_face(const char *filename, unsigned int faceOptions);
/** @deprecated Since 1.3.7. This function is now an alias for gr_make_file_face().
*
* Create gr_face from a font file, with subsegment caching support.
*
* @return gr_face that accesses a font file directly. Returns NULL on failure.
* @param filename Full path and filename to font file
* @param segCacheMaxSize Specifies how big to make the cache in segments.
* @param faceOptions Bitfield from enum gr_face_options to control face options.
*/
GR2_DEPRECATED_API gr_face* gr_make_file_face_with_seg_cache(const char *filename, unsigned int segCacheMaxSize, unsigned int faceOptions);
#endif // !GRAPHITE2_NFILEFACE
/** Create a font from a face
*
* @return gr_font Call font_destroy to free this font
* @param ppm Resolution of the font in pixels per em
* @param face Face this font corresponds to. This must stay alive as long as the font is alive.
*/
GR2_API gr_font* gr_make_font(float ppm, const gr_face *face);
/** query function to find the hinted advance of a glyph
*
* @param appFontHandle is the unique information passed to gr_make_font_with_advance()
* @param glyphid is the glyph to retireve the hinted advance for.
*/
typedef float (*gr_advance_fn)(const void* appFontHandle, gr_uint16 glyphid);
/** struct housing function pointers to manage font hinted metrics for the
* graphite engine. */
struct gr_font_ops
{
/** size of the structure in bytes to allow for future extensibility */
size_t size;
/** a pointer to a function to retrieve the hinted
* advance width of a glyph which the font cannot
* provide without client assistance. This can be
* NULL to signify no horizontal hinted metrics are necessary. */
gr_advance_fn glyph_advance_x;
/** a pointer to a function to retrieve the hinted
* advance height of a glyph which the font cannot
* provide without client assistance. This can be
* NULL to signify no horizontal hinted metrics are necessary. */
gr_advance_fn glyph_advance_y;
};
typedef struct gr_font_ops gr_font_ops;
/** Creates a font with hinted advance width query functions
*
* @return gr_font to be destroyed via font_destroy
* @param ppm size of font in pixels per em
* @param appFontHandle font specific information that must stay alive as long
* as the font does
* @param font_ops pointer font specific callback structure for hinted metrics.
* Need only stay alive for the duration of the call.
* @param face the face this font corresponds to. Must stay alive as long as
* the font does.
*/
GR2_API gr_font* gr_make_font_with_ops(float ppm, const void* appFontHandle, const gr_font_ops * font_ops, const gr_face *face);
/** Creates a font with hinted advance width query function.
* This function is deprecated. Use gr_make_font_with_ops instead.
*
* @return gr_font to be destroyed via font_destroy
* @param ppm size of font in pixels per em
* @param appFontHandle font specific information that must stay alive as long
* as the font does
* @param getAdvance callback function reference that returns horizontal advance in pixels for a glyph.
* @param face the face this font corresponds to. Must stay alive as long as
* the font does.
*/
GR2_API gr_font* gr_make_font_with_advance_fn(float ppm, const void* appFontHandle, gr_advance_fn getAdvance, const gr_face *face);
/** Free a font **/
GR2_API void gr_font_destroy(gr_font *font);
/** get a feature value
*
* @return value of specific feature or 0 if any problems.
* @param pfeatureref gr_feature_ref to the feature
* @param feats gr_feature_val containing all the values
*/
GR2_API gr_uint16 gr_fref_feature_value(const gr_feature_ref* pfeatureref, const gr_feature_val* feats);
/** set a feature value
*
* @return false if there were any problems (value out of range, etc.)
* @param pfeatureref gr_feature_ref to the feature
* @param val value to set the feature to
* @param pDest the gr_feature_val containing all the values for all the features
*/
GR2_API int gr_fref_set_feature_value(const gr_feature_ref* pfeatureref, gr_uint16 val, gr_feature_val* pDest);
/** Returns the id tag for a gr_feature_ref **/
GR2_API gr_uint32 gr_fref_id(const gr_feature_ref* pfeatureref);
/** Returns number of values a feature may take, given a gr_feature_ref **/
GR2_API gr_uint16 gr_fref_n_values(const gr_feature_ref* pfeatureref);
/** Returns the value associated with a particular value in a feature
*
* @return value
* @param pfeatureref gr_feature_ref of the feature of interest
* @param settingno Index up to the return value of gr_fref_n_values() of the value
*/
GR2_API gr_int16 gr_fref_value(const gr_feature_ref* pfeatureref, gr_uint16 settingno);
/** Returns a string of the UI name of a feature
*
* @return string of the UI name, in the encoding form requested. Call gr_label_destroy() after use.
* @param pfeatureref gr_feature_ref of the feature
* @param langId This is a pointer since the face may not support a string in the requested
* language. The actual language of the string is returned in langId
* @param utf Encoding form for the string
* @param length Used to return the length of the string returned in bytes.
*/
GR2_API void* gr_fref_label(const gr_feature_ref* pfeatureref, gr_uint16 *langId, enum gr_encform utf, gr_uint32 *length);
/** Return a UI string for a possible value of a feature
*
* @return string of the UI name, in the encoding form requested. nul terminated. Call gr_label_destroy()
* after use.
* @param pfeatureref gr_feature_ref of the feature
* @param settingno Value setting index
* @param langId This is a pointer to the requested language. The requested language id is
* replaced by the actual language id of the string returned.
* @param utf Encoding form for the string
* @param length Returns the length of the string returned in bytes.
*/
GR2_API void* gr_fref_value_label(const gr_feature_ref* pfeatureref, gr_uint16 settingno/*rather than a value*/, gr_uint16 *langId, enum gr_encform utf, gr_uint32 *length);
/** Destroy a previously returned label string **/
GR2_API void gr_label_destroy(void * label);
/** Copies a gr_feature_val **/
GR2_API gr_feature_val* gr_featureval_clone(const gr_feature_val* pfeatures);
/** Destroys a gr_feature_val **/
GR2_API void gr_featureval_destroy(gr_feature_val *pfeatures);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,85 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms
of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
General Public License, as published by the Free Software Foundation,
either version 2 of the License or (at your option) any later version.
*/
#pragma once
#include <graphite2/Types.h>
#include <graphite2/Font.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#endif
/** deprecated mechanism that doesn't do anything now. */
typedef enum {
GRLOG_NONE = 0x0,
GRLOG_FACE = 0x01,
GRLOG_SEGMENT = 0x02,
GRLOG_PASS = 0x04,
GRLOG_CACHE = 0x08,
GRLOG_OPCODE = 0x80,
GRLOG_ALL = 0xFF
} GrLogMask;
/** Start logging all segment creation and updates on the provided face. This
* is logged to a JSON file, see "Segment JSON Schema.txt" for a precise
* definition of the file
*
* @return true if the file was successfully created and logging is correctly
* initialised.
* @param face the gr_face whose segments you want to log to the given file
* @param log_path a utf8 encoded file name and path to log to.
*/
GR2_API bool gr_start_logging(gr_face * face, const char *log_path);
/** Stop logging on the given face. This will close the log file created by
* gr_start_logging.
*
* @param face the gr_face whose segments you want to stop logging
*/
GR2_API void gr_stop_logging(gr_face * face);
/** Start logging to a FILE object.
* This function is deprecated as of 1.2.0, use the _face versions instead.
*
* @return True on success
* @param logfile FILE reference to output logging to
* @param mask What aspects of logging to report (ignored)
*/
GR2_API bool graphite_start_logging(FILE * logFile, GrLogMask mask); //may not do anthing if disabled in the implementation of the engine.
/** Stop logging to a FILE object.
* This function is deprecated as of 1.2.0, use the _face versions instead.
*/
GR2_API void graphite_stop_logging();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,461 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms
of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
General Public License, as published by the Free Software Foundation,
either version 2 of the License or (at your option) any later version.
*/
#pragma once
#include "graphite2/Types.h"
#include "graphite2/Font.h"
#ifdef __cplusplus
extern "C"
{
#endif
enum gr_break_weight {
gr_breakNone = 0,
/* after break weights */
gr_breakWhitespace = 10,
gr_breakWord = 15,
gr_breakIntra = 20,
gr_breakLetter = 30,
gr_breakClip = 40,
/* before break weights */
gr_breakBeforeWhitespace = -10,
gr_breakBeforeWord = -15,
gr_breakBeforeIntra = -20,
gr_breakBeforeLetter = -30,
gr_breakBeforeClip = -40
};
enum gr_justFlags {
/// Indicates that this segment is a complete line
gr_justCompleteLine = 0,
/// Indicates that the start of the slot list is not at the start of a line
gr_justStartInline = 1,
/// Indicates that the end of the slot list is not at the end of a line
gr_justEndInline = 2
};
/** Used for looking up slot attributes. Most are already available in other functions **/
enum gr_attrCode {
/// adjusted glyph advance in x direction in design units
gr_slatAdvX = 0,
/// adjusted glyph advance in y direction (usually 0) in design units
gr_slatAdvY,
/// returns 0. Deprecated.
gr_slatAttTo,
/// This slot attaches to its parent at the given design units in the x direction
gr_slatAttX,
/// This slot attaches to its parent at the given design units in the y direction
gr_slatAttY,
/// This slot attaches to its parent at the given glyph point (not implemented)
gr_slatAttGpt,
/// x-direction adjustment from the given glyph point (not implemented)
gr_slatAttXOff,
/// y-direction adjustment from the given glyph point (not implemented)
gr_slatAttYOff,
/// Where on this glyph should align with the attachment point on the parent glyph in the x-direction.
gr_slatAttWithX,
/// Where on this glyph should align with the attachment point on the parent glyph in the y-direction
gr_slatAttWithY,
/// Which glyph point on this glyph should align with the attachment point on the parent glyph (not implemented).
gr_slatWithGpt,
/// Adjustment to gr_slatWithGpt in x-direction (not implemented)
gr_slatAttWithXOff,
/// Adjustment to gr_slatWithGpt in y-direction (not implemented)
gr_slatAttWithYOff,
/// Attach at given nesting level (not implemented)
gr_slatAttLevel,
/// Line break breakweight for this glyph
gr_slatBreak,
/// Ligature component reference (not implemented)
gr_slatCompRef,
/// bidi directionality of this glyph (not implemented)
gr_slatDir,
/// Whether insertion is allowed before this glyph
gr_slatInsert,
/// Final positioned position of this glyph relative to its parent in x-direction in pixels
gr_slatPosX,
/// Final positioned position of this glyph relative to its parent in y-direction in pixels
gr_slatPosY,
/// Amount to shift glyph by in x-direction design units
gr_slatShiftX,
/// Amount to shift glyph by in y-direction design units
gr_slatShiftY,
/// attribute user1
gr_slatUserDefnV1,
/// not implemented
gr_slatMeasureSol,
/// not implemented
gr_slatMeasureEol,
/// Amount this slot can stretch (not implemented)
gr_slatJStretch,
/// Amount this slot can shrink (not implemented)
gr_slatJShrink,
/// Granularity by which this slot can stretch or shrink (not implemented)
gr_slatJStep,
/// Justification weight for this glyph (not implemented)
gr_slatJWeight,
/// Amount this slot mush shrink or stretch in design units
gr_slatJWidth = 29,
/// SubSegment split point
gr_slatSegSplit = gr_slatJStretch + 29,
/// User defined attribute, see subattr for user attr number
gr_slatUserDefn,
/// Bidi level
gr_slatBidiLevel = 56,
/// Collision flags
gr_slatColFlags,
/// Collision constraint rectangle left (bl.x)
gr_slatColLimitblx,
/// Collision constraint rectangle lower (bl.y)
gr_slatColLimitbly,
/// Collision constraint rectangle right (tr.x)
gr_slatColLimittrx,
/// Collision constraint rectangle upper (tr.y)
gr_slatColLimittry,
/// Collision shift x
gr_slatColShiftx,
/// Collision shift y
gr_slatColShifty,
/// Collision margin
gr_slatColMargin,
/// Margin cost weight
gr_slatColMarginWt,
// Additional glyph that excludes movement near this one:
gr_slatColExclGlyph,
gr_slatColExclOffx,
gr_slatColExclOffy,
// Collision sequence enforcing attributes:
gr_slatSeqClass,
gr_slatSeqProxClass,
gr_slatSeqOrder,
gr_slatSeqAboveXoff,
gr_slatSeqAboveWt,
gr_slatSeqBelowXlim,
gr_slatSeqBelowWt,
gr_slatSeqValignHt,
gr_slatSeqValignWt,
/// not implemented
gr_slatMax,
/// not implemented
gr_slatNoEffect = gr_slatMax + 1
};
enum gr_bidirtl {
/// Underlying paragraph direction is RTL
gr_rtl = 1,
/// Set this to not run the bidi pass internally, even if the font asks for it.
/// This presumes that the segment is in a single direction. Most of the time
/// this bit should be set unless you know you are passing full paragraphs of text.
gr_nobidi = 2,
/// Disable auto mirroring for rtl text
gr_nomirror = 4
};
typedef struct gr_char_info gr_char_info;
typedef struct gr_segment gr_segment;
typedef struct gr_slot gr_slot;
/** Returns Unicode character for a charinfo.
*
* @param p Pointer to charinfo to return information on.
*/
GR2_API unsigned int gr_cinfo_unicode_char(const gr_char_info* p/*not NULL*/);
/** Returns breakweight for a charinfo.
*
* @return Breakweight is a number between -50 and 50 indicating the cost of a
* break before or after this character. If the value < 0, the absolute value
* is this character's contribution to the overall breakweight before it. If the value
* > 0, then the value is this character's contribution to the overall breakweight after it.
* The overall breakweight between two characters is the maximum of the breakweight
* contributions from the characters either side of it. If a character makes no
* contribution to the breakweight on one side of it, the contribution is considered
* to be 0.
* @param p Pointer to charinfo to return information on.
*/
GR2_API int gr_cinfo_break_weight(const gr_char_info* p/*not NULL*/);
/** Returns the slot index that after this character is after in the slot stream
*
* In effect each character is associated with a set of slots and this returns
* the index of the last slot in the segment this character is associated with.
*
* @return after slot index between 0 and gr_seg_n_slots()
* @param p Pointer to charinfo to return information on.
*/
GR2_API int gr_cinfo_after(const gr_char_info* p/*not NULL*/);
/** Returns the slot index that before this character is before in the slot stream
*
* In effect each character is associated with a set of slots and this returns
* the index of the first slot in the segment this character is associated with.
*
* @return before slot index between 0 and gr_seg_n_slots()
* @param p Pointer to charinfo to return information on.
*/
GR2_API int gr_cinfo_before(const gr_char_info* p/*not NULL*/);
/** Returns the code unit index of this character in the input string
*
* @return code unit index between 0 and the end of the string
* @param p Pointer to charinfo to return information on.
*/
GR2_API size_t gr_cinfo_base(const gr_char_info* p/*not NULL*/);
/** Returns the number of unicode characters in a string.
*
* @return number of characters in the string
* @param enc Specifies the type of data in the string: utf8, utf16, utf32
* @param buffer_begin The start of the string
* @param buffer_end Measure up to the first nul or when end is reached, whichever is earliest.
* This parameter may be NULL.
* @param pError If there is a structural fault in the string, the location is returned
* in this variable. If no error occurs, pError will contain NULL. NULL
* may be passed for pError if no such information is required.
*/
GR2_API size_t gr_count_unicode_characters(enum gr_encform enc, const void* buffer_begin, const void* buffer_end, const void** pError);
/** Creates and returns a segment.
*
* @return a segment that needs seg_destroy called on it. May return NULL if bad problems
* in segment processing.
* @param font Gives the size of the font in pixels per em for final positioning. If
* NULL, positions are returned in design units, i.e. at a ppm of the upem
* of the face.
* @param face The face containing all the non-size dependent information.
* @param script This is a tag containing a script identifier that is used to choose
* which graphite table within the font to use. Maybe 0. Tag may be 4 chars
* NULL padded in LSBs or space padded in LSBs.
* @param pFeats Pointer to a feature values to be used for the segment. Only one
* feature values may be used for a segment. If NULL the default features
* for the font will be used.
* @param enc Specifies what encoding form the string is in (utf8, utf16, utf32)
* @param pStart Start of the string
* @param nChars Number of unicode characters to process in the string. The string will
* be processed either up to the first NULL or until nChars have been
* processed. nChars is also used to initialise the internal memory
* allocations of the segment. So it is wise not to make nChars too much
* greater than the actual number of characters being processed.
* @param dir Specifies whether the segment is processed right to left (1) or left to
* right (0) and whether to run the internal bidi pass, if a font requests it.
* See enum gr_bidirtl for details.
*/
GR2_API gr_segment* gr_make_seg(const gr_font* font, const gr_face* face, gr_uint32 script, const gr_feature_val* pFeats, enum gr_encform enc, const void* pStart, size_t nChars, int dir);
/** Destroys a segment, freeing the memory.
*
* @param p The segment to destroy
*/
GR2_API void gr_seg_destroy(gr_segment* p);
/** Returns the advance for the whole segment.
*
* Returns the width of the segment up to the next glyph origin after the segment
*/
GR2_API float gr_seg_advance_X(const gr_segment* pSeg/*not NULL*/);
/** Returns the height advance for the segment. **/
GR2_API float gr_seg_advance_Y(const gr_segment* pSeg/*not NULL*/);
/** Returns the number of gr_char_infos in the segment. **/
GR2_API unsigned int gr_seg_n_cinfo(const gr_segment* pSeg/*not NULL*/);
/** Returns a gr_char_info at a given index in the segment. **/
GR2_API const gr_char_info* gr_seg_cinfo(const gr_segment* pSeg/*not NULL*/, unsigned int index/*must be <number_of_CharInfo*/);
/** Returns the number of glyph gr_slots in the segment. **/
GR2_API unsigned int gr_seg_n_slots(const gr_segment* pSeg/*not NULL*/); //one slot per glyph
/** Returns the first gr_slot in the segment.
*
* The first slot in a segment has a gr_slot_prev_in_segment() of NULL. Slots are owned
* by their segment and are destroyed along with the segment.
*/
GR2_API const gr_slot* gr_seg_first_slot(gr_segment* pSeg/*not NULL*/); //may give a base slot or a slot which is attached to another
/** Returns the last gr_slot in the segment.
*
* The last slot in a segment has a gr_slot_next_in_segment() of NULL
*/
GR2_API const gr_slot* gr_seg_last_slot(gr_segment* pSeg/*not NULL*/); //may give a base slot or a slot which is attached to another
/** Justifies a linked list of slots for a line to a given width
*
* Passed a pointer to the start of a linked list of slots corresponding to a line, as
* set up by gr_slot_linebreak_before, this function will position the glyphs in the line
* to take up the given width. It is possible to specify a subrange within the line to process.
* This allows skipping of line initial or final whitespace, for example. While this will ensure
* that the subrange fits width, the line will still be positioned with the first glyph of the
* line at 0. So the resulting positions may be beyond width.
*
* @return float The resulting width of the range of slots justified.
* @param pSeg Pointer to the segment
* @param pStart Pointer to the start of the line linked list (including skipped characters)
* @param pFont Font to use for positioning
* @param width Width in pixels in which to fit the line. If < 0. don't adjust natural width, just run justification passes
* to handle line end contextuals, if there are any.
* @param flags Indicates line ending types. Default is linked list is a full line
* @param pFirst If not NULL, the first slot in the list to be considered part of the line (so can skip)
* @param pLast If not NULL, the last slot to process in the line (allow say trailing whitespace to be skipped)
*/
GR2_API float gr_seg_justify(gr_segment* pSeg/*not NULL*/, const gr_slot* pStart/*not NULL*/, const gr_font *pFont, double width, enum gr_justFlags flags, const gr_slot* pFirst, const gr_slot* pLast);
/** Returns the next slot along in the segment.
*
* Slots are held in a linked list. This returns the next in the linked list. The slot
* may or may not be attached to another slot. Returns NULL at the end of the segment.
*/
GR2_API const gr_slot* gr_slot_next_in_segment(const gr_slot* p);
/** Returns the previous slot along in the segment.
*
* Slots are held in a doubly linked list. This returns the previos slot in the linked
* list. This slot may or may not be attached to it. Returns NULL at the start of the
* segment.
*/
GR2_API const gr_slot* gr_slot_prev_in_segment(const gr_slot* p);
/** Returns the attachment parent slot of this slot.
*
* Attached slots form a tree. This returns the parent of this slot in that tree. A
* base glyph which is not attached to another glyph, always returns NULL.
*/
GR2_API const gr_slot* gr_slot_attached_to(const gr_slot* p);
/** Returns the first slot attached to this slot.
*
* Attached slots form a singly linked list from the parent. This returns the first
* slot in that list. Note that this is a reference to another slot that is also in
* the main segment doubly linked list.
*
* if gr_slot_first_attachment(p) != NULL then gr_slot_attached_to(gr_slot_first_attachment(p)) == p.
*/
GR2_API const gr_slot* gr_slot_first_attachment(const gr_slot* p);
/** Returns the next slot attached to our attachment parent.
*
* This returns the next slot in the singly linked list of slots attached to this
* slot's parent. If there are no more such slots, NULL is returned. If there is
* no parent, i.e. the passed slot is a cluster base, then the next cluster base
* in graphical order (ltr, even for rtl text) is returned.
*
* if gr_slot_next_sibling_attachment(p) != NULL then gr_slot_attached_to(gr_slot_next_sibling_attachment(p)) == gr_slot_attached_to(p).
*/
GR2_API const gr_slot* gr_slot_next_sibling_attachment(const gr_slot* p);
/** Returns glyph id of the slot
*
* Each slot has a glyphid which is rendered at the position given by the slot. This
* glyphid is the real glyph to be rendered and never a pseudo glyph.
*/
GR2_API unsigned short gr_slot_gid(const gr_slot* p);
/** Returns X offset of glyph from start of segment **/
GR2_API float gr_slot_origin_X(const gr_slot* p);
/** Returns Y offset of glyph from start of segment **/
GR2_API float gr_slot_origin_Y(const gr_slot* p);
/** Returns the glyph advance for this glyph as adjusted for kerning
*
* @param p Slot to give results for
* @param face gr_face of the glyphs. May be NULL if unhinted advances used
* @param font gr_font to scale for pixel results. If NULL returns design
* units advance. If not NULL then returns pixel advance based
* on hinted or scaled glyph advances in the font. face must be
* passed for hinted advances to be used.
*/
GR2_API float gr_slot_advance_X(const gr_slot* p, const gr_face* face, const gr_font *font);
/** Returns the vertical advance for the glyph in the slot adjusted for kerning
*
* Returns design units unless font is not NULL in which case the pixel value
* is returned scaled for the given font
*/
GR2_API float gr_slot_advance_Y(const gr_slot* p, const gr_face* face, const gr_font *font);
/** Returns the gr_char_info index before us
*
* Returns the index of the gr_char_info that a cursor before this slot, would put
* an underlying cursor before. This may also be interpretted as each slot holding
* a set of char_infos that it is associated with and this function returning the
* index of the char_info with lowest index, from this set.
*/
GR2_API int gr_slot_before(const gr_slot* p/*not NULL*/);
/** Returns the gr_char_info index after us
*
* Returns the index of the gr_char_info that a cursor after this slot would put an
* underlying cursor after. This may also be interpretted as each slot holding a set
* of char_infos that it is associated with and this function returning the index of
* the char_info with the highest index, from this set.
*/
GR2_API int gr_slot_after(const gr_slot* p/*not NULL*/);
/** Returns the index of this slot in the segment
*
* Returns the index given to this slot during final positioning. This corresponds
* to the value returned br gr_cinfo_before() and gr_cinfo_after()
*/
GR2_API unsigned int gr_slot_index(const gr_slot* p/*not NULL*/);
/** Return a slot attribute value
*
* Given a slot and an attribute along with a possible subattribute, return the
* corresponding value in the slot. See enum gr_attrCode for details of each attribute.
*/
GR2_API int gr_slot_attr(const gr_slot* p/*not NULL*/, const gr_segment* pSeg/*not NULL*/, enum gr_attrCode index, gr_uint8 subindex); //tbd - do we need to expose this?
/** Returns whether text may be inserted before this glyph.
*
* This indicates whether a cursor can be put before this slot. It applies to
* base glyphs that have no parent as well as attached glyphs that have the
* .insert attribute explicitly set to true. This is the primary mechanism
* for identifying contiguous sequences of base plus diacritics.
*/
GR2_API int gr_slot_can_insert_before(const gr_slot* p);
/** Returns the original gr_char_info index this slot refers to.
*
* Each Slot has a gr_char_info that it originates from. This is that gr_char_info.
* The index is passed to gr_seg_cinfo(). This information is useful for testing.
*/
GR2_API int gr_slot_original(const gr_slot* p/*not NULL*/);
/** Breaks a segment into lines.
*
* Breaks the slot linked list at the given point in the linked list. It is up
* to the application to keep track of the first slot on each line.
*/
GR2_API void gr_slot_linebreak_before(gr_slot *p/*not NULL*/);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,79 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms
of the Mozilla Public License (http://mozilla.org/MPL) or the GNU
General Public License, as published by the Free Software Foundation,
either version 2 of the License or (at your option) any later version.
*/
#pragma once
#include <stddef.h>
typedef unsigned char gr_uint8;
typedef gr_uint8 gr_byte;
typedef signed char gr_int8;
typedef unsigned short gr_uint16;
typedef short gr_int16;
typedef unsigned int gr_uint32;
typedef int gr_int32;
enum gr_encform {
gr_utf8 = 1/*sizeof(uint8)*/, gr_utf16 = 2/*sizeof(uint16)*/, gr_utf32 = 4/*sizeof(uint32)*/
};
// Define API function declspec/attributes and how each supported compiler or OS
// allows us to specify them.
#if defined __GNUC__
#define _gr2_and ,
#define _gr2_tag_fn(a) __attribute__((a))
#define _gr2_deprecated_flag deprecated
#define _gr2_export_flag visibility("default")
#define _gr2_import_flag visibility("default")
#define _gr2_static_flag visibility("hidden")
#endif
#if defined _WIN32 || defined __CYGWIN__
#if defined __GNUC__ // These three will be redefined for Windows
#undef _gr2_export_flag
#undef _gr2_import_flag
#undef _gr2_static_flag
#else // How MSVC sepcifies function level attributes adn deprecation
#define _gr2_and
#define _gr2_tag_fn(a) __declspec(a)
#define _gr2_deprecated_flag deprecated
#endif
#define _gr2_export_flag dllexport
#define _gr2_import_flag dllimport
#define _gr2_static_flag
#endif
#if defined GRAPHITE2_STATIC
#define GR2_API _gr2_tag_fn(_gr2_static_flag)
#define GR2_DEPRECATED_API _gr2_tag_fn(_gr2_deprecated_flag _gr2_and _gr2_static_flag)
#elif defined GRAPHITE2_EXPORTING
#define GR2_API _gr2_tag_fn(_gr2_export_flag)
#define GR2_DEPRECATED_API _gr2_tag_fn(_gr2_deprecated_flag _gr2_and _gr2_export_flag)
#else
#define GR2_API _gr2_tag_fn(_gr2_import_flag)
#define GR2_DEPRECATED_API _gr2_tag_fn(_gr2_deprecated_flag _gr2_and _gr2_import_flag)
#endif

155
thirdparty/graphite/src/CmapCache.cpp vendored Normal file
View File

@ -0,0 +1,155 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Main.h"
#include "inc/CmapCache.h"
#include "inc/Face.h"
#include "inc/TtfTypes.h"
#include "inc/TtfUtil.h"
using namespace graphite2;
const void * bmp_subtable(const Face::Table & cmap)
{
const void * stbl;
if (!cmap.size()) return 0;
if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap + cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap + cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap + cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap + cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap + cmap.size()))
return stbl;
return 0;
}
const void * smp_subtable(const Face::Table & cmap)
{
const void * stbl;
if (!cmap.size()) return 0;
if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap + cmap.size())
|| TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap + cmap.size()))
return stbl;
return 0;
}
template <unsigned int (*NextCodePoint)(const void *, unsigned int, int *),
uint16 (*LookupCodePoint)(const void *, unsigned int, int)>
bool cache_subtable(uint16 * blocks[], const void * cst, const unsigned int limit)
{
int rangeKey = 0;
uint32 codePoint = NextCodePoint(cst, 0, &rangeKey),
prevCodePoint = 0;
while (codePoint < limit)
{
unsigned int block = codePoint >> 8;
if (!blocks[block])
{
blocks[block] = grzeroalloc<uint16>(0x100);
if (!blocks[block])
return false;
}
blocks[block][codePoint & 0xFF] = LookupCodePoint(cst, codePoint, rangeKey);
// prevent infinite loop
if (codePoint <= prevCodePoint)
codePoint = prevCodePoint + 1;
prevCodePoint = codePoint;
codePoint = NextCodePoint(cst, codePoint, &rangeKey);
}
return true;
}
CachedCmap::CachedCmap(const Face & face)
: m_isBmpOnly(true),
m_blocks(0)
{
const Face::Table cmap(face, Tag::cmap);
if (!cmap) return;
const void * bmp_cmap = bmp_subtable(cmap);
const void * smp_cmap = smp_subtable(cmap);
m_isBmpOnly = !smp_cmap;
m_blocks = grzeroalloc<uint16 *>(m_isBmpOnly ? 0x100 : 0x1100);
if (m_blocks && smp_cmap)
{
if (!cache_subtable<TtfUtil::CmapSubtable12NextCodepoint, TtfUtil::CmapSubtable12Lookup>(m_blocks, smp_cmap, 0x10FFFF))
return;
}
if (m_blocks && bmp_cmap)
{
if (!cache_subtable<TtfUtil::CmapSubtable4NextCodepoint, TtfUtil::CmapSubtable4Lookup>(m_blocks, bmp_cmap, 0xFFFF))
return;
}
}
CachedCmap::~CachedCmap() throw()
{
if (!m_blocks) return;
unsigned int numBlocks = (m_isBmpOnly)? 0x100 : 0x1100;
for (unsigned int i = 0; i < numBlocks; i++)
free(m_blocks[i]);
free(m_blocks);
}
uint16 CachedCmap::operator [] (const uint32 usv) const throw()
{
if ((m_isBmpOnly && usv > 0xFFFF) || (usv > 0x10FFFF))
return 0;
const uint32 block = 0xFFFF & (usv >> 8);
if (m_blocks[block])
return m_blocks[block][usv & 0xFF];
return 0;
};
CachedCmap::operator bool() const throw()
{
return m_blocks != 0;
}
DirectCmap::DirectCmap(const Face & face)
: _cmap(face, Tag::cmap),
_smp(smp_subtable(_cmap)),
_bmp(bmp_subtable(_cmap))
{
}
uint16 DirectCmap::operator [] (const uint32 usv) const throw()
{
return usv > 0xFFFF
? (_smp ? TtfUtil::CmapSubtable12Lookup(_smp, usv, 0) : 0)
: TtfUtil::CmapSubtable4Lookup(_bmp, usv, 0);
}
DirectCmap::operator bool () const throw()
{
return _cmap && _bmp;
}

782
thirdparty/graphite/src/Code.cpp vendored Normal file
View File

@ -0,0 +1,782 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This class represents loaded graphite stack machine code. It performs
// basic sanity checks, on the incoming code to prevent more obvious problems
// from crashing graphite.
// Author: Tim Eves
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include "graphite2/Segment.h"
#include "inc/Code.h"
#include "inc/Face.h"
#include "inc/GlyphFace.h"
#include "inc/GlyphCache.h"
#include "inc/Machine.h"
#include "inc/Rule.h"
#include "inc/Silf.h"
#include <cstdio>
#ifdef NDEBUG
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#endif
using namespace graphite2;
using namespace vm;
namespace {
inline bool is_return(const instr i) {
const opcode_t * opmap = Machine::getOpcodeTable();
const instr pop_ret = *opmap[POP_RET].impl,
ret_zero = *opmap[RET_ZERO].impl,
ret_true = *opmap[RET_TRUE].impl;
return i == pop_ret || i == ret_zero || i == ret_true;
}
struct context
{
context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false;}
struct {
uint8 changed:1,
referenced:1;
} flags;
uint8 codeRef;
};
} // end namespace
class Machine::Code::decoder
{
public:
struct limits;
static const int NUMCONTEXTS = 256;
decoder(limits & lims, Code &code, enum passtype pt) throw();
bool load(const byte * bc_begin, const byte * bc_end);
void apply_analysis(instr * const code, instr * code_end);
byte max_ref() { return _max_ref; }
int out_index() const { return _out_index; }
private:
void set_ref(int index) throw();
void set_noref(int index) throw();
void set_changed(int index) throw();
opcode fetch_opcode(const byte * bc);
void analyse_opcode(const opcode, const int8 * const dp) throw();
bool emit_opcode(opcode opc, const byte * & bc);
bool validate_opcode(const byte opc, const byte * const bc);
bool valid_upto(const uint16 limit, const uint16 x) const throw();
bool test_context() const throw();
bool test_ref(int8 index) const throw();
bool test_attr(attrCode attr) const throw();
void failure(const status_t s) const throw() { _code.failure(s); }
Code & _code;
int _out_index;
uint16 _out_length;
instr * _instr;
byte * _data;
limits & _max;
enum passtype _passtype;
int _stack_depth;
bool _in_ctxt_item;
int16 _slotref;
context _contexts[NUMCONTEXTS];
byte _max_ref;
};
struct Machine::Code::decoder::limits
{
const byte * bytecode;
const uint8 pre_context;
const uint16 rule_length,
classes,
glyf_attrs,
features;
const byte attrid[gr_slatMax];
};
inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
: _code(code),
_out_index(code._constraint ? 0 : lims.pre_context),
_out_length(code._constraint ? 1 : lims.rule_length),
_instr(code._code), _data(code._data), _max(lims), _passtype(pt),
_stack_depth(0),
_in_ctxt_item(false),
_slotref(0),
_max_ref(0)
{ }
Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
enum passtype pt, byte * * const _out)
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
_constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
{
#ifdef GRAPHITE2_TELEMETRY
telemetry::category _code_cat(face.tele.code);
#endif
assert(bytecode_begin != 0);
if (bytecode_begin == bytecode_end)
{
// ::new (this) Code();
return;
}
assert(bytecode_end > bytecode_begin);
const opcode_t * op_to_fn = Machine::getOpcodeTable();
// Allocate code and data target buffers, these sizes are a worst case
// estimate. Once we know their real sizes the we'll shrink them.
if (_out) _code = reinterpret_cast<instr *>(*_out);
else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
_data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
if (!_code || !_data) {
failure(alloc_failed);
return;
}
decoder::limits lims = {
bytecode_end,
pre_context,
rule_length,
silf.numClasses(),
face.glyphs().numAttrs(),
face.numFeatures(),
{1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,255,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0, silf.numUser()}
};
decoder dec(lims, *this, pt);
if(!dec.load(bytecode_begin, bytecode_end))
return;
// Is this an empty program?
if (_instr_count == 0)
{
release_buffers();
::new (this) Code();
return;
}
// When we reach the end check we've terminated it correctly
if (!is_return(_code[_instr_count-1])) {
failure(missing_return);
return;
}
assert((_constraint && immutable()) || !_constraint);
dec.apply_analysis(_code, _code + _instr_count);
_max_ref = dec.max_ref();
// Now we know exactly how much code and data the program really needs
// realloc the buffers to exactly the right size so we don't waste any
// memory.
assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
if (_out)
*_out += total_sz;
else
{
instr * const old_code = _code;
_code = static_cast<instr *>(realloc(_code, total_sz));
if (!_code) free(old_code);
}
_data = reinterpret_cast<byte *>(_code + (_instr_count+1));
if (!_code)
{
failure(alloc_failed);
return;
}
// Make this RET_ZERO, we should never reach this but just in case ...
_code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(_data_size + (_instr_count+1)*sizeof(instr));
#endif
}
Machine::Code::~Code() throw ()
{
if (_own)
release_buffers();
}
bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
{
_max.bytecode = bc_end;
while (bc < bc_end)
{
const opcode opc = fetch_opcode(bc++);
if (opc == vm::MAX_OPCODE)
return false;
analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
if (!emit_opcode(opc, bc))
return false;
}
return bool(_code);
}
// Validation check and fixups.
//
opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
{
const byte opc = *bc++;
// Do some basic sanity checks based on what we know about the opcode
if (!validate_opcode(opc, bc)) return MAX_OPCODE;
// And check its arguments as far as possible
switch (opcode(opc))
{
case NOP :
break;
case PUSH_BYTE :
case PUSH_BYTEU :
case PUSH_SHORT :
case PUSH_SHORTU :
case PUSH_LONG :
++_stack_depth;
break;
case ADD :
case SUB :
case MUL :
case DIV :
case MIN_ :
case MAX_ :
case AND :
case OR :
case EQUAL :
case NOT_EQ :
case LESS :
case GTR :
case LESS_EQ :
case GTR_EQ :
case BITOR :
case BITAND :
if (--_stack_depth <= 0)
failure(underfull_stack);
break;
case NEG :
case TRUNC8 :
case TRUNC16 :
case NOT :
case BITNOT :
case BITSET :
if (_stack_depth <= 0)
failure(underfull_stack);
break;
case COND :
_stack_depth -= 2;
if (_stack_depth <= 0)
failure(underfull_stack);
break;
case NEXT_N : // runtime checked
break;
case NEXT :
case COPY_NEXT :
++_out_index;
if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
failure(out_of_range_data);
break;
case PUT_GLYPH_8BIT_OBS :
valid_upto(_max.classes, bc[0]);
test_context();
break;
case PUT_SUBS_8BIT_OBS :
test_ref(int8(bc[0]));
valid_upto(_max.classes, bc[1]);
valid_upto(_max.classes, bc[2]);
test_context();
break;
case PUT_COPY :
test_ref(int8(bc[0]));
test_context();
break;
case INSERT :
if (_passtype >= PASS_TYPE_POSITIONING)
failure(invalid_opcode);
++_out_length;
if (_out_index < 0) ++_out_index;
if (_out_index < -1 || _out_index >= _out_length)
failure(out_of_range_data);
break;
case DELETE :
if (_passtype >= PASS_TYPE_POSITIONING)
failure(invalid_opcode);
if (_out_index < _max.pre_context)
failure(out_of_range_data);
--_out_index;
--_out_length;
if (_out_index < -1 || _out_index > _out_length)
failure(out_of_range_data);
break;
case ASSOC :
if (bc[0] == 0)
failure(out_of_range_data);
for (uint8 num = bc[0]; num; --num)
test_ref(int8(bc[num]));
test_context();
break;
case CNTXT_ITEM :
valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
if (_in_ctxt_item) failure(nested_context_item);
break;
case ATTR_SET :
case ATTR_ADD :
case ATTR_SUB :
case ATTR_SET_SLOT :
if (--_stack_depth < 0)
failure(underfull_stack);
valid_upto(gr_slatMax, bc[0]);
if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
failure(out_of_range_data);
test_attr(attrCode(bc[0]));
test_context();
break;
case IATTR_SET_SLOT :
if (--_stack_depth < 0)
failure(underfull_stack);
if (valid_upto(gr_slatMax, bc[0]))
valid_upto(_max.attrid[bc[0]], bc[1]);
test_attr(attrCode(bc[0]));
test_context();
break;
case PUSH_SLOT_ATTR :
++_stack_depth;
valid_upto(gr_slatMax, bc[0]);
test_ref(int8(bc[1]));
if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
failure(out_of_range_data);
test_attr(attrCode(bc[0]));
break;
case PUSH_GLYPH_ATTR_OBS :
case PUSH_ATT_TO_GATTR_OBS :
++_stack_depth;
valid_upto(_max.glyf_attrs, bc[0]);
test_ref(int8(bc[1]));
break;
case PUSH_ATT_TO_GLYPH_METRIC :
case PUSH_GLYPH_METRIC :
++_stack_depth;
valid_upto(kgmetDescent, bc[0]);
test_ref(int8(bc[1]));
// level: dp[2] no check necessary
break;
case PUSH_FEAT :
++_stack_depth;
valid_upto(_max.features, bc[0]);
test_ref(int8(bc[1]));
break;
case PUSH_ISLOT_ATTR :
++_stack_depth;
if (valid_upto(gr_slatMax, bc[0]))
{
test_ref(int8(bc[1]));
valid_upto(_max.attrid[bc[0]], bc[2]);
}
test_attr(attrCode(bc[0]));
break;
case PUSH_IGLYPH_ATTR :// not implemented
++_stack_depth;
break;
case POP_RET :
if (--_stack_depth < 0)
failure(underfull_stack);
GR_FALLTHROUGH;
// no break
case RET_ZERO :
case RET_TRUE :
break;
case IATTR_SET :
case IATTR_ADD :
case IATTR_SUB :
if (--_stack_depth < 0)
failure(underfull_stack);
if (valid_upto(gr_slatMax, bc[0]))
valid_upto(_max.attrid[bc[0]], bc[1]);
test_attr(attrCode(bc[0]));
test_context();
break;
case PUSH_PROC_STATE : // dummy: dp[0] no check necessary
case PUSH_VERSION :
++_stack_depth;
break;
case PUT_SUBS :
test_ref(int8(bc[0]));
valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
test_context();
break;
case PUT_SUBS2 : // not implemented
case PUT_SUBS3 : // not implemented
break;
case PUT_GLYPH :
valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
test_context();
break;
case PUSH_GLYPH_ATTR :
case PUSH_ATT_TO_GLYPH_ATTR :
++_stack_depth;
valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
test_ref(int8(bc[2]));
break;
case SET_FEAT :
valid_upto(_max.features, bc[0]);
test_ref(int8(bc[1]));
break;
default:
failure(invalid_opcode);
break;
}
return bool(_code) ? opcode(opc) : MAX_OPCODE;
}
void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) throw()
{
switch (opc)
{
case DELETE :
_code._delete = true;
break;
case ASSOC :
set_changed(0);
// for (uint8 num = arg[0]; num; --num)
// _analysis.set_noref(num);
break;
case PUT_GLYPH_8BIT_OBS :
case PUT_GLYPH :
_code._modify = true;
set_changed(0);
break;
case ATTR_SET :
case ATTR_ADD :
case ATTR_SUB :
case ATTR_SET_SLOT :
case IATTR_SET_SLOT :
case IATTR_SET :
case IATTR_ADD :
case IATTR_SUB :
set_noref(0);
break;
case NEXT :
case COPY_NEXT :
++_slotref;
_contexts[_slotref] = context(uint8(_code._instr_count+1));
// if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
break;
case INSERT :
if (_slotref >= 0) --_slotref;
_code._modify = true;
break;
case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
case PUT_SUBS :
_code._modify = true;
set_changed(0);
GR_FALLTHROUGH;
// no break
case PUT_COPY :
if (arg[0] != 0) { set_changed(0); _code._modify = true; }
set_ref(arg[0]);
break;
case PUSH_GLYPH_ATTR_OBS :
case PUSH_SLOT_ATTR :
case PUSH_GLYPH_METRIC :
case PUSH_ATT_TO_GATTR_OBS :
case PUSH_ATT_TO_GLYPH_METRIC :
case PUSH_ISLOT_ATTR :
case PUSH_FEAT :
case SET_FEAT :
set_ref(arg[1]);
break;
case PUSH_ATT_TO_GLYPH_ATTR :
case PUSH_GLYPH_ATTR :
set_ref(arg[2]);
break;
default:
break;
}
}
bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
{
const opcode_t * op_to_fn = Machine::getOpcodeTable();
const opcode_t & op = op_to_fn[opc];
if (op.impl[_code._constraint] == 0)
{
failure(unimplemented_opcode_used);
return false;
}
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
// Add this instruction
*_instr++ = op.impl[_code._constraint];
++_code._instr_count;
// Grab the parameters
if (param_sz) {
memcpy(_data, bc, param_sz * sizeof(byte));
bc += param_sz;
_data += param_sz;
_code._data_size += param_sz;
}
// recursively decode a context item so we can split the skip into
// instruction and data portions.
if (opc == CNTXT_ITEM)
{
assert(_out_index == 0);
_in_ctxt_item = true;
_out_index = _max.pre_context + int8(_data[-2]);
_slotref = int8(_data[-2]);
_out_length = _max.rule_length;
const size_t ctxt_start = _code._instr_count;
byte & instr_skip = _data[-1];
byte & data_skip = *_data++;
++_code._data_size;
const byte *curr_end = _max.bytecode;
if (load(bc, bc + instr_skip))
{
bc += instr_skip;
data_skip = instr_skip - byte(_code._instr_count - ctxt_start);
instr_skip = byte(_code._instr_count - ctxt_start);
_max.bytecode = curr_end;
_out_length = 1;
_out_index = 0;
_slotref = 0;
_in_ctxt_item = false;
}
else
{
_out_index = 0;
_slotref = 0;
return false;
}
}
return bool(_code);
}
void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
{
// insert TEMP_COPY commands for slots that need them (that change and are referenced later)
int tempcount = 0;
if (_code._constraint) return;
const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
{
if (!c->flags.referenced || !c->flags.changed) continue;
instr * const tip = code + c->codeRef + tempcount;
memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
*tip = temp_copy;
++code_end;
++tempcount;
_code._delete = true;
}
_code._instr_count = code_end - code;
}
inline
bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
{
if (opc >= MAX_OPCODE)
{
failure(invalid_opcode);
return false;
}
const opcode_t & op = Machine::getOpcodeTable()[opc];
if (op.impl[_code._constraint] == 0)
{
failure(unimplemented_opcode_used);
return false;
}
if (op.param_sz == VARARGS && bc >= _max.bytecode)
{
failure(arguments_exhausted);
return false;
}
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
if (bc - 1 + param_sz >= _max.bytecode)
{
failure(arguments_exhausted);
return false;
}
return true;
}
bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
{
const bool t = (limit != 0) && (x < limit);
if (!t) failure(out_of_range_data);
return t;
}
inline
bool Machine::Code::decoder::test_ref(int8 index) const throw()
{
if (_code._constraint && !_in_ctxt_item)
{
if (index > 0 || -index > _max.pre_context)
{
failure(out_of_range_data);
return false;
}
}
else
{
if (_max.rule_length == 0
|| (_slotref + _max.pre_context + index >= _max.rule_length)
|| (_slotref + _max.pre_context + index < 0))
{
failure(out_of_range_data);
return false;
}
}
return true;
}
bool Machine::Code::decoder::test_context() const throw()
{
if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
{
failure(out_of_range_data);
return false;
}
return true;
}
bool Machine::Code::decoder::test_attr(attrCode) const throw()
{
#if 0 // This code is coming but causes backward compatibility problems.
if (_passtype < PASS_TYPE_POSITIONING)
{
if (attr != gr_slatBreak && attr != gr_slatDir && attr != gr_slatUserDefn
&& attr != gr_slatCompRef)
{
failure(out_of_range_data);
return false;
}
}
#endif
return true;
}
inline
void Machine::Code::failure(const status_t s) throw() {
release_buffers();
_status = s;
}
inline
void Machine::Code::decoder::set_ref(int index) throw() {
if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
_contexts[index + _slotref].flags.referenced = true;
if (index + _slotref > _max_ref) _max_ref = index + _slotref;
}
inline
void Machine::Code::decoder::set_noref(int index) throw() {
if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
if (index + _slotref > _max_ref) _max_ref = index + _slotref;
}
inline
void Machine::Code::decoder::set_changed(int index) throw() {
if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
_contexts[index + _slotref].flags.changed= true;
if (index + _slotref > _max_ref) _max_ref = index + _slotref;
}
void Machine::Code::release_buffers() throw()
{
if (_own)
free(_code);
_code = 0;
_data = 0;
_own = false;
}
int32 Machine::Code::run(Machine & m, slotref * & map) const
{
// assert(_own);
assert(*this); // Check we are actually runnable
if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
|| m.slotMap()[_max_ref + m.slotMap().context()] == 0)
{
m._status = Machine::slot_offset_out_bounds;
return 1;
// return m.run(_code, _data, map);
}
return m.run(_code, _data, map);
}

1115
thirdparty/graphite/src/Collider.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

125
thirdparty/graphite/src/Decompressor.cpp vendored Normal file
View File

@ -0,0 +1,125 @@
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cassert>
#include "inc/Decompressor.h"
#include "inc/Compression.h"
using namespace lz4;
namespace {
inline
u32 read_literal(u8 const * &s, u8 const * const e, u32 l) {
if (l == 15 && s != e)
{
u8 b = 0;
do { l += b = *s++; } while(b==0xff && s != e);
}
return l;
}
bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal,
u32 & literal_len, u32 & match_len, u32 & match_dist)
{
u8 const token = *src++;
literal_len = read_literal(src, end, token >> 4);
literal = src;
src += literal_len;
// Normal exit for end of stream, wrap arround check and parital match check.
if (src > end - sizeof(u16) || src < literal)
return false;
match_dist = *src++;
match_dist |= *src++ << 8;
match_len = read_literal(src, end, token & 0xf) + MINMATCH;
// Malformed stream check.
return src <= end-MINCODA;
}
}
int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
{
if (out_size <= in_size || in_size < MINSRCSIZE)
return -1;
u8 const * src = static_cast<u8 const *>(in),
* literal = 0,
* const src_end = src + in_size;
u8 * dst = static_cast<u8*>(out),
* const dst_end = dst + out_size;
// Check the in and out size hasn't wrapped around.
if (src >= src_end || dst >= dst_end)
return -1;
u32 literal_len = 0,
match_len = 0,
match_dist = 0;
while (read_sequence(src, src_end, literal, literal_len, match_len,
match_dist))
{
if (literal_len != 0)
{
// Copy in literal. At this point the a minimal literal + minminal
// match plus the coda (1 + 2 + 5) must be 8 bytes or more allowing
// us to remain within the src buffer for an overrun_copy on
// machines upto 64 bits.
if (align(literal_len) > out_size)
return -1;
dst = overrun_copy(dst, literal, literal_len);
out_size -= literal_len;
}
// Copy, possibly repeating, match from earlier in the
// decoded output.
u8 const * const pcpy = dst - match_dist;
if (pcpy < static_cast<u8*>(out)
|| match_len > unsigned(out_size - LASTLITERALS)
// Wrap around checks:
|| out_size < LASTLITERALS || pcpy >= dst)
return -1;
if (dst > pcpy+sizeof(unsigned long)
&& align(match_len) <= out_size)
dst = overrun_copy(dst, pcpy, match_len);
else
dst = safe_copy(dst, pcpy, match_len);
out_size -= match_len;
}
if (literal > src_end - literal_len || literal_len > out_size)
return -1;
dst = fast_copy(dst, literal, literal_len);
return int(dst - (u8*)out);
}

366
thirdparty/graphite/src/Face.cpp vendored Normal file
View File

@ -0,0 +1,366 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cstring>
#include "graphite2/Segment.h"
#include "inc/CmapCache.h"
#include "inc/debug.h"
#include "inc/Decompressor.h"
#include "inc/Endian.h"
#include "inc/Face.h"
#include "inc/FileFace.h"
#include "inc/GlyphFace.h"
#include "inc/json.h"
#include "inc/Segment.h"
#include "inc/NameTable.h"
#include "inc/Error.h"
using namespace graphite2;
namespace
{
enum compression
{
NONE,
LZ4
};
}
Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
: m_appFaceHandle(appFaceHandle),
m_pFileFace(NULL),
m_pGlyphFaceCache(NULL),
m_cmap(NULL),
m_pNames(NULL),
m_logger(NULL),
m_error(0), m_errcntxt(0),
m_silfs(NULL),
m_numSilf(0),
m_ascent(0),
m_descent(0)
{
memset(&m_ops, 0, sizeof m_ops);
memcpy(&m_ops, &ops, min(sizeof m_ops, ops.size));
}
Face::~Face()
{
setLogger(0);
delete m_pGlyphFaceCache;
delete m_cmap;
delete[] m_silfs;
#ifndef GRAPHITE2_NFILEFACE
delete m_pFileFace;
#endif
delete m_pNames;
}
float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
{
const Font & font = *reinterpret_cast<const Font *>(font_ptr);
return font.face().glyphs().glyph(glyphid)->theAdvance().x * font.scale();
}
bool Face::readGlyphs(uint32 faceOptions)
{
Error e;
#ifdef GRAPHITE2_TELEMETRY
telemetry::category _glyph_cat(tele.glyph);
#endif
error_context(EC_READGLYPHS);
m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
|| e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
|| e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM))
{
return error(e);
}
if (faceOptions & gr_face_cacheCmap)
m_cmap = new CachedCmap(*this);
else
m_cmap = new DirectCmap(*this);
if (e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
return error(e);
if (faceOptions & gr_face_preloadGlyphs)
nameTable(); // preload the name table along with the glyphs.
return true;
}
bool Face::readGraphite(const Table & silf)
{
#ifdef GRAPHITE2_TELEMETRY
telemetry::category _silf_cat(tele.silf);
#endif
Error e;
error_context(EC_READSILF);
const byte * p = silf;
if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
const uint32 version = be::read<uint32>(p);
if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
if (version >= 0x00030000)
be::skip<uint32>(p); // compilerVersion
m_numSilf = be::read<uint16>(p);
be::skip<uint16>(p); // reserved
bool havePasses = false;
m_silfs = new Silf[m_numSilf];
if (e.test(!m_silfs, E_OUTOFMEM)) return error(e);
for (int i = 0; i < m_numSilf; i++)
{
error_context(EC_ASILF + (i << 8));
const uint32 offset = be::read<uint32>(p),
next = i == m_numSilf - 1 ? uint32(silf.size()) : be::peek<uint32>(p);
if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
return error(e);
if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
return false;
if (m_silfs[i].numPasses())
havePasses = true;
}
return havePasses;
}
bool Face::readFeatures()
{
return m_Sill.readFace(*this);
}
bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
{
#if !defined GRAPHITE2_NTRACING
json * dbgout = logger();
if (dbgout)
{
*dbgout << json::object
<< "id" << objectid(seg)
<< "passes" << json::array;
}
#endif
// if ((seg->dir() & 1) != aSilf->dir())
// seg->reverseSlots();
if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
seg->doMirror(aSilf->aMirror());
bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
if (res)
{
seg->associateChars(0, seg->charInfoCount());
if (aSilf->flags() & 0x20)
res &= seg->initCollisions();
if (res)
res &= aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
}
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
seg->positionSlots(0, 0, 0, seg->currdir());
*dbgout << json::item
<< json::close // Close up the passes array
<< "outputdir" << (seg->currdir() ? "rtl" : "ltr")
<< "output" << json::array;
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close
<< "advance" << seg->advance()
<< "chars" << json::array;
for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
*dbgout << json::flat << *seg->charinfo(int(i));
*dbgout << json::close // Close up the chars array
<< json::close; // Close up the segment object
}
#endif
return res;
}
void Face::setLogger(FILE * log_file GR_MAYBE_UNUSED)
{
#if !defined GRAPHITE2_NTRACING
delete m_logger;
m_logger = log_file ? new json(log_file) : 0;
#endif
}
const Silf *Face::chooseSilf(uint32 script) const
{
if (m_numSilf == 0)
return NULL;
else if (m_numSilf == 1 || script == 0)
return m_silfs;
else // do more work here
return m_silfs;
}
uint16 Face::findPseudo(uint32 uid) const
{
return (m_numSilf) ? m_silfs[0].findPseudo(uid) : 0;
}
int32 Face::getGlyphMetric(uint16 gid, uint8 metric) const
{
switch (metrics(metric))
{
case kgmetAscent : return m_ascent;
case kgmetDescent : return m_descent;
default:
if (gid >= glyphs().numGlyphs()) return 0;
return glyphs().glyph(gid)->getMetric(metric);
}
}
void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
{
#ifndef GRAPHITE2_NFILEFACE
if (m_pFileFace==pFileFace)
return;
delete m_pFileFace;
m_pFileFace = pFileFace;
#endif
}
NameTable * Face::nameTable() const
{
if (m_pNames) return m_pNames;
const Table name(*this, Tag::name);
if (name)
m_pNames = new NameTable(name, name.size());
return m_pNames;
}
uint16 Face::languageForLocale(const char * locale) const
{
nameTable();
if (m_pNames)
return m_pNames->getLanguageId(locale);
return 0;
}
Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
: _f(&face), _sz(0), _compressed(false)
{
_p = static_cast<const byte *>((*_f->m_ops.get_table)(_f->m_appFaceHandle, n, &_sz));
if (!TtfUtil::CheckTable(n, _p, _sz))
{
release(); // Make sure we release the table buffer even if the table failed its checks
return;
}
if (be::peek<uint32>(_p) >= version)
decompress();
}
void Face::Table::release()
{
if (_compressed)
free(const_cast<byte *>(_p));
else if (_p && _f->m_ops.release_table)
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
_p = 0; _sz = 0;
}
Face::Table & Face::Table::operator = (const Table && rhs) throw()
{
if (this == &rhs) return *this;
release();
new (this) Table(std::move(rhs));
return *this;
}
Error Face::Table::decompress()
{
Error e;
if (e.test(_sz < 5 * sizeof(uint32), E_BADSIZE))
return e;
byte * uncompressed_table = 0;
size_t uncompressed_size = 0;
const byte * p = _p;
const uint32 version = be::read<uint32>(p); // Table version number.
// The scheme is in the top 5 bits of the 1st uint32.
const uint32 hdr = be::read<uint32>(p);
switch(compression(hdr >> 27))
{
case NONE: return e;
case LZ4:
{
uncompressed_size = hdr & 0x07ffffff;
uncompressed_table = gralloc<byte>(uncompressed_size);
if (!e.test(!uncompressed_table || uncompressed_size < 4, E_OUTOFMEM))
{
memset(uncompressed_table, 0, 4); // make sure version number is initialised
// coverity[forward_null : FALSE] - uncompressed_table has been checked so can't be null
// coverity[checked_return : FALSE] - we test e later
e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
}
break;
}
default:
e.error(E_BADSCHEME);
};
// Check the uncompressed version number against the original.
if (!e)
// coverity[forward_null : FALSE] - uncompressed_table has already been tested so can't be null
// coverity[checked_return : FALSE] - we test e later
e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
// Tell the provider to release the compressed form since were replacing
// it anyway.
release();
if (e)
{
free(uncompressed_table);
uncompressed_table = 0;
uncompressed_size = 0;
}
_p = uncompressed_table;
_sz = uncompressed_size;
_compressed = true;
return e;
}

293
thirdparty/graphite/src/FeatureMap.cpp vendored Normal file
View File

@ -0,0 +1,293 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cstring>
#include "inc/Main.h"
#include "inc/bits.h"
#include "inc/Endian.h"
#include "inc/FeatureMap.h"
#include "inc/FeatureVal.h"
#include "graphite2/Font.h"
#include "inc/TtfUtil.h"
#include <cstdlib>
#include "inc/Face.h"
using namespace graphite2;
namespace
{
static int cmpNameAndFeatures(const void *ap, const void *bp)
{
const NameAndFeatureRef & a = *static_cast<const NameAndFeatureRef *>(ap),
& b = *static_cast<const NameAndFeatureRef *>(bp);
return (a < b ? -1 : (b < a ? 1 : 0));
}
const size_t FEAT_HEADER = sizeof(uint32) + 2*sizeof(uint16) + sizeof(uint32),
FEATURE_SIZE = sizeof(uint32)
+ 2*sizeof(uint16)
+ sizeof(uint32)
+ 2*sizeof(uint16),
FEATURE_SETTING_SIZE = sizeof(int16) + sizeof(uint16);
uint16 readFeatureSettings(const byte * p, FeatureSetting * s, size_t num_settings)
{
uint16 max_val = 0;
for (FeatureSetting * const end = s + num_settings; s != end; ++s)
{
const int16 value = be::read<int16>(p);
::new (s) FeatureSetting(value, be::read<uint16>(p));
if (uint16(value) > max_val) max_val = value;
}
return max_val;
}
}
FeatureRef::FeatureRef(const Face & face,
unsigned short & bits_offset, uint32 max_val,
uint32 name, uint16 uiName, flags_t flags,
FeatureSetting *settings, uint16 num_set) throw()
: m_face(&face),
m_nameValues(settings),
m_mask(mask_over_val(max_val)),
m_max(max_val),
m_id(name),
m_nameid(uiName),
m_numSet(num_set),
m_flags(flags)
{
const uint8 need_bits = bit_set_count(m_mask);
m_index = (bits_offset + need_bits) / SIZEOF_CHUNK;
if (m_index > bits_offset / SIZEOF_CHUNK)
bits_offset = m_index*SIZEOF_CHUNK;
m_bits = bits_offset % SIZEOF_CHUNK;
bits_offset += need_bits;
m_mask <<= m_bits;
}
FeatureRef::~FeatureRef() throw()
{
free(m_nameValues);
}
bool FeatureMap::readFeats(const Face & face)
{
const Face::Table feat(face, TtfUtil::Tag::Feat);
const byte * p = feat;
if (!p) return true;
if (feat.size() < FEAT_HEADER) return false;
const byte *const feat_start = p,
*const feat_end = p + feat.size();
const uint32 version = be::read<uint32>(p);
m_numFeats = be::read<uint16>(p);
be::skip<uint16>(p);
be::skip<uint32>(p);
// Sanity checks
if (m_numFeats == 0) return true;
if (version < 0x00010000 ||
p + m_numFeats*FEATURE_SIZE > feat_end)
{ //defensive
m_numFeats = 0;
return false;
}
m_feats = new FeatureRef [m_numFeats];
uint16 * const defVals = gralloc<uint16>(m_numFeats);
if (!defVals || !m_feats) return false;
unsigned short bits = 0; //to cause overflow on first Feature
for (int i = 0, ie = m_numFeats; i != ie; i++)
{
const uint32 label = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p);
const uint16 num_settings = be::read<uint16>(p);
if (version >= 0x00020000)
be::skip<uint16>(p);
const uint32 settings_offset = be::read<uint32>(p);
const uint16 flags = be::read<uint16>(p),
uiName = be::read<uint16>(p);
if (settings_offset > size_t(feat_end - feat_start)
|| settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start))
{
free(defVals);
return false;
}
FeatureSetting *uiSet;
uint32 maxVal;
if (num_settings != 0)
{
uiSet = gralloc<FeatureSetting>(num_settings);
if (!uiSet)
{
free(defVals);
return false;
}
maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings);
defVals[i] = uiSet[0].value();
}
else
{
uiSet = 0;
maxVal = 0xffffffff;
defVals[i] = 0;
}
::new (m_feats + i) FeatureRef (face, bits, maxVal,
label, uiName,
FeatureRef::flags_t(flags),
uiSet, num_settings);
}
new (&m_defaultFeatures) Features(bits/(sizeof(uint32)*8) + 1, *this);
m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
if (!m_pNamedFeats)
{
free(defVals);
return false;
}
for (int i = 0; i < m_numFeats; ++i)
{
m_feats[i].applyValToFeature(defVals[i], m_defaultFeatures);
m_pNamedFeats[i] = m_feats[i];
}
free(defVals);
qsort(m_pNamedFeats, m_numFeats, sizeof(NameAndFeatureRef), &cmpNameAndFeatures);
return true;
}
bool SillMap::readFace(const Face & face)
{
if (!m_FeatureMap.readFeats(face)) return false;
if (!readSill(face)) return false;
return true;
}
bool SillMap::readSill(const Face & face)
{
const Face::Table sill(face, TtfUtil::Tag::Sill);
const byte *p = sill;
if (!p) return true;
if (sill.size() < 12) return false;
if (be::read<uint32>(p) != 0x00010000UL) return false;
m_numLanguages = be::read<uint16>(p);
m_langFeats = new LangFeaturePair[m_numLanguages];
if (!m_langFeats || !m_FeatureMap.m_numFeats) { m_numLanguages = 0; return true; } //defensive
p += 6; // skip the fast search
if (sill.size() < m_numLanguages * 8U + 12) return false;
for (int i = 0; i < m_numLanguages; i++)
{
uint32 langid = be::read<uint32>(p);
uint16 numSettings = be::read<uint16>(p);
uint16 offset = be::read<uint16>(p);
if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
Features* feats = new Features(m_FeatureMap.m_defaultFeatures);
if (!feats) return false;
const byte *pLSet = sill + offset;
// Apply langauge specific settings
for (int j = 0; j < numSettings; j++)
{
uint32 name = be::read<uint32>(pLSet);
uint16 val = be::read<uint16>(pLSet);
pLSet += 2;
const FeatureRef* pRef = m_FeatureMap.findFeatureRef(name);
if (pRef) pRef->applyValToFeature(val, *feats);
}
// Add the language id feature which is always feature id 1
const FeatureRef* pRef = m_FeatureMap.findFeatureRef(1);
if (pRef) pRef->applyValToFeature(langid, *feats);
m_langFeats[i].m_lang = langid;
m_langFeats[i].m_pFeatures = feats;
}
return true;
}
Features* SillMap::cloneFeatures(uint32 langname/*0 means default*/) const
{
if (langname)
{
// the number of languages in a font is usually small e.g. 8 in Doulos
// so this loop is not very expensive
for (uint16 i = 0; i < m_numLanguages; i++)
{
if (m_langFeats[i].m_lang == langname)
return new Features(*m_langFeats[i].m_pFeatures);
}
}
return new Features (m_FeatureMap.m_defaultFeatures);
}
const FeatureRef *FeatureMap::findFeatureRef(uint32 name) const
{
NameAndFeatureRef *it;
for (it = m_pNamedFeats; it < m_pNamedFeats + m_numFeats; ++it)
if (it->m_name == name)
return it->m_pFRef;
return NULL;
}
bool FeatureRef::applyValToFeature(uint32 val, Features & pDest) const
{
if (val>maxVal() || !m_face)
return false;
if (pDest.m_pMap==NULL)
pDest.m_pMap = &m_face->theSill().theFeatureMap();
else
if (pDest.m_pMap!=&m_face->theSill().theFeatureMap())
return false; //incompatible
if (m_index >= pDest.size())
pDest.resize(m_index+1);
pDest[m_index] &= ~m_mask;
pDest[m_index] |= (uint32(val) << m_bits);
return true;
}
uint32 FeatureRef::getFeatureVal(const Features& feats) const
{
if (m_index < feats.size() && m_face
&& &m_face->theSill().theFeatureMap()==feats.m_pMap)
return (feats[m_index] & m_mask) >> m_bits;
else
return 0;
}

115
thirdparty/graphite/src/FileFace.cpp vendored Normal file
View File

@ -0,0 +1,115 @@
/* GRAPHITE2 LICENSING
Copyright 2012, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cstring>
#include "inc/FileFace.h"
#ifndef GRAPHITE2_NFILEFACE
using namespace graphite2;
FileFace::FileFace(const char *filename)
: _file(fopen(filename, "rb")),
_file_len(0),
_header_tbl(NULL),
_table_dir(NULL)
{
if (!_file) return;
if (fseek(_file, 0, SEEK_END)) return;
_file_len = ftell(_file);
if (fseek(_file, 0, SEEK_SET)) return;
size_t tbl_offset, tbl_len;
// Get the header.
if (!TtfUtil::GetHeaderInfo(tbl_offset, tbl_len)) return;
if (fseek(_file, long(tbl_offset), SEEK_SET)) return;
_header_tbl = (TtfUtil::Sfnt::OffsetSubTable*)gralloc<char>(tbl_len);
if (_header_tbl)
{
if (fread(_header_tbl, 1, tbl_len, _file) != tbl_len) return;
if (!TtfUtil::CheckHeader(_header_tbl)) return;
}
// Get the table directory
if (!TtfUtil::GetTableDirInfo(_header_tbl, tbl_offset, tbl_len)) return;
_table_dir = (TtfUtil::Sfnt::OffsetSubTable::Entry*)gralloc<char>(tbl_len);
if (fseek(_file, long(tbl_offset), SEEK_SET)) return;
if (_table_dir && fread(_table_dir, 1, tbl_len, _file) != tbl_len)
{
free(_table_dir);
_table_dir = NULL;
}
return;
}
FileFace::~FileFace()
{
free(_table_dir);
free(_header_tbl);
if (_file)
fclose(_file);
}
const void *FileFace::get_table_fn(const void* appFaceHandle, unsigned int name, size_t *len)
{
if (appFaceHandle == 0) return 0;
const FileFace & file_face = *static_cast<const FileFace *>(appFaceHandle);
void *tbl;
size_t tbl_offset, tbl_len;
if (!TtfUtil::GetTableInfo(name, file_face._header_tbl, file_face._table_dir, tbl_offset, tbl_len))
return 0;
if (tbl_offset > file_face._file_len || tbl_len > file_face._file_len - tbl_offset
|| fseek(file_face._file, long(tbl_offset), SEEK_SET) != 0)
return 0;
tbl = malloc(tbl_len);
if (!tbl || fread(tbl, 1, tbl_len, file_face._file) != tbl_len)
{
free(tbl);
return 0;
}
if (len) *len = tbl_len;
return tbl;
}
void FileFace::rel_table_fn(const void* appFaceHandle, const void *table_buffer)
{
if (appFaceHandle == 0) return;
free(const_cast<void *>(table_buffer));
}
const gr_face_ops FileFace::ops = { sizeof FileFace::ops, &FileFace::get_table_fn, &FileFace::rel_table_fn };
#endif //!GRAPHITE2_NFILEFACE

58
thirdparty/graphite/src/Font.cpp vendored Normal file
View File

@ -0,0 +1,58 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Face.h"
#include "inc/Font.h"
#include "inc/GlyphCache.h"
using namespace graphite2;
Font::Font(float ppm, const Face & f, const void * appFontHandle, const gr_font_ops * ops)
: m_appFontHandle(appFontHandle ? appFontHandle : this),
m_face(f),
m_scale(ppm / f.glyphs().unitsPerEm()),
m_hinted(appFontHandle && ops && (ops->glyph_advance_x || ops->glyph_advance_y))
{
memset(&m_ops, 0, sizeof m_ops);
if (m_hinted && ops)
memcpy(&m_ops, ops, min(sizeof m_ops, ops->size));
else
m_ops.glyph_advance_x = &Face::default_glyph_advance;
size_t nGlyphs = f.glyphs().numGlyphs();
m_advances = gralloc<float>(nGlyphs);
if (m_advances)
{
for (float *advp = m_advances; nGlyphs; --nGlyphs, ++advp)
*advp = INVALID_ADVANCE;
}
}
/*virtual*/ Font::~Font()
{
free(m_advances);
}

492
thirdparty/graphite/src/GlyphCache.cpp vendored Normal file
View File

@ -0,0 +1,492 @@
/* GRAPHITE2 LICENSING
Copyright 2012, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/Face.h" //for the tags
#include "inc/GlyphCache.h"
#include "inc/GlyphFace.h"
#include "inc/Endian.h"
#include "inc/bits.h"
using namespace graphite2;
namespace
{
// Iterator over version 1 or 2 glat entries which consist of a series of
// +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
// v1 |k|n|v1 |v2 |...|vN | or v2 | k | n |v1 |v2 |...|vN |
// +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
// variable length structures.
template<typename W>
class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
{
unsigned short key() const { return uint16(be::peek<W>(_e) + _n); }
unsigned int run() const { return be::peek<W>(_e+sizeof(W)); }
void advance_entry() { _n = 0; _e = _v; be::skip<W>(_v,2); }
public:
_glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
_glat_iterator<W> & operator ++ () {
++_n; be::skip<uint16>(_v);
if (_n == run()) advance_entry();
return *this;
}
_glat_iterator<W> operator ++ (int) { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
// This is strictly a >= operator. A true == operator could be
// implemented that test for overlap but it would be more expensive a
// test.
bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e - 1; }
bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
value_type operator * () const {
return value_type(key(), be::peek<uint16>(_v));
}
protected:
const byte * _e, * _v;
size_t _n;
};
typedef _glat_iterator<uint8> glat_iterator;
typedef _glat_iterator<uint16> glat2_iterator;
}
const SlantBox SlantBox::empty = {0,0,0,0};
class GlyphCache::Loader
{
public:
Loader(const Face & face); //return result indicates success. Do not use if failed.
operator bool () const throw();
unsigned short int units_per_em() const throw();
unsigned short int num_glyphs() const throw();
unsigned short int num_attrs() const throw();
bool has_boxes() const throw();
const GlyphFace * read_glyph(unsigned short gid, GlyphFace &, int *numsubs) const throw();
GlyphBox * read_box(uint16 gid, GlyphBox *curr, const GlyphFace & face) const throw();
CLASS_NEW_DELETE;
private:
Face::Table _head,
_hhea,
_hmtx,
_glyf,
_loca,
m_pGlat,
m_pGloc;
bool _long_fmt;
bool _has_boxes;
unsigned short _num_glyphs_graphics, //i.e. boundary box and advance
_num_glyphs_attributes,
_num_attrs; // number of glyph attributes per glyph
};
GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
: _glyph_loader(new Loader(face)),
_glyphs(_glyph_loader && *_glyph_loader && _glyph_loader->num_glyphs()
? grzeroalloc<const GlyphFace *>(_glyph_loader->num_glyphs()) : 0),
_boxes(_glyph_loader && _glyph_loader->has_boxes() && _glyph_loader->num_glyphs()
? grzeroalloc<GlyphBox *>(_glyph_loader->num_glyphs()) : 0),
_num_glyphs(_glyphs ? _glyph_loader->num_glyphs() : 0),
_num_attrs(_glyphs ? _glyph_loader->num_attrs() : 0),
_upem(_glyphs ? _glyph_loader->units_per_em() : 0)
{
if ((face_options & gr_face_preloadGlyphs) && _glyph_loader && _glyphs)
{
int numsubs = 0;
GlyphFace * const glyphs = new GlyphFace [_num_glyphs];
if (!glyphs)
return;
// The 0 glyph is definately required.
_glyphs[0] = _glyph_loader->read_glyph(0, glyphs[0], &numsubs);
// glyphs[0] has the same address as the glyphs array just allocated,
// thus assigning the &glyphs[0] to _glyphs[0] means _glyphs[0] points
// to the entire array.
const GlyphFace * loaded = _glyphs[0];
for (uint16 gid = 1; loaded && gid != _num_glyphs; ++gid)
_glyphs[gid] = loaded = _glyph_loader->read_glyph(gid, glyphs[gid], &numsubs);
if (!loaded)
{
_glyphs[0] = 0;
delete [] glyphs;
}
else if (numsubs > 0 && _boxes)
{
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
GlyphBox * currbox = boxes;
for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
{
_boxes[gid] = currbox;
currbox = _glyph_loader->read_box(gid, currbox, *_glyphs[gid]);
}
if (!currbox)
{
free(boxes);
_boxes[0] = 0;
}
}
delete _glyph_loader;
_glyph_loader = 0;
// coverity[leaked_storage : FALSE] - calling read_glyph on index 0 saved
// glyphs as _glyphs[0]. Setting _glyph_loader to nullptr here flags that
// the dtor needs to call delete[] on _glyphs[0] to release what was allocated
// as glyphs
}
if (_glyphs && glyph(0) == 0)
{
free(_glyphs);
_glyphs = 0;
if (_boxes)
{
free(_boxes);
_boxes = 0;
}
_num_glyphs = _num_attrs = _upem = 0;
}
}
GlyphCache::~GlyphCache()
{
if (_glyphs)
{
if (_glyph_loader)
{
const GlyphFace * * g = _glyphs;
for(unsigned short n = _num_glyphs; n; --n, ++g)
delete *g;
}
else
delete [] _glyphs[0];
free(_glyphs);
}
if (_boxes)
{
if (_glyph_loader)
{
GlyphBox * * g = _boxes;
for (uint16 n = _num_glyphs; n; --n, ++g)
free(*g);
}
else
free(_boxes[0]);
free(_boxes);
}
delete _glyph_loader;
}
const GlyphFace *GlyphCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid
{
if (glyphid >= numGlyphs())
return _glyphs[0];
const GlyphFace * & p = _glyphs[glyphid];
if (p == 0 && _glyph_loader)
{
int numsubs = 0;
GlyphFace * g = new GlyphFace();
if (g) p = _glyph_loader->read_glyph(glyphid, *g, &numsubs);
if (!p)
{
delete g;
return *_glyphs;
}
if (_boxes)
{
_boxes[glyphid] = (GlyphBox *)gralloc<char>(sizeof(GlyphBox) + 8 * numsubs * sizeof(float));
if (!_glyph_loader->read_box(glyphid, _boxes[glyphid], *_glyphs[glyphid]))
{
free(_boxes[glyphid]);
_boxes[glyphid] = 0;
}
}
}
return p;
}
GlyphCache::Loader::Loader(const Face & face)
: _head(face, Tag::head),
_hhea(face, Tag::hhea),
_hmtx(face, Tag::hmtx),
_glyf(face, Tag::glyf),
_loca(face, Tag::loca),
_long_fmt(false),
_has_boxes(false),
_num_glyphs_graphics(0),
_num_glyphs_attributes(0),
_num_attrs(0)
{
if (!operator bool())
return;
const Face::Table maxp = Face::Table(face, Tag::maxp);
if (!maxp) { _head = Face::Table(); return; }
_num_glyphs_graphics = static_cast<unsigned short>(TtfUtil::GlyphCount(maxp));
// This will fail if the number of glyphs is wildly out of range.
if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-2))
{
_head = Face::Table();
return;
}
if ((m_pGlat = Face::Table(face, Tag::Glat, 0x00030000)) == NULL
|| (m_pGloc = Face::Table(face, Tag::Gloc)) == NULL
|| m_pGloc.size() < 8)
{
_head = Face::Table();
return;
}
const byte * p = m_pGloc;
int version = be::read<uint32>(p);
const uint16 flags = be::read<uint16>(p);
_num_attrs = be::read<uint16>(p);
// We can accurately calculate the number of attributed glyphs by
// subtracting the length of the attribids array (numAttribs long if present)
// and dividing by either 2 or 4 depending on shor or lonf format
_long_fmt = flags & 1;
ptrdiff_t tmpnumgattrs = (m_pGloc.size()
- (p - m_pGloc)
- sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
/ (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
|| _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
|| _num_glyphs_graphics > tmpnumgattrs
|| m_pGlat.size() < 4)
{
_head = Face::Table();
return;
}
_num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
p = m_pGlat;
version = be::read<uint32>(p);
if (version >= 0x00040000 || (version >= 0x00030000 && m_pGlat.size() < 8)) // reject Glat tables that are too new
{
_head = Face::Table();
return;
}
else if (version >= 0x00030000)
{
unsigned int glatflags = be::read<uint32>(p);
_has_boxes = glatflags & 1;
// delete this once the compiler is fixed
_has_boxes = true;
}
}
inline
GlyphCache::Loader::operator bool () const throw()
{
return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
}
inline
unsigned short int GlyphCache::Loader::units_per_em() const throw()
{
return _head ? TtfUtil::DesignUnits(_head) : 0;
}
inline
unsigned short int GlyphCache::Loader::num_glyphs() const throw()
{
return max(_num_glyphs_graphics, _num_glyphs_attributes);
}
inline
unsigned short int GlyphCache::Loader::num_attrs() const throw()
{
return _num_attrs;
}
inline
bool GlyphCache::Loader::has_boxes () const throw()
{
return _has_boxes;
}
const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFace & glyph, int *numsubs) const throw()
{
Rect bbox;
Position advance;
if (glyphid < _num_glyphs_graphics)
{
int nLsb;
unsigned int nAdvWid;
if (_glyf)
{
int xMin, yMin, xMax, yMax;
size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
{
if ((xMin > xMax) || (yMin > yMax))
return 0;
bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
Position(static_cast<float>(xMax), static_cast<float>(yMax)));
}
}
if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
advance = Position(static_cast<float>(nAdvWid), 0);
}
if (glyphid < _num_glyphs_attributes)
{
const byte * gloc = m_pGloc;
size_t glocs = 0, gloce = 0;
be::skip<uint32>(gloc);
be::skip<uint16>(gloc,2);
if (_long_fmt)
{
if (8 + glyphid * sizeof(uint32) > m_pGloc.size())
return 0;
be::skip<uint32>(gloc, glyphid);
glocs = be::read<uint32>(gloc);
gloce = be::peek<uint32>(gloc);
}
else
{
if (8 + glyphid * sizeof(uint16) > m_pGloc.size())
return 0;
be::skip<uint16>(gloc, glyphid);
glocs = be::read<uint16>(gloc);
gloce = be::peek<uint16>(gloc);
}
if (glocs >= m_pGlat.size() - 1 || gloce > m_pGlat.size())
return 0;
const uint32 glat_version = be::peek<uint32>(m_pGlat);
if (glat_version >= 0x00030000)
{
if (glocs >= gloce)
return 0;
const byte * p = m_pGlat + glocs;
uint16 bmap = be::read<uint16>(p);
int num = bit_set_count((uint32)bmap);
if (numsubs) *numsubs += num;
glocs += 6 + 8 * num;
if (glocs > gloce)
return 0;
}
if (glat_version < 0x00020000)
{
if (gloce - glocs < 2*sizeof(byte)+sizeof(uint16)
|| gloce - glocs > _num_attrs*(2*sizeof(byte)+sizeof(uint16)))
return 0;
new (&glyph) GlyphFace(bbox, advance, glat_iterator(m_pGlat + glocs), glat_iterator(m_pGlat + gloce));
}
else
{
if (gloce - glocs < 3*sizeof(uint16) // can a glyph have no attributes? why not?
|| gloce - glocs > _num_attrs*3*sizeof(uint16)
|| glocs > m_pGlat.size() - 2*sizeof(uint16))
return 0;
new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
}
if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
return 0;
}
return &glyph;
}
inline float scale_to(uint8 t, float zmin, float zmax)
{
return (zmin + t * (zmax - zmin) / 255);
}
Rect readbox(Rect &b, uint8 zxmin, uint8 zymin, uint8 zxmax, uint8 zymax)
{
return Rect(Position(scale_to(zxmin, b.bl.x, b.tr.x), scale_to(zymin, b.bl.y, b.tr.y)),
Position(scale_to(zxmax, b.bl.x, b.tr.x), scale_to(zymax, b.bl.y, b.tr.y)));
}
GlyphBox * GlyphCache::Loader::read_box(uint16 gid, GlyphBox *curr, const GlyphFace & glyph) const throw()
{
if (gid >= _num_glyphs_attributes) return 0;
const byte * gloc = m_pGloc;
size_t glocs = 0, gloce = 0;
be::skip<uint32>(gloc);
be::skip<uint16>(gloc,2);
if (_long_fmt)
{
be::skip<uint32>(gloc, gid);
glocs = be::read<uint32>(gloc);
gloce = be::peek<uint32>(gloc);
}
else
{
be::skip<uint16>(gloc, gid);
glocs = be::read<uint16>(gloc);
gloce = be::peek<uint16>(gloc);
}
if (gloce > m_pGlat.size() || glocs + 6 >= gloce)
return 0;
const byte * p = m_pGlat + glocs;
uint16 bmap = be::read<uint16>(p);
int num = bit_set_count((uint32)bmap);
Rect bbox = glyph.theBBox();
Rect diamax(Position(bbox.bl.x + bbox.bl.y, bbox.bl.x - bbox.tr.y),
Position(bbox.tr.x + bbox.tr.y, bbox.tr.x - bbox.bl.y));
Rect diabound = readbox(diamax, p[0], p[2], p[1], p[3]);
::new (curr) GlyphBox(num, bmap, &diabound);
be::skip<uint8>(p, 4);
if (glocs + 6 + num * 8 >= gloce)
return 0;
for (int i = 0; i < num * 2; ++i)
{
Rect box = readbox((i & 1) ? diamax : bbox, p[0], p[2], p[1], p[3]);
curr->addSubBox(i >> 1, i & 1, &box);
be::skip<uint8>(p, 4);
}
return (GlyphBox *)((char *)(curr) + sizeof(GlyphBox) + 2 * num * sizeof(Rect));
}

48
thirdparty/graphite/src/GlyphFace.cpp vendored Normal file
View File

@ -0,0 +1,48 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/GlyphFace.h"
using namespace graphite2;
int32 GlyphFace::getMetric(uint8 metric) const
{
switch (metrics(metric))
{
case kgmetLsb : return int32(m_bbox.bl.x);
case kgmetRsb : return int32(m_advance.x - m_bbox.tr.x);
case kgmetBbTop : return int32(m_bbox.tr.y);
case kgmetBbBottom : return int32(m_bbox.bl.y);
case kgmetBbLeft : return int32(m_bbox.bl.x);
case kgmetBbRight : return int32(m_bbox.tr.x);
case kgmetBbHeight : return int32(m_bbox.tr.y - m_bbox.bl.y);
case kgmetBbWidth : return int32(m_bbox.tr.x - m_bbox.bl.x);
case kgmetAdvWidth : return int32(m_advance.x);
case kgmetAdvHeight : return int32(m_advance.y);
default : return 0;
}
}

298
thirdparty/graphite/src/Intervals.cpp vendored Normal file
View File

@ -0,0 +1,298 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <algorithm>
#include <cmath>
#include <limits>
#include "inc/Intervals.h"
#include "inc/Segment.h"
#include "inc/Slot.h"
#include "inc/debug.h"
#include "inc/bits.h"
using namespace graphite2;
#include <cmath>
inline
Zones::Exclusion Zones::Exclusion::split_at(float p) {
Exclusion r(*this);
r.xm = x = p;
return r;
}
inline
void Zones::Exclusion::left_trim(float p) {
x = p;
}
inline
Zones::Exclusion & Zones::Exclusion::operator += (Exclusion const & rhs) {
c += rhs.c; sm += rhs.sm; smx += rhs.smx; open = false;
return *this;
}
inline
uint8 Zones::Exclusion::outcode(float val) const {
float p = val;
//float d = std::numeric_limits<float>::epsilon();
float d = 0.;
return ((p - xm >= d) << 1) | (x - p > d);
}
void Zones::exclude_with_margins(float xmin, float xmax, int axis) {
remove(xmin, xmax);
weightedAxis(axis, xmin-_margin_len, xmin, 0, 0, _margin_weight, xmin-_margin_len, 0, 0, false);
weightedAxis(axis, xmax, xmax+_margin_len, 0, 0, _margin_weight, xmax+_margin_len, 0, 0, false);
}
namespace
{
inline
bool separated(float a, float b) {
return a != b;
//int exp;
//float res = frexpf(fabs(a - b), &exp);
//return (*(unsigned int *)(&res) > 4);
//return std::fabs(a-b) > std::numeric_limits<float>::epsilon(); // std::epsilon may not work. but 0.5 fails exising 64 bit tests
//return std::fabs(a-b) > 0.5f;
}
}
void Zones::insert(Exclusion e)
{
#if !defined GRAPHITE2_NTRACING
addDebug(&e);
#endif
e.x = max(e.x, _pos);
e.xm = min(e.xm, _posm);
if (e.x >= e.xm) return;
for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie && e.x < e.xm; ++i)
{
const uint8 oca = e.outcode(i->x),
ocb = e.outcode(i->xm);
if ((oca & ocb) != 0) continue;
switch (oca ^ ocb) // What kind of overlap?
{
case 0: // e completely covers i
// split e at i.x into e1,e2
// split e2 at i.mx into e2,e3
// drop e1 ,i+e2, e=e3
*i += e;
e.left_trim(i->xm);
break;
case 1: // e overlaps on the rhs of i
// split i at e->x into i1,i2
// split e at i.mx into e1,e2
// trim i1, insert i2+e1, e=e2
if (!separated(i->xm, e.x)) break;
if (separated(i->x,e.x)) { i = _exclusions.insert(i,i->split_at(e.x)); ++i; }
*i += e;
e.left_trim(i->xm);
break;
case 2: // e overlaps on the lhs of i
// split e at i->x into e1,e2
// split i at e.mx into i1,i2
// drop e1, insert e2+i1, trim i2
if (!separated(e.xm, i->x)) return;
if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
*i += e;
return;
case 3: // i completely covers e
// split i at e.x into i1,i2
// split i2 at e.mx into i2,i3
// insert i1, insert e+i2
if (separated(e.xm, i->xm)) i = _exclusions.insert(i,i->split_at(e.xm));
i = _exclusions.insert(i, i->split_at(e.x));
*++i += e;
return;
}
ie = _exclusions.end();
}
}
void Zones::remove(float x, float xm)
{
#if !defined GRAPHITE2_NTRACING
removeDebug(x, xm);
#endif
x = max(x, _pos);
xm = min(xm, _posm);
if (x >= xm) return;
for (iterator i = _exclusions.begin(), ie = _exclusions.end(); i != ie; ++i)
{
const uint8 oca = i->outcode(x),
ocb = i->outcode(xm);
if ((oca & ocb) != 0) continue;
switch (oca ^ ocb) // What kind of overlap?
{
case 0: // i completely covers e
if (separated(i->x, x)) { i = _exclusions.insert(i,i->split_at(x)); ++i; }
GR_FALLTHROUGH;
// no break
case 1: // i overlaps on the rhs of e
i->left_trim(xm);
return;
case 2: // i overlaps on the lhs of e
i->xm = x;
if (separated(i->x, i->xm)) break;
GR_FALLTHROUGH;
// no break
case 3: // e completely covers i
i = _exclusions.erase(i);
--i;
break;
}
ie = _exclusions.end();
}
}
Zones::const_iterator Zones::find_exclusion_under(float x) const
{
size_t l = 0, h = _exclusions.size();
while (l < h)
{
size_t const p = (l+h) >> 1;
switch (_exclusions[p].outcode(x))
{
case 0 : return _exclusions.begin()+p;
case 1 : h = p; break;
case 2 :
case 3 : l = p+1; break;
}
}
return _exclusions.begin()+l;
}
float Zones::closest(float origin, float & cost) const
{
float best_c = std::numeric_limits<float>::max(),
best_x = 0;
const const_iterator start = find_exclusion_under(origin);
// Forward scan looking for lowest cost
for (const_iterator i = start, ie = _exclusions.end(); i != ie; ++i)
if (i->track_cost(best_c, best_x, origin)) break;
// Backward scan looking for lowest cost
// We start from the exclusion to the immediate left of start since we've
// already tested start with the right most scan above.
for (const_iterator i = start-1, ie = _exclusions.begin()-1; i != ie; --i)
if (i->track_cost(best_c, best_x, origin)) break;
cost = (best_c == std::numeric_limits<float>::max() ? -1 : best_c);
return best_x;
}
// Cost and test position functions
bool Zones::Exclusion::track_cost(float & best_cost, float & best_pos, float origin) const {
const float p = test_position(origin),
localc = cost(p - origin);
if (open && localc > best_cost) return true;
if (localc < best_cost)
{
best_cost = localc;
best_pos = p;
}
return false;
}
inline
float Zones::Exclusion::cost(float p) const {
return (sm * p - 2 * smx) * p + c;
}
float Zones::Exclusion::test_position(float origin) const {
if (sm < 0)
{
// sigh, test both ends and perhaps the middle too!
float res = x;
float cl = cost(x);
if (x < origin && xm > origin)
{
float co = cost(origin);
if (co < cl)
{
cl = co;
res = origin;
}
}
float cr = cost(xm);
return cl > cr ? xm : res;
}
else
{
float zerox = smx / sm + origin;
if (zerox < x) return x;
else if (zerox > xm) return xm;
else return zerox;
}
}
#if !defined GRAPHITE2_NTRACING
void Zones::jsonDbgOut(Segment *seg) const {
if (_dbg)
{
for (Zones::idebugs s = dbgs_begin(), e = dbgs_end(); s != e; ++s)
{
*_dbg << json::flat << json::array
<< objectid(dslot(seg, (Slot *)(s->_env[0])))
<< reinterpret_cast<ptrdiff_t>(s->_env[1]);
if (s->_isdel)
*_dbg << "remove" << Position(s->_excl.x, s->_excl.xm);
else
*_dbg << "exclude" << json::flat << json::array
<< s->_excl.x << s->_excl.xm
<< s->_excl.sm << s->_excl.smx << s->_excl.c
<< json::close;
*_dbg << json::close;
}
}
}
#endif

282
thirdparty/graphite/src/Justifier.cpp vendored Normal file
View File

@ -0,0 +1,282 @@
/* GRAPHITE2 LICENSING
Copyright 2012, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Segment.h"
#include "graphite2/Font.h"
#include "inc/debug.h"
#include "inc/CharInfo.h"
#include "inc/Slot.h"
#include "inc/Main.h"
#include <cmath>
using namespace graphite2;
class JustifyTotal {
public:
JustifyTotal() : m_numGlyphs(0), m_tStretch(0), m_tShrink(0), m_tStep(0), m_tWeight(0) {}
void accumulate(Slot *s, Segment *seg, int level);
int weight() const { return m_tWeight; }
CLASS_NEW_DELETE
private:
int m_numGlyphs;
int m_tStretch;
int m_tShrink;
int m_tStep;
int m_tWeight;
};
void JustifyTotal::accumulate(Slot *s, Segment *seg, int level)
{
++m_numGlyphs;
m_tStretch += s->getJustify(seg, level, 0);
m_tShrink += s->getJustify(seg, level, 1);
m_tStep += s->getJustify(seg, level, 2);
m_tWeight += s->getJustify(seg, level, 3);
}
float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags jflags, Slot *pFirst, Slot *pLast)
{
Slot *end = last();
float currWidth = 0.0;
const float scale = font ? font->scale() : 1.0f;
Position res;
if (width < 0 && !(silf()->flags()))
return width;
if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
{
reverseSlots();
std::swap(pFirst, pLast);
}
if (!pFirst) pFirst = pSlot;
while (!pFirst->isBase()) pFirst = pFirst->attachedTo();
if (!pLast) pLast = last();
while (!pLast->isBase()) pLast = pLast->attachedTo();
const float base = pFirst->origin().x / scale;
width = width / scale;
if ((jflags & gr_justEndInline) == 0)
{
while (pLast != pFirst && pLast)
{
Rect bbox = theGlyphBBoxTemporary(pLast->glyph());
if (bbox.bl.x != 0.f || bbox.bl.y != 0.f || bbox.tr.x != 0.f || bbox.tr.y == 0.f)
break;
pLast = pLast->prev();
}
}
if (pLast)
end = pLast->nextSibling();
if (pFirst)
pFirst = pFirst->nextSibling();
int icount = 0;
int numLevels = silf()->numJustLevels();
if (!numLevels)
{
for (Slot *s = pSlot; s && s != end; s = s->nextSibling())
{
CharInfo *c = charinfo(s->before());
if (isWhitespace(c->unicodeChar()))
{
s->setJustify(this, 0, 3, 1);
s->setJustify(this, 0, 2, 1);
s->setJustify(this, 0, 0, -1);
++icount;
}
}
if (!icount)
{
for (Slot *s = pSlot; s && s != end; s = s->nextSibling())
{
s->setJustify(this, 0, 3, 1);
s->setJustify(this, 0, 2, 1);
s->setJustify(this, 0, 0, -1);
}
}
++numLevels;
}
Vector<JustifyTotal> stats(numLevels);
for (Slot *s = pFirst; s && s != end; s = s->nextSibling())
{
float w = s->origin().x / scale + s->advance() - base;
if (w > currWidth) currWidth = w;
for (int j = 0; j < numLevels; ++j)
stats[j].accumulate(s, this, j);
s->just(0);
}
for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
{
float diff;
float error = 0.;
float diffpw;
int tWeight = stats[i].weight();
if (tWeight == 0) continue;
do {
error = 0.;
diff = width - currWidth;
diffpw = diff / tWeight;
tWeight = 0;
for (Slot *s = pFirst; s && s != end; s = s->nextSibling()) // don't include final glyph
{
int w = s->getJustify(this, i, 3);
float pref = diffpw * w + error;
int step = s->getJustify(this, i, 2);
if (!step) step = 1; // handle lazy font developers
if (pref > 0)
{
float max = uint16(s->getJustify(this, i, 0));
if (i == 0) max -= s->just();
if (pref > max) pref = max;
else tWeight += w;
}
else
{
float max = uint16(s->getJustify(this, i, 1));
if (i == 0) max += s->just();
if (-pref > max) pref = -max;
else tWeight += w;
}
int actual = int(pref / step) * step;
if (actual)
{
error += diffpw * w - actual;
if (i == 0)
s->just(s->just() + actual);
else
s->setJustify(this, i, 4, actual);
}
}
currWidth += diff - error;
} while (i == 0 && int(std::abs(error)) > 0 && tWeight);
}
Slot *oldFirst = m_first;
Slot *oldLast = m_last;
if (silf()->flags() & 1)
{
m_first = pSlot = addLineEnd(pSlot);
m_last = pLast = addLineEnd(end);
if (!m_first || !m_last) return -1.0;
}
else
{
m_first = pSlot;
m_last = pLast;
}
// run justification passes here
#if !defined GRAPHITE2_NTRACING
json * const dbgout = m_face->logger();
if (dbgout)
*dbgout << json::object
<< "justifies" << objectid(this)
<< "passes" << json::array;
#endif
if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0.f || (silf()->flags() & 1)))
m_silf->runGraphite(this, m_silf->justificationPass(), m_silf->positionPass());
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
*dbgout << json::item << json::close; // Close up the passes array
positionSlots(NULL, pSlot, pLast, m_dir);
Slot *lEnd = pLast->nextSibling();
*dbgout << "output" << json::array;
for(Slot * t = pSlot; t != lEnd; t = t->next())
*dbgout << dslot(this, t);
*dbgout << json::close << json::close;
}
#endif
res = positionSlots(font, pSlot, pLast, m_dir);
if (silf()->flags() & 1)
{
if (m_first)
delLineEnd(m_first);
if (m_last)
delLineEnd(m_last);
}
m_first = oldFirst;
m_last = oldLast;
if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
reverseSlots();
return res.x;
}
Slot *Segment::addLineEnd(Slot *nSlot)
{
Slot *eSlot = newSlot();
if (!eSlot) return NULL;
const uint16 gid = silf()->endLineGlyphid();
const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
eSlot->setGlyph(this, gid, theGlyph);
if (nSlot)
{
eSlot->next(nSlot);
eSlot->prev(nSlot->prev());
nSlot->prev(eSlot);
eSlot->before(nSlot->before());
if (eSlot->prev())
eSlot->after(eSlot->prev()->after());
else
eSlot->after(nSlot->before());
}
else
{
nSlot = m_last;
eSlot->prev(nSlot);
nSlot->next(eSlot);
eSlot->after(eSlot->prev()->after());
eSlot->before(nSlot->after());
}
return eSlot;
}
void Segment::delLineEnd(Slot *s)
{
Slot *nSlot = s->next();
if (nSlot)
{
nSlot->prev(s->prev());
if (s->prev())
s->prev()->next(nSlot);
}
else
s->prev()->next(NULL);
freeSlot(s);
}

254
thirdparty/graphite/src/NameTable.cpp vendored Normal file
View File

@ -0,0 +1,254 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Main.h"
#include "inc/Endian.h"
#include "inc/NameTable.h"
#include "inc/UtfCodec.h"
using namespace graphite2;
NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID)
: m_platformId(0), m_encodingId(0), m_languageCount(0),
m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),
m_table(0), m_nameData(NULL)
{
void *pdata = gralloc<byte>(length);
if (!pdata) return;
memcpy(pdata, data, length);
m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
(length > sizeof(TtfUtil::Sfnt::FontNames) +
sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
{
uint16 offset = be::swap<uint16>(m_table->string_offset);
if (offset < length)
{
m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
setPlatformEncoding(platformId, encodingID);
m_nameDataLength = uint16(length - offset);
return;
}
}
free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
m_table = NULL;
}
uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
{
if (!m_nameData) return 0;
uint16 i = 0;
uint16 count = be::swap<uint16>(m_table->count);
for (; i < count; i++)
{
if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId &&
be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)
{
m_platformOffset = i;
break;
}
}
while ((++i < count) &&
(be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) &&
(be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID))
{
m_platformLastRecord = i;
}
m_encodingId = encodingID;
m_platformId = platformId;
return 0;
}
void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length)
{
uint16 anyLang = 0;
uint16 enUSLang = 0;
uint16 bestLang = 0;
if (!m_table)
{
languageId = 0;
length = 0;
return NULL;
}
for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++)
{
if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId)
{
uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id);
if (langId == languageId)
{
bestLang = i;
break;
}
// MS language tags have the language in the lower byte, region in the higher
else if ((langId & 0xFF) == (languageId & 0xFF))
{
bestLang = i;
}
else if (langId == 0x409)
{
enUSLang = i;
}
else
{
anyLang = i;
}
}
}
if (!bestLang)
{
if (enUSLang) bestLang = enUSLang;
else
{
bestLang = anyLang;
if (!anyLang)
{
languageId = 0;
length = 0;
return NULL;
}
}
}
const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang];
languageId = be::swap<uint16>(nameRecord.language_id);
uint16 utf16Length = be::swap<uint16>(nameRecord.length);
uint16 offset = be::swap<uint16>(nameRecord.offset);
if(offset + utf16Length > m_nameDataLength)
{
languageId = 0;
length = 0;
return NULL;
}
utf16Length >>= 1; // in utf16 units
utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length + 1);
if (!utf16Name)
{
languageId = 0;
length = 0;
return NULL;
}
const uint8* pName = m_nameData + offset;
for (size_t i = 0; i < utf16Length; i++)
{
utf16Name[i] = be::read<uint16>(pName);
}
utf16Name[utf16Length] = 0;
if (!utf16::validate(utf16Name, utf16Name + utf16Length))
{
free(utf16Name);
languageId = 0;
length = 0;
return NULL;
}
switch (enc)
{
case gr_utf8:
{
utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
if (!uniBuffer)
{
free(utf16Name);
languageId = 0;
length = 0;
return NULL;
}
utf8::iterator d = uniBuffer;
for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
*d = *s;
length = uint32(d - uniBuffer);
uniBuffer[length] = 0;
free(utf16Name);
return uniBuffer;
}
case gr_utf16:
length = utf16Length;
return utf16Name;
case gr_utf32:
{
utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);
if (!uniBuffer)
{
free(utf16Name);
languageId = 0;
length = 0;
return NULL;
}
utf32::iterator d = uniBuffer;
for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
*d = *s;
length = uint32(d - uniBuffer);
uniBuffer[length] = 0;
free(utf16Name);
return uniBuffer;
}
}
free(utf16Name);
languageId = 0;
length = 0;
return NULL;
}
uint16 NameTable::getLanguageId(const char * bcp47Locale)
{
size_t localeLength = strlen(bcp47Locale);
uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);
if (m_table && (be::swap<uint16>(m_table->format) == 1))
{
const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +
sizeof(TtfUtil::Sfnt::FontNames)
+ sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);
uint16 numLangEntries = be::read<uint16>(pLangEntries);
const TtfUtil::Sfnt::LangTagRecord * langTag =
reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);
if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)
{
for (uint16 i = 0; i < numLangEntries; i++)
{
uint16 offset = be::swap<uint16>(langTag[i].offset);
uint16 length = be::swap<uint16>(langTag[i].length);
if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))
{
const uint8* pName = m_nameData + offset;
bool match = true;
for (size_t j = 0; j < localeLength; j++)
{
uint16 code = be::read<uint16>(pName);
if ((code > 0x7F) || (code != bcp47Locale[j]))
{
match = false;
break;
}
}
if (match)
return 0x8000 + i;
}
}
}
}
return localeId;
}

1107
thirdparty/graphite/src/Pass.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

97
thirdparty/graphite/src/Position.cpp vendored Normal file
View File

@ -0,0 +1,97 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Position.h"
#include <cmath>
using namespace graphite2;
bool Rect::hitTest(Rect &other)
{
if (bl.x > other.tr.x) return false;
if (tr.x < other.bl.x) return false;
if (bl.y > other.tr.y) return false;
if (tr.y < other.bl.y) return false;
return true;
}
Position Rect::overlap(Position &offset, Rect &other, Position &othero)
{
float ax = (bl.x + offset.x) - (other.tr.x + othero.x);
float ay = (bl.y + offset.y) - (other.tr.y + othero.y);
float bx = (other.bl.x + othero.x) - (tr.x + offset.x);
float by = (other.bl.y + othero.y) - (tr.y + offset.y);
return Position((ax > bx ? ax : bx), (ay > by ? ay : by));
}
float boundmin(float move, float lim1, float lim2, float &error)
{
// error is always positive for easy comparison
if (move < lim1 && move < lim2)
{ error = 0.; return move; }
else if (lim1 < lim2)
{ error = std::fabs(move - lim1); return lim1; }
else
{ error = std::fabs(move - lim2); return lim2; }
}
#if 0
Position Rect::constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox)
{
// a = max, i = min, s = sum, d = diff
float eax, eay, eix, eiy, eas, eis, ead, eid;
float beste = INF;
Position res;
// calculate the movements in each direction and the error (amount of remaining overlap)
// first param is movement, second and third are movement over the constraining box
float ax = boundmin(obox.tr.x + other.x - box.bl.x - offset.x + 1, tr.x - offset.x, INF, &eax);
float ay = boundmin(obox.tr.y + other.y - box.bl.y - offset.y + 1, tr.y - offset.y, INF, &eay);
float ix = boundmin(obox.bl.x + other.x - box.tr.x - offset.x + 1, bl.x - offset.x, INF, &eix);
float iy = boundmin(obox.bl.y + other.y - box.tr.y - offset.y + 1, bl.y - offset.y, INF, &eiy);
float as = boundmin(ISQRT2 * (osdbox.tr.x + other.x + other.y - sdbox.bl.x - offset.x - offset.y) + 1, tr.x - offset.x, tr.y - offset.y, &eas);
float is = boundmin(ISQRT2 * (osdbox.bl.x + other.x + other.y - sdbox.tr.x - offset.x - offset.y) + 1, bl.x - offset.x, bl.y - offset.y, &eis);
float ad = boundmin(ISQRT2 * (osdbox.tr.y + other.x - other.y - sdbox.bl.y - offset.x + offset.y) + 1, tr.y - offset.y, tr.x - offset.x, &ead);
float id = boundmin(ISQRT2 * (osdbox.bl.y + other.x - other.y - sdbox.tr.y - offset.x + offset.y) + 1, bl.y - offset.y, bl.x - offset.x, &eid);
if (eax < beste)
{ res = Position(ax, 0); beste = eax; }
if (eay < beste)
{ res = Position(0, ay); beste = eay; }
if (eix < beste)
{ res = Position(ix, 0); beste = eix; }
if (eiy < beste)
{ res = Position(0, iy); beste = eiy; }
if (SQRT2 * (eas) < beste)
{ res = Position(as, ad); beste = SQRT2 * (eas); }
if (SQRT2 * (eis) < beste)
{ res = Position(is, is); beste = SQRT2 * (eis); }
if (SQRT2 * (ead) < beste)
{ res = Position(ad, ad); beste = SQRT2 * (ead); }
if (SQRT2 * (eid) < beste)
{ res = Position(id, id); beste = SQRT2 * (eid); }
return res;
}
#endif

423
thirdparty/graphite/src/Segment.cpp vendored Normal file
View File

@ -0,0 +1,423 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/UtfCodec.h"
#include <cstring>
#include <cstdlib>
#include "inc/bits.h"
#include "inc/Segment.h"
#include "graphite2/Font.h"
#include "inc/CharInfo.h"
#include "inc/debug.h"
#include "inc/Slot.h"
#include "inc/Main.h"
#include "inc/CmapCache.h"
#include "inc/Collider.h"
#include "graphite2/Segment.h"
using namespace graphite2;
Segment::Segment(size_t numchars, const Face* face, uint32 script, int textDir)
: m_freeSlots(NULL),
m_freeJustifies(NULL),
m_charinfo(new CharInfo[numchars]),
m_collisions(NULL),
m_face(face),
m_silf(face->chooseSilf(script)),
m_first(NULL),
m_last(NULL),
m_bufSize(numchars + 10),
m_numGlyphs(numchars),
m_numCharinfo(numchars),
m_defaultOriginal(0),
m_dir(textDir),
m_flags(((m_silf->flags() & 0x20) != 0) << 1),
m_passBits(m_silf->aPassBits() ? -1 : 0)
{
freeSlot(newSlot());
m_bufSize = log_binary(numchars)+1;
}
Segment::~Segment()
{
for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
free(*i);
for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
free(*i);
for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
free(*i);
delete[] m_charinfo;
free(m_collisions);
}
void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
{
Slot *aSlot = newSlot();
if (!aSlot) return;
m_charinfo[id].init(cid);
m_charinfo[id].feats(iFeats);
m_charinfo[id].base(coffset);
const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0);
aSlot->child(NULL);
aSlot->setGlyph(this, gid, theGlyph);
aSlot->originate(id);
aSlot->before(id);
aSlot->after(id);
if (m_last) m_last->next(aSlot);
aSlot->prev(m_last);
m_last = aSlot;
if (!m_first) m_first = aSlot;
if (theGlyph && m_silf->aPassBits())
m_passBits &= theGlyph->attrs()[m_silf->aPassBits()]
| (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);
}
Slot *Segment::newSlot()
{
if (!m_freeSlots)
{
// check that the segment doesn't grow indefinintely
if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)
return NULL;
int numUser = m_silf->numUser();
#if !defined GRAPHITE2_NTRACING
if (m_face->logger()) ++numUser;
#endif
Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
int16 *newAttrs = grzeroalloc<int16>(m_bufSize * numUser);
if (!newSlots || !newAttrs)
{
free(newSlots);
free(newAttrs);
return NULL;
}
for (size_t i = 0; i < m_bufSize; i++)
{
::new (newSlots + i) Slot(newAttrs + i * numUser);
newSlots[i].next(newSlots + i + 1);
}
newSlots[m_bufSize - 1].next(NULL);
newSlots[0].next(NULL);
m_slots.push_back(newSlots);
m_userAttrs.push_back(newAttrs);
m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
return newSlots;
}
Slot *res = m_freeSlots;
m_freeSlots = m_freeSlots->next();
res->next(NULL);
return res;
}
void Segment::freeSlot(Slot *aSlot)
{
if (aSlot == nullptr) return;
if (m_last == aSlot) m_last = aSlot->prev();
if (m_first == aSlot) m_first = aSlot->next();
if (aSlot->attachedTo())
aSlot->attachedTo()->removeChild(aSlot);
while (aSlot->firstChild())
{
if (aSlot->firstChild()->attachedTo() == aSlot)
{
aSlot->firstChild()->attachTo(nullptr);
aSlot->removeChild(aSlot->firstChild());
}
else
aSlot->firstChild(nullptr);
}
// reset the slot incase it is reused
::new (aSlot) Slot(aSlot->userAttrs());
memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
// Update generation counter for debug
#if !defined GRAPHITE2_NTRACING
if (m_face->logger())
++aSlot->userAttrs()[m_silf->numUser()];
#endif
// update next pointer
if (!m_freeSlots)
aSlot->next(nullptr);
else
aSlot->next(m_freeSlots);
m_freeSlots = aSlot;
}
SlotJustify *Segment::newJustify()
{
if (!m_freeJustifies)
{
const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());
byte *justs = grzeroalloc<byte>(justSize * m_bufSize);
if (!justs) return NULL;
for (ptrdiff_t i = m_bufSize - 2; i >= 0; --i)
{
SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);
SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1));
p->next = next;
}
m_freeJustifies = (SlotJustify *)justs;
m_justifies.push_back(m_freeJustifies);
}
SlotJustify *res = m_freeJustifies;
m_freeJustifies = m_freeJustifies->next;
res->next = NULL;
return res;
}
void Segment::freeJustify(SlotJustify *aJustify)
{
int numJust = m_silf->numJustLevels();
if (m_silf->numJustLevels() <= 0) numJust = 1;
aJustify->next = m_freeJustifies;
memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16));
m_freeJustifies = aJustify;
}
// reverse the slots but keep diacritics in their same position after their bases
void Segment::reverseSlots()
{
m_dir = m_dir ^ 64; // invert the reverse flag
if (m_first == m_last) return; // skip 0 or 1 glyph runs
Slot *t = 0;
Slot *curr = m_first;
Slot *tlast;
Slot *tfirst;
Slot *out = 0;
while (curr && getSlotBidiClass(curr) == 16)
curr = curr->next();
if (!curr) return;
tfirst = curr->prev();
tlast = curr;
while (curr)
{
if (getSlotBidiClass(curr) == 16)
{
Slot *d = curr->next();
while (d && getSlotBidiClass(d) == 16)
d = d->next();
d = d ? d->prev() : m_last;
Slot *p = out->next(); // one after the diacritics. out can't be null
if (p)
p->prev(d);
else
tlast = d;
t = d->next();
d->next(p);
curr->prev(out);
out->next(curr);
}
else // will always fire first time round the loop
{
if (out)
out->prev(curr);
t = curr->next();
curr->next(out);
out = curr;
}
curr = t;
}
out->prev(tfirst);
if (tfirst)
tfirst->next(out);
else
m_first = out;
m_last = tlast;
}
void Segment::linkClusters(Slot *s, Slot * end)
{
end = end->next();
for (; s != end && !s->isBase(); s = s->next());
Slot * ls = s;
if (m_dir & 1)
{
for (; s != end; s = s->next())
{
if (!s->isBase()) continue;
s->sibling(ls);
ls = s;
}
}
else
{
for (; s != end; s = s->next())
{
if (!s->isBase()) continue;
ls->sibling(s);
ls = s;
}
}
}
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
{
Position currpos(0., 0.);
float clusterMin = 0.;
Rect bbox;
bool reorder = (currdir() != isRtl);
if (reorder)
{
Slot *temp;
reverseSlots();
temp = iStart;
iStart = iEnd;
iEnd = temp;
}
if (!iStart) iStart = m_first;
if (!iEnd) iEnd = m_last;
if (!iStart || !iEnd) // only true for empty segments
return currpos;
if (isRtl)
{
for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
{
if (s->isBase())
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
else
{
for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
{
if (s->isBase())
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
if (reorder)
reverseSlots();
return currpos;
}
void Segment::associateChars(int offset, size_t numChars)
{
int i = 0, j = 0;
CharInfo *c, *cend;
for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)
{
c->before(-1);
c->after(-1);
}
for (Slot * s = m_first; s; s->index(i++), s = s->next())
{
j = s->before();
if (j < 0) continue;
for (const int after = s->after(); j <= after; ++j)
{
c = charinfo(j);
if (c->before() == -1 || i < c->before()) c->before(i);
if (c->after() < i) c->after(i);
}
}
for (Slot *s = m_first; s; s = s->next())
{
int a;
for (a = s->after() + 1; a < offset + int(numChars) && charinfo(a)->after() < 0; ++a)
{ charinfo(a)->after(s->index()); }
--a;
s->after(a);
for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)
{ charinfo(a)->before(s->index()); }
++a;
s->before(a);
}
}
template <typename utf_iter>
inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
{
const Cmap & cmap = face.cmap();
int slotid = 0;
const typename utf_iter::codeunit_type * const base = c;
for (; n_chars; --n_chars, ++c, ++slotid)
{
const uint32 usv = *c;
uint16 gid = cmap[usv];
if (!gid) gid = face.findPseudo(usv);
seg.appendSlot(slotid, usv, gid, fid, c - base);
}
}
bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
{
assert(face);
assert(pFeats);
if (!m_charinfo) return false;
// utf iterator is self recovering so we don't care about the error state of the iterator.
switch (enc)
{
case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
}
return true;
}
void Segment::doMirror(uint16 aMirror)
{
Slot * s;
for (s = m_first; s; s = s->next())
{
unsigned short g = glyphAttr(s->gid(), aMirror);
if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
s->setGlyph(this, g);
}
}
bool Segment::initCollisions()
{
m_collisions = grzeroalloc<SlotCollision>(slotCount());
if (!m_collisions) return false;
for (Slot *p = m_first; p; p = p->next())
if (p->index() < slotCount())
::new (collisionInfo(p)) SlotCollision(this, p);
else
return false;
return true;
}

439
thirdparty/graphite/src/Silf.cpp vendored Normal file
View File

@ -0,0 +1,439 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cstdlib>
#include "graphite2/Segment.h"
#include "inc/debug.h"
#include "inc/Endian.h"
#include "inc/Silf.h"
#include "inc/Segment.h"
#include "inc/Rule.h"
#include "inc/Error.h"
using namespace graphite2;
namespace { static const uint32 ERROROFFSET = 0xFFFFFFFF; }
Silf::Silf() throw()
: m_passes(0),
m_pseudos(0),
m_classOffsets(0),
m_classData(0),
m_justs(0),
m_numPasses(0),
m_numJusts(0),
m_sPass(0),
m_pPass(0),
m_jPass(0),
m_bPass(0),
m_flags(0),
m_dir(0),
m_aPseudo(0),
m_aBreak(0),
m_aUser(0),
m_aBidi(0),
m_aMirror(0),
m_aPassBits(0),
m_iMaxComp(0),
m_aCollision(0),
m_aLig(0),
m_numPseudo(0),
m_nClass(0),
m_nLinear(0),
m_gEndLine(0)
{
memset(&m_silfinfo, 0, sizeof m_silfinfo);
}
Silf::~Silf() throw()
{
releaseBuffers();
}
void Silf::releaseBuffers() throw()
{
delete [] m_passes;
delete [] m_pseudos;
free(m_classOffsets);
free(m_classData);
free(m_justs);
m_passes= 0;
m_pseudos = 0;
m_classOffsets = 0;
m_classData = 0;
m_justs = 0;
}
bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, uint32 version)
{
const byte * p = silf_start,
* const silf_end = p + lSilf;
Error e;
if (e.test(version >= 0x00060000, E_BADSILFVERSION))
{
releaseBuffers(); return face.error(e);
}
if (version >= 0x00030000)
{
if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
be::skip<int32>(p); // ruleVersion
be::skip<uint16>(p,2); // passOffset & pseudosOffset
}
else if (e.test(lSilf < 20, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
const uint16 maxGlyph = be::read<uint16>(p);
m_silfinfo.extra_ascent = be::read<uint16>(p);
m_silfinfo.extra_descent = be::read<uint16>(p);
m_numPasses = be::read<uint8>(p);
m_sPass = be::read<uint8>(p);
m_pPass = be::read<uint8>(p);
m_jPass = be::read<uint8>(p);
m_bPass = be::read<uint8>(p);
m_flags = be::read<uint8>(p);
be::skip<uint8>(p,2); // max{Pre,Post}Context.
m_aPseudo = be::read<uint8>(p);
m_aBreak = be::read<uint8>(p);
m_aBidi = be::read<uint8>(p);
m_aMirror = be::read<uint8>(p);
m_aPassBits = be::read<uint8>(p);
// Read Justification levels.
m_numJusts = be::read<uint8>(p);
if (e.test(maxGlyph >= face.glyphs().numGlyphs(), E_BADMAXGLYPH)
|| e.test(p + m_numJusts * 8 >= silf_end, E_BADNUMJUSTS))
{
releaseBuffers(); return face.error(e);
}
if (m_numJusts)
{
m_justs = gralloc<Justinfo>(m_numJusts);
if (e.test(!m_justs, E_OUTOFMEM)) return face.error(e);
for (uint8 i = 0; i < m_numJusts; i++)
{
::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
be::skip<byte>(p,8);
}
}
if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
m_aLig = be::read<uint16>(p);
m_aUser = be::read<uint8>(p);
m_iMaxComp = be::read<uint8>(p);
m_dir = be::read<uint8>(p) - 1;
m_aCollision = be::read<uint8>(p);
be::skip<byte>(p,3);
be::skip<uint16>(p, be::read<uint8>(p)); // don't need critical features yet
be::skip<byte>(p); // reserved
if (e.test(p >= silf_end, E_BADCRITFEATURES)) { releaseBuffers(); return face.error(e); }
be::skip<uint32>(p, be::read<uint8>(p)); // don't use scriptTag array.
if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
m_gEndLine = be::read<uint16>(p); // lbGID
const byte * o_passes = p;
uint32 passes_start = be::read<uint32>(p);
const size_t num_attrs = face.glyphs().numAttrs();
if (e.test(m_aPseudo >= num_attrs, E_BADAPSEUDO)
|| e.test(m_aBreak >= num_attrs, E_BADABREAK)
|| e.test(m_aBidi >= num_attrs, E_BADABIDI)
|| e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
|| e.test(m_aCollision && m_aCollision >= num_attrs - 5, E_BADACOLLISION)
|| e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= lSilf, E_BADPASSESSTART)
|| e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
|| e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
|| e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
|| e.test(m_aLig > 127, E_BADALIG))
{
releaseBuffers();
return face.error(e);
}
be::skip<uint32>(p, m_numPasses);
if (e.test(unsigned(p - silf_start) + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
m_numPseudo = be::read<uint16>(p);
be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
m_pseudos = new Pseudo[m_numPseudo];
if (e.test(unsigned(p - silf_start) + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
|| e.test(!m_pseudos, E_OUTOFMEM))
{
releaseBuffers(); return face.error(e);
}
for (int i = 0; i < m_numPseudo; i++)
{
m_pseudos[i].uid = be::read<uint32>(p);
m_pseudos[i].gid = be::read<uint16>(p);
}
const size_t clen = readClassMap(p, passes_start + silf_start - p, version, e);
m_passes = new Pass[m_numPasses];
if (e || e.test(clen > unsigned(passes_start + silf_start - p), E_BADPASSESSTART)
|| e.test(!m_passes, E_OUTOFMEM))
{ releaseBuffers(); return face.error(e); }
for (size_t i = 0; i < m_numPasses; ++i)
{
uint32 pass_start = be::read<uint32>(o_passes);
uint32 pass_end = be::peek<uint32>(o_passes);
face.error_context((face.error_context() & 0xFF00) + EC_ASILF + unsigned(i << 16));
if (e.test(pass_start > pass_end, E_BADPASSSTART)
|| e.test(pass_start < passes_start, E_BADPASSSTART)
|| e.test(pass_end > lSilf, E_BADPASSEND)) {
releaseBuffers(); return face.error(e);
}
enum passtype pt = PASS_TYPE_UNKNOWN;
if (i >= m_jPass) pt = PASS_TYPE_JUSTIFICATION;
else if (i >= m_pPass) pt = PASS_TYPE_POSITIONING;
else if (i >= m_sPass) pt = PASS_TYPE_SUBSTITUTE;
else pt = PASS_TYPE_LINEBREAK;
m_passes[i].init(this);
if (!m_passes[i].readPass(silf_start + pass_start, pass_end - pass_start, pass_start, face, pt,
version, e))
{
releaseBuffers();
return false;
}
}
// fill in gr_faceinfo
m_silfinfo.upem = face.glyphs().unitsPerEm();
m_silfinfo.has_bidi_pass = (m_bPass != 0xFF);
m_silfinfo.justifies = (m_numJusts != 0) || (m_jPass < m_pPass);
m_silfinfo.line_ends = (m_flags & 1);
m_silfinfo.space_contextuals = gr_faceinfo::gr_space_contextuals((m_flags >> 2) & 0x7);
return true;
}
template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len, Error &e)
{
const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
const uint32 max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
// Check that the last+1 offset is less than or equal to the class map length.
if (e.test(be::peek<T>(p) != cls_off, E_MISALIGNEDCLASSES)
|| e.test(max_off > (data_len - cls_off)/sizeof(uint16), E_HIGHCLASSOFFSET))
return ERROROFFSET;
// Read in all the offsets.
m_classOffsets = gralloc<uint32>(m_nClass+1);
if (e.test(!m_classOffsets, E_OUTOFMEM)) return ERROROFFSET;
for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
{
*o = (be::read<T>(p) - cls_off)/sizeof(uint16);
if (e.test(*o > max_off, E_HIGHCLASSOFFSET))
return ERROROFFSET;
}
return max_off;
}
size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error &e)
{
if (e.test(data_len < sizeof(uint16)*2, E_BADCLASSSIZE)) return ERROROFFSET;
m_nClass = be::read<uint16>(p);
m_nLinear = be::read<uint16>(p);
// Check that numLinear < numClass,
// that there is at least enough data for numClasses offsets.
if (e.test(m_nLinear > m_nClass, E_TOOMANYLINEAR)
|| e.test((m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16)) > (data_len - 4), E_CLASSESTOOBIG))
return ERROROFFSET;
uint32 max_off;
if (version >= 0x00040000)
max_off = readClassOffsets<uint32>(p, data_len, e);
else
max_off = readClassOffsets<uint16>(p, data_len, e);
if (max_off == ERROROFFSET) return ERROROFFSET;
if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG))
return ERROROFFSET;
// Check the linear offsets are sane, these must be monotonically increasing.
assert(m_nClass >= m_nLinear);
for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
return ERROROFFSET;
// Fortunately the class data is all uint16s so we can decode these now
m_classData = gralloc<uint16>(max_off);
if (e.test(!m_classData, E_OUTOFMEM)) return ERROROFFSET;
for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
*d = be::read<uint16>(p);
// Check the lookup class invariants for each non-linear class
for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
{
const uint16 * lookup = m_classData + *o;
if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off
|| e.test(lookup[0] == 0 // A LookupClass with no looks is a suspicious thing ...
|| lookup[0] * 2 + *o + 4 > max_off // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
|| lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO) // rangeShift: numIDs - searchRange
|| e.test(((o[1] - *o) & 1) != 0, ERROROFFSET)) // glyphs are in pairs so difference must be even.
return ERROROFFSET;
}
return max_off;
}
uint16 Silf::findPseudo(uint32 uid) const
{
for (int i = 0; i < m_numPseudo; i++)
if (m_pseudos[i].uid == uid) return m_pseudos[i].gid;
return 0;
}
uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
{
if (cid > m_nClass) return -1;
const uint16 * cls = m_classData + m_classOffsets[cid];
if (cid < m_nLinear) // output class being used for input, shouldn't happen
{
for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls)
if (*cls == gid) return i;
return -1;
}
else
{
const uint16 * min = cls + 4, // lookups array
* max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
do
{
const uint16 * p = min + (-2 & ((max-min)/2));
if (p[0] > gid) max = p;
else min = p;
}
while (max - min > 2);
return min[0] == gid ? min[1] : -1;
}
}
uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
{
if (cid > m_nClass) return 0;
uint32 loc = m_classOffsets[cid];
if (cid < m_nLinear)
{
if (index < m_classOffsets[cid + 1] - loc)
return m_classData[index + loc];
}
else // input class being used for output. Shouldn't happen
{
for (unsigned int i = loc + 4; i < m_classOffsets[cid + 1]; i += 2)
if (m_classData[i + 1] == index) return m_classData[i];
}
return 0;
}
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
{
assert(seg != 0);
size_t maxSize = seg->slotCount() * MAX_SEG_GROWTH_FACTOR;
SlotMap map(*seg, m_dir, maxSize);
FiniteStateMachine fsm(map, seg->getFace()->logger());
vm::Machine m(map);
uint8 lbidi = m_bPass;
#if !defined GRAPHITE2_NTRACING
json * const dbgout = seg->getFace()->logger();
#endif
if (lastPass == 0)
{
if (firstPass == lastPass && lbidi == 0xFF)
return true;
lastPass = m_numPasses;
}
if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi)))
lastPass++;
else
lbidi = 0xFF;
for (size_t i = firstPass; i < lastPass; ++i)
{
// bidi and mirroring
if (i == lbidi)
{
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
*dbgout << json::item << json::object
// << "pindex" << i // for debugging
<< "id" << -1
<< "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
<< "passdir" << (m_dir & 1 ? "rtl" : "ltr")
<< "slots" << json::array;
seg->positionSlots(0, 0, 0, seg->currdir());
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close
<< "rules" << json::array << json::close
<< json::close;
}
#endif
if (seg->currdir() != (m_dir & 1))
seg->reverseSlots();
if (m_aMirror && (seg->dir() & 3) == 3)
seg->doMirror(m_aMirror);
--i;
lbidi = lastPass;
--lastPass;
continue;
}
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
*dbgout << json::item << json::object
// << "pindex" << i // for debugging
<< "id" << i+1
<< "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
<< "passdir" << ((m_dir & 1) ^ m_passes[i].reverseDir() ? "rtl" : "ltr")
<< "slots" << json::array;
seg->positionSlots(0, 0, 0, seg->currdir());
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close;
}
#endif
// test whether to reorder, prepare for positioning
bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
&& !m_passes[i].runGraphite(m, fsm, reverse))
return false;
// only subsitution passes can change segment length, cached subsegments are short for their text
if (m.status() != vm::Machine::finished
|| (seg->slotCount() && seg->slotCount() > maxSize))
return false;
}
return true;
}

529
thirdparty/graphite/src/Slot.cpp vendored Normal file
View File

@ -0,0 +1,529 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/Segment.h"
#include "inc/Slot.h"
#include "inc/Silf.h"
#include "inc/CharInfo.h"
#include "inc/Rule.h"
#include "inc/Collider.h"
using namespace graphite2;
Slot::Slot(int16 *user_attrs) :
m_next(NULL), m_prev(NULL),
m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0),
m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL),
m_position(0, 0), m_shift(0, 0), m_advance(0, 0),
m_attach(0, 0), m_with(0, 0), m_just(0.),
m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0),
m_userAttr(user_attrs), m_justs(NULL)
{
}
// take care, this does not copy any of the GrSlot pointer fields
void Slot::set(const Slot & orig, int charOffset, size_t sizeAttr, size_t justLevels, size_t numChars)
{
// leave m_next and m_prev unchanged
m_glyphid = orig.m_glyphid;
m_realglyphid = orig.m_realglyphid;
m_original = orig.m_original + charOffset;
if (charOffset + int(orig.m_before) < 0)
m_before = 0;
else
m_before = orig.m_before + charOffset;
if (charOffset <= 0 && orig.m_after + charOffset >= numChars)
m_after = int(numChars) - 1;
else
m_after = orig.m_after + charOffset;
m_parent = NULL;
m_child = NULL;
m_sibling = NULL;
m_position = orig.m_position;
m_shift = orig.m_shift;
m_advance = orig.m_advance;
m_attach = orig.m_attach;
m_with = orig.m_with;
m_flags = orig.m_flags;
m_attLevel = orig.m_attLevel;
m_bidiCls = orig.m_bidiCls;
m_bidiLevel = orig.m_bidiLevel;
if (m_userAttr && orig.m_userAttr)
memcpy(m_userAttr, orig.m_userAttr, sizeAttr * sizeof(*m_userAttr));
if (m_justs && orig.m_justs)
memcpy(m_justs, orig.m_justs, SlotJustify::size_of(justLevels));
}
void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
{
m_before += numCharInfo;
m_after += numCharInfo;
m_position = m_position + relpos;
}
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth)
{
SlotCollision *coll = NULL;
if (depth > 100 || (attrLevel && m_attLevel > attrLevel)) return Position(0, 0);
float scale = font ? font->scale() : 1.0f;
Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y);
float tAdvance = m_advance.x + m_just;
if (isFinal && (coll = seg->collisionInfo(this)))
{
const Position &collshift = coll->offset();
if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl)
shift = shift + collshift;
}
const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph());
if (font)
{
scale = font->scale();
shift *= scale;
if (font->isHinted() && glyphFace)
tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(glyph());
else
tAdvance *= scale;
}
Position res;
m_position = base + shift;
if (!m_parent)
{
res = base + Position(tAdvance, m_advance.y * scale);
clusterMin = m_position.x;
}
else
{
float tAdv;
m_position += (m_attach - m_with) * scale;
tAdv = m_advance.x >= 0.5f ? m_position.x + tAdvance - shift.x : 0.f;
res = Position(tAdv, 0);
if ((m_advance.x >= 0.5f || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x;
}
if (glyphFace)
{
Rect ourBbox = glyphFace->theBBox() * scale + m_position;
bbox = bbox.widen(ourBbox);
}
if (m_child && m_child != this && m_child->attachedTo() == this)
{
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
}
if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
{
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
if (tRes.x > res.x) res = tRes;
}
if (!m_parent && clusterMin < base.x)
{
Position adj = Position(m_position.x - clusterMin, 0.);
res += adj;
m_position += adj;
if (m_child) m_child->floodShift(adj);
}
return res;
}
int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl)
{
Position base;
if (glyph() >= seg->getFace()->glyphs().numGlyphs())
return 0;
Rect bbox = seg->theGlyphBBoxTemporary(glyph());
float clusterMin = 0.;
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
switch (metrics(metric))
{
case kgmetLsb :
return int32(bbox.bl.x);
case kgmetRsb :
return int32(res.x - bbox.tr.x);
case kgmetBbTop :
return int32(bbox.tr.y);
case kgmetBbBottom :
return int32(bbox.bl.y);
case kgmetBbLeft :
return int32(bbox.bl.x);
case kgmetBbRight :
return int32(bbox.tr.x);
case kgmetBbWidth :
return int32(bbox.tr.x - bbox.bl.x);
case kgmetBbHeight :
return int32(bbox.tr.y - bbox.bl.y);
case kgmetAdvWidth :
return int32(res.x);
case kgmetAdvHeight :
return int32(res.y);
default :
return 0;
}
}
#define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
{
if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
{
int indx = ind - gr_slatJStretch;
return getJustify(seg, indx / 5, indx % 5);
}
switch (ind)
{
case gr_slatAdvX : return int(m_advance.x);
case gr_slatAdvY : return int(m_advance.y);
case gr_slatAttTo : return m_parent ? 1 : 0;
case gr_slatAttX : return int(m_attach.x);
case gr_slatAttY : return int(m_attach.y);
case gr_slatAttXOff :
case gr_slatAttYOff : return 0;
case gr_slatAttWithX : return int(m_with.x);
case gr_slatAttWithY : return int(m_with.y);
case gr_slatAttWithXOff:
case gr_slatAttWithYOff:return 0;
case gr_slatAttLevel : return m_attLevel;
case gr_slatBreak : return seg->charinfo(m_original)->breakWeight();
case gr_slatCompRef : return 0;
case gr_slatDir : return seg->dir() & 1;
case gr_slatInsert : return isInsertBefore();
case gr_slatPosX : return int(m_position.x); // but need to calculate it
case gr_slatPosY : return int(m_position.y);
case gr_slatShiftX : return int(m_shift.x);
case gr_slatShiftY : return int(m_shift.y);
case gr_slatMeasureSol: return -1; // err what's this?
case gr_slatMeasureEol: return -1;
case gr_slatJWidth: return int(m_just);
case gr_slatUserDefnV1: subindex = 0; GR_FALLTHROUGH;
// no break
case gr_slatUserDefn : return subindex < seg->numAttrs() ? m_userAttr[subindex] : 0;
case gr_slatSegSplit : return seg->charinfo(m_original)->flags() & 3;
case gr_slatBidiLevel: return m_bidiLevel;
case gr_slatColFlags : { SlotCollision *c = seg->collisionInfo(this); return c ? c->flags() : 0; }
case gr_slatColLimitblx:SLOTGETCOLATTR(limit().bl.x)
case gr_slatColLimitbly:SLOTGETCOLATTR(limit().bl.y)
case gr_slatColLimittrx:SLOTGETCOLATTR(limit().tr.x)
case gr_slatColLimittry:SLOTGETCOLATTR(limit().tr.y)
case gr_slatColShiftx : SLOTGETCOLATTR(offset().x)
case gr_slatColShifty : SLOTGETCOLATTR(offset().y)
case gr_slatColMargin : SLOTGETCOLATTR(margin())
case gr_slatColMarginWt:SLOTGETCOLATTR(marginWt())
case gr_slatColExclGlyph:SLOTGETCOLATTR(exclGlyph())
case gr_slatColExclOffx:SLOTGETCOLATTR(exclOffset().x)
case gr_slatColExclOffy:SLOTGETCOLATTR(exclOffset().y)
case gr_slatSeqClass : SLOTGETCOLATTR(seqClass())
case gr_slatSeqProxClass:SLOTGETCOLATTR(seqProxClass())
case gr_slatSeqOrder : SLOTGETCOLATTR(seqOrder())
case gr_slatSeqAboveXoff:SLOTGETCOLATTR(seqAboveXoff())
case gr_slatSeqAboveWt: SLOTGETCOLATTR(seqAboveWt())
case gr_slatSeqBelowXlim:SLOTGETCOLATTR(seqBelowXlim())
case gr_slatSeqBelowWt: SLOTGETCOLATTR(seqBelowWt())
case gr_slatSeqValignHt:SLOTGETCOLATTR(seqValignHt())
case gr_slatSeqValignWt:SLOTGETCOLATTR(seqValignWt())
default : return 0;
}
}
#define SLOTCOLSETATTR(x) { \
SlotCollision *c = seg->collisionInfo(this); \
if (c) { c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
break; }
#define SLOTCOLSETCOMPLEXATTR(t, y, x) { \
SlotCollision *c = seg->collisionInfo(this); \
if (c) { \
const t &s = c-> y; \
c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
break; }
void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
{
if (ind == gr_slatUserDefnV1)
{
ind = gr_slatUserDefn;
subindex = 0;
if (seg->numAttrs() == 0)
return;
}
else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
{
int indx = ind - gr_slatJStretch;
return setJustify(seg, indx / 5, indx % 5, value);
}
switch (ind)
{
case gr_slatAdvX : m_advance.x = value; break;
case gr_slatAdvY : m_advance.y = value; break;
case gr_slatAttTo :
{
const uint16 idx = uint16(value);
if (idx < map.size() && map[idx])
{
Slot *other = map[idx];
if (other == this || other == m_parent || other->isCopied()) break;
if (m_parent) { m_parent->removeChild(this); attachTo(NULL); }
Slot *pOther = other;
int count = 0;
bool foundOther = false;
while (pOther)
{
++count;
if (pOther == this) foundOther = true;
pOther = pOther->attachedTo();
}
for (pOther = m_child; pOther; pOther = pOther->m_child)
++count;
for (pOther = m_sibling; pOther; pOther = pOther->m_sibling)
++count;
if (count < 100 && !foundOther && other->child(this))
{
attachTo(other);
if ((map.dir() != 0) ^ (idx > subindex))
m_with = Position(advance(), 0);
else // normal match to previous root
m_attach = Position(other->advance(), 0);
}
}
break;
}
case gr_slatAttX : m_attach.x = value; break;
case gr_slatAttY : m_attach.y = value; break;
case gr_slatAttXOff :
case gr_slatAttYOff : break;
case gr_slatAttWithX : m_with.x = value; break;
case gr_slatAttWithY : m_with.y = value; break;
case gr_slatAttWithXOff :
case gr_slatAttWithYOff : break;
case gr_slatAttLevel :
m_attLevel = byte(value);
break;
case gr_slatBreak :
seg->charinfo(m_original)->breakWeight(value);
break;
case gr_slatCompRef : break; // not sure what to do here
case gr_slatDir : break;
case gr_slatInsert :
markInsertBefore(value? true : false);
break;
case gr_slatPosX : break; // can't set these here
case gr_slatPosY : break;
case gr_slatShiftX : m_shift.x = value; break;
case gr_slatShiftY : m_shift.y = value; break;
case gr_slatMeasureSol : break;
case gr_slatMeasureEol : break;
case gr_slatJWidth : just(value); break;
case gr_slatSegSplit : seg->charinfo(m_original)->addflags(value & 3); break;
case gr_slatUserDefn : m_userAttr[subindex] = value; break;
case gr_slatColFlags : {
SlotCollision *c = seg->collisionInfo(this);
if (c)
c->setFlags(value);
break; }
case gr_slatColLimitblx : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(value, s.bl.y), s.tr)))
case gr_slatColLimitbly : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(s.bl.x, value), s.tr)))
case gr_slatColLimittrx : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(value, s.tr.y))))
case gr_slatColLimittry : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(s.tr.x, value))))
case gr_slatColMargin : SLOTCOLSETATTR(setMargin(value))
case gr_slatColMarginWt : SLOTCOLSETATTR(setMarginWt(value))
case gr_slatColExclGlyph : SLOTCOLSETATTR(setExclGlyph(value))
case gr_slatColExclOffx : SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(value, s.y)))
case gr_slatColExclOffy : SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(s.x, value)))
case gr_slatSeqClass : SLOTCOLSETATTR(setSeqClass(value))
case gr_slatSeqProxClass : SLOTCOLSETATTR(setSeqProxClass(value))
case gr_slatSeqOrder : SLOTCOLSETATTR(setSeqOrder(value))
case gr_slatSeqAboveXoff : SLOTCOLSETATTR(setSeqAboveXoff(value))
case gr_slatSeqAboveWt : SLOTCOLSETATTR(setSeqAboveWt(value))
case gr_slatSeqBelowXlim : SLOTCOLSETATTR(setSeqBelowXlim(value))
case gr_slatSeqBelowWt : SLOTCOLSETATTR(setSeqBelowWt(value))
case gr_slatSeqValignHt : SLOTCOLSETATTR(setSeqValignHt(value))
case gr_slatSeqValignWt : SLOTCOLSETATTR(setSeqValignWt(value))
default :
break;
}
}
int Slot::getJustify(const Segment *seg, uint8 level, uint8 subindex) const
{
if (level && level >= seg->silf()->numJustLevels()) return 0;
if (m_justs)
return m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex];
if (level >= seg->silf()->numJustLevels()) return 0;
Justinfo *jAttrs = seg->silf()->justAttrs() + level;
switch (subindex) {
case 0 : return seg->glyphAttr(gid(), jAttrs->attrStretch());
case 1 : return seg->glyphAttr(gid(), jAttrs->attrShrink());
case 2 : return seg->glyphAttr(gid(), jAttrs->attrStep());
case 3 : return seg->glyphAttr(gid(), jAttrs->attrWeight());
case 4 : return 0; // not been set yet, so clearly 0
default: return 0;
}
}
void Slot::setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value)
{
if (level && level >= seg->silf()->numJustLevels()) return;
if (!m_justs)
{
SlotJustify *j = seg->newJustify();
if (!j) return;
j->LoadSlot(this, seg);
m_justs = j;
}
m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex] = value;
}
bool Slot::child(Slot *ap)
{
if (this == ap) return false;
else if (ap == m_child) return true;
else if (!m_child)
m_child = ap;
else
return m_child->sibling(ap);
return true;
}
bool Slot::sibling(Slot *ap)
{
if (this == ap) return false;
else if (ap == m_sibling) return true;
else if (!m_sibling || !ap)
m_sibling = ap;
else
return m_sibling->sibling(ap);
return true;
}
bool Slot::removeChild(Slot *ap)
{
if (this == ap || !m_child || !ap) return false;
else if (ap == m_child)
{
Slot *nSibling = m_child->nextSibling();
m_child->nextSibling(NULL);
m_child = nSibling;
return true;
}
for (Slot *p = m_child; p; p = p->m_sibling)
{
if (p->m_sibling && p->m_sibling == ap)
{
p->m_sibling = p->m_sibling->m_sibling;
ap->nextSibling(NULL);
return true;
}
}
return false;
}
void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
{
m_glyphid = glyphid;
m_bidiCls = -1;
if (!theGlyph)
{
theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid);
if (!theGlyph)
{
m_realglyphid = 0;
m_advance = Position(0.,0.);
return;
}
}
m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()];
if (m_realglyphid > seg->getFace()->glyphs().numGlyphs())
m_realglyphid = 0;
const GlyphFace *aGlyph = theGlyph;
if (m_realglyphid)
{
aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid);
if (!aGlyph) aGlyph = theGlyph;
}
m_advance = Position(aGlyph->theAdvance().x, 0.);
if (seg->silf()->aPassBits())
{
seg->mergePassBits(uint8(theGlyph->attrs()[seg->silf()->aPassBits()]));
if (seg->silf()->numPasses() > 16)
seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()+1] << 16);
}
}
void Slot::floodShift(Position adj, int depth)
{
if (depth > 100)
return;
m_position += adj;
if (m_child) m_child->floodShift(adj, depth + 1);
if (m_sibling) m_sibling->floodShift(adj, depth + 1);
}
void SlotJustify::LoadSlot(const Slot *s, const Segment *seg)
{
for (int i = seg->silf()->numJustLevels() - 1; i >= 0; --i)
{
Justinfo *justs = seg->silf()->justAttrs() + i;
int16 *v = values + i * NUMJUSTPARAMS;
v[0] = seg->glyphAttr(s->gid(), justs->attrStretch());
v[1] = seg->glyphAttr(s->gid(), justs->attrShrink());
v[2] = seg->glyphAttr(s->gid(), justs->attrStep());
v[3] = seg->glyphAttr(s->gid(), justs->attrWeight());
}
}
Slot * Slot::nextInCluster(const Slot *s) const
{
Slot *base;
if (s->firstChild())
return s->firstChild();
else if (s->nextSibling())
return s->nextSibling();
while ((base = s->attachedTo()))
{
// if (base->firstChild() == s && base->nextSibling())
if (base->nextSibling())
return base->nextSibling();
s = base;
}
return NULL;
}
bool Slot::isChildOf(const Slot *base) const
{
for (Slot *p = m_parent; p; p = p->m_parent)
if (p == base)
return true;
return false;
}

62
thirdparty/graphite/src/Sparse.cpp vendored Normal file
View File

@ -0,0 +1,62 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cassert>
#include "inc/Sparse.h"
#include "inc/bits.h"
using namespace graphite2;
const sparse::chunk sparse::empty_chunk = {0,0};
sparse::~sparse() throw()
{
if (m_array.map == &empty_chunk) return;
free(m_array.values);
}
sparse::mapped_type sparse::operator [] (const key_type k) const throw()
{
mapped_type g = key_type(k/SIZEOF_CHUNK - m_nchunks) >> (sizeof k*8 - 1);
const chunk & c = m_array.map[g*k/SIZEOF_CHUNK];
const mask_t m = c.mask >> (SIZEOF_CHUNK - 1 - (k%SIZEOF_CHUNK));
g *= m & 1;
return g*m_array.values[g*(c.offset + bit_set_count(m >> 1))];
}
size_t sparse::capacity() const throw()
{
size_t n = m_nchunks,
s = 0;
for (const chunk *ci=m_array.map; n; --n, ++ci)
s += bit_set_count(ci->mask);
return s;
}

2053
thirdparty/graphite/src/TtfUtil.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

45
thirdparty/graphite/src/UtfCodec.cpp vendored Normal file
View File

@ -0,0 +1,45 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "inc/UtfCodec.h"
//using namespace graphite2;
namespace graphite2 {
}
using namespace graphite2;
const int8 _utf_codec<8>::sz_lut[16] =
{
1,1,1,1,1,1,1,1, // 1 byte
0,0,0,0, // trailing byte
2,2, // 2 bytes
3, // 3 bytes
4 // 4 bytes
};
const byte _utf_codec<8>::mask_lut[5] = {0x7f, 0xff, 0x3f, 0x1f, 0x0f};

138
thirdparty/graphite/src/call_machine.cpp vendored Normal file
View File

@ -0,0 +1,138 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This call threaded interpreter implmentation for machine.h
// Author: Tim Eves
// Build either this interpreter or the direct_machine implementation.
// The call threaded interpreter is portable across compilers and
// architectures as well as being useful to debug (you can set breakpoints on
// opcodes) but is slower that the direct threaded interpreter by a factor of 2
#include <cassert>
#include <cstring>
#include <graphite2/Segment.h>
#include "inc/Machine.h"
#include "inc/Segment.h"
#include "inc/Slot.h"
#include "inc/Rule.h"
// Disable the unused parameter warning as th compiler is mistaken since dp
// is always updated (even if by 0) on every opcode.
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#define registers const byte * & dp, vm::Machine::stack_t * & sp, \
vm::Machine::stack_t * const sb, regbank & reg
// These are required by opcodes.h and should not be changed
#define STARTOP(name) bool name(registers) REGPARM(4);\
bool name(registers) {
#define ENDOP return (sp - sb)/Machine::STACK_MAX==0; \
}
#define EXIT(status) { push(status); return false; }
// This is required by opcode_table.h
#define do_(name) instr(name)
using namespace graphite2;
using namespace vm;
struct regbank {
slotref is;
slotref * map;
SlotMap & smap;
slotref * const map_base;
const instr * & ip;
uint8 direction;
int8 flags;
Machine::status_t & status;
};
typedef bool (* ip_t)(registers);
// Pull in the opcode definitions
// We pull these into a private namespace so these otherwise common names dont
// pollute the toplevel namespace.
namespace {
#define smap reg.smap
#define seg smap.segment
#define is reg.is
#define ip reg.ip
#define map reg.map
#define mapb reg.map_base
#define flags reg.flags
#define dir reg.direction
#define status reg.status
#include "inc/opcodes.h"
#undef smap
#undef seg
#undef is
#undef ip
#undef map
#undef mapb
#undef flags
#undef dir
}
Machine::stack_t Machine::run(const instr * program,
const byte * data,
slotref * & map)
{
assert(program != 0);
// Declare virtual machine registers
const instr * ip = program-1;
const byte * dp = data;
stack_t * sp = _stack + Machine::STACK_GUARD,
* const sb = sp;
regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0, _status};
// Run the program
while ((reinterpret_cast<ip_t>(*++ip))(dp, sp, sb, reg)) {}
const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
check_final_stack(sp);
map = reg.map;
*map = reg.is;
return ret;
}
// Pull in the opcode table
namespace {
#include "inc/opcode_table.h"
}
const opcode_t * Machine::getOpcodeTable() throw()
{
return opcode_table;
}

View File

@ -0,0 +1,140 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This direct threaded interpreter implmentation for machine.h
// Author: Tim Eves
// Build either this interpreter or the call_machine implementation.
// The direct threaded interpreter is relies upon a gcc feature called
// labels-as-values so is only portable to compilers that support the
// extension (gcc only as far as I know) however it should build on any
// architecture gcc supports.
// This is twice as fast as the call threaded model and is likely faster on
// inorder processors with short pipelines and little branch prediction such
// as the ARM and possibly Atom chips.
#include <cassert>
#include <cstring>
#include "inc/Machine.h"
#include "inc/Segment.h"
#include "inc/Slot.h"
#include "inc/Rule.h"
#define STARTOP(name) name: {
#define ENDOP }; goto *((sp - sb)/Machine::STACK_MAX ? &&end : *++ip);
#define EXIT(status) { push(status); goto end; }
#define do_(name) &&name
using namespace graphite2;
using namespace vm;
namespace {
// The GCC manual has this to say about labels as values:
// The &&foo expressions for the same label might have different values
// if the containing function is inlined or cloned. If a program relies
// on them being always the same, __attribute__((__noinline__,__noclone__))
// should be used to prevent inlining and cloning.
//
// is_return in Code.cpp relies on being able to do comparisons, so it needs
// them to be always the same.
//
// The GCC manual further adds:
// If &&foo is used in a static variable initializer, inlining and
// cloning is forbidden.
//
// In this file, &&foo *is* used in a static variable initializer, and it's not
// entirely clear whether this should prevent inlining of the function or not.
// In practice, though, clang 7 can end up inlining the function with ThinLTO,
// which breaks at least is_return. https://bugs.llvm.org/show_bug.cgi?id=39241
// So all in all, we need at least the __noinline__ attribute. __noclone__
// is not supported by clang.
__attribute__((__noinline__))
const void * direct_run(const bool get_table_mode,
const instr * program,
const byte * data,
Machine::stack_t * stack,
slotref * & __map,
uint8 _dir,
Machine::status_t & status,
SlotMap * __smap=0)
{
// We need to define and return to opcode table from within this function
// other inorder to take the addresses of the instruction bodies.
#include "inc/opcode_table.h"
if (get_table_mode)
return opcode_table;
// Declare virtual machine registers
const instr * ip = program;
const byte * dp = data;
Machine::stack_t * sp = stack + Machine::STACK_GUARD,
* const sb = sp;
SlotMap & smap = *__smap;
Segment & seg = smap.segment;
slotref is = *__map,
* map = __map,
* const mapb = smap.begin()+smap.context();
uint8 dir = _dir;
int8 flags = 0;
// start the program
goto **ip;
// Pull in the opcode definitions
#include "inc/opcodes.h"
end:
__map = map;
*__map = is;
return sp;
}
}
const opcode_t * Machine::getOpcodeTable() throw()
{
slotref * dummy;
Machine::status_t dumstat = Machine::finished;
return static_cast<const opcode_t *>(direct_run(true, 0, 0, 0, dummy, 0, dumstat));
}
Machine::stack_t Machine::run(const instr * program,
const byte * data,
slotref * & is)
{
assert(program != 0);
const stack_t *sp = static_cast<const stack_t *>(
direct_run(false, program, data, _stack, is, _map.dir(), _status, &_map));
const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
check_final_stack(sp);
return ret;
}

View File

@ -0,0 +1,65 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cassert>
#include "graphite2/Segment.h"
#include "inc/CharInfo.h"
extern "C"
{
unsigned int gr_cinfo_unicode_char(const gr_char_info* p/*not NULL*/)
{
assert(p);
return p->unicodeChar();
}
int gr_cinfo_break_weight(const gr_char_info* p/*not NULL*/)
{
assert(p);
return p->breakWeight();
}
int gr_cinfo_after(const gr_char_info *p/*not NULL*/)
{
assert(p);
return p->after();
}
int gr_cinfo_before(const gr_char_info *p/*not NULL*/)
{
assert(p);
return p->before();
}
size_t gr_cinfo_base(const gr_char_info *p/*not NULL*/)
{
assert(p);
return p->base();
}
} // extern "C"

267
thirdparty/graphite/src/gr_face.cpp vendored Normal file
View File

@ -0,0 +1,267 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "graphite2/Font.h"
#include "inc/Face.h"
#include "inc/FileFace.h"
#include "inc/GlyphCache.h"
#include "inc/CmapCache.h"
#include "inc/Silf.h"
#include "inc/json.h"
using namespace graphite2;
#if !defined GRAPHITE2_NTRACING
extern json *global_log;
#endif
namespace
{
bool load_face(Face & face, unsigned int options)
{
#ifdef GRAPHITE2_TELEMETRY
telemetry::category _misc_cat(face.tele.misc);
#endif
Face::Table silf(face, Tag::Silf, 0x00050000);
if (!silf)
return false;
if (!face.readGlyphs(options))
return false;
if (silf)
{
if (!face.readFeatures() || !face.readGraphite(silf))
{
#if !defined GRAPHITE2_NTRACING
if (global_log)
{
*global_log << json::object
<< "type" << "fontload"
<< "failure" << face.error()
<< "context" << face.error_context()
<< json::close;
}
#endif
return false;
}
else
return true;
}
else
return false;
}
inline
uint32 zeropad(const uint32 x)
{
if (x == 0x20202020) return 0;
if ((x & 0x00FFFFFF) == 0x00202020) return x & 0xFF000000;
if ((x & 0x0000FFFF) == 0x00002020) return x & 0xFFFF0000;
if ((x & 0x000000FF) == 0x00000020) return x & 0xFFFFFF00;
return x;
}
}
extern "C" {
gr_face* gr_make_face_with_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int faceOptions)
//the appFaceHandle must stay alive all the time when the gr_face is alive. When finished with the gr_face, call destroy_face
{
if (ops == 0) return 0;
Face *res = new Face(appFaceHandle, *ops);
if (res && load_face(*res, faceOptions))
return static_cast<gr_face *>(res);
delete res;
return 0;
}
gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tablefn, unsigned int faceOptions)
{
const gr_face_ops ops = {sizeof(gr_face_ops), tablefn, NULL};
return gr_make_face_with_ops(appFaceHandle, &ops, faceOptions);
}
gr_face* gr_make_face_with_seg_cache_and_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int , unsigned int faceOptions)
{
return gr_make_face_with_ops(appFaceHandle, ops, faceOptions);
}
gr_face* gr_make_face_with_seg_cache(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tablefn, unsigned int, unsigned int faceOptions)
{
const gr_face_ops ops = {sizeof(gr_face_ops), tablefn, NULL};
return gr_make_face_with_ops(appFaceHandle, &ops, faceOptions);
}
gr_uint32 gr_str_to_tag(const char *str)
{
uint32 res = 0;
switch(max(strlen(str),size_t(4)))
{
case 4: res |= str[3]; GR_FALLTHROUGH;
case 3: res |= str[2] << 8; GR_FALLTHROUGH;
case 2: res |= str[1] << 16; GR_FALLTHROUGH;
case 1: res |= str[0] << 24; GR_FALLTHROUGH;
default: break;
}
return res;
}
void gr_tag_to_str(gr_uint32 tag, char *str)
{
if (!str) return;
*str++ = char(tag >> 24);
*str++ = char(tag >> 16);
*str++ = char(tag >> 8);
*str++ = char(tag);
*str = '\0';
}
gr_feature_val* gr_face_featureval_for_lang(const gr_face* pFace, gr_uint32 langname/*0 means clone default*/) //clones the features. if none for language, clones the default
{
assert(pFace);
langname = zeropad(langname);
return static_cast<gr_feature_val *>(pFace->theSill().cloneFeatures(langname));
}
const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId) //When finished with the FeatureRef, call destroy_FeatureRef
{
assert(pFace);
featId = zeropad(featId);
const FeatureRef* pRef = pFace->featureById(featId);
return static_cast<const gr_feature_ref*>(pRef);
}
unsigned short gr_face_n_fref(const gr_face* pFace)
{
assert(pFace);
int res = 0;
for (int i = 0; i < pFace->numFeatures(); ++i)
if (!(pFace->feature(i)->getFlags() & FeatureRef::HIDDEN))
++res;
return res;
}
const gr_feature_ref* gr_face_fref(const gr_face* pFace, gr_uint16 i) //When finished with the FeatureRef, call destroy_FeatureRef
{
assert(pFace);
int count = 0;
for (int j = 0; j < pFace->numFeatures(); ++j)
{
const FeatureRef* pRef = pFace->feature(j);
if (!(pRef->getFlags() & FeatureRef::HIDDEN))
if (count++ == i)
return static_cast<const gr_feature_ref*>(pRef);
}
return 0;
}
unsigned short gr_face_n_languages(const gr_face* pFace)
{
assert(pFace);
return pFace->theSill().numLanguages();
}
gr_uint32 gr_face_lang_by_index(const gr_face* pFace, gr_uint16 i)
{
assert(pFace);
return pFace->theSill().getLangName(i);
}
void gr_face_destroy(gr_face *face)
{
delete static_cast<Face*>(face);
}
gr_uint16 gr_face_name_lang_for_locale(gr_face *face, const char * locale)
{
if (face)
{
return face->languageForLocale(locale);
}
return 0;
}
unsigned short gr_face_n_glyphs(const gr_face* pFace)
{
return pFace->glyphs().numGlyphs();
}
const gr_faceinfo *gr_face_info(const gr_face *pFace, gr_uint32 script)
{
if (!pFace) return 0;
const Silf *silf = pFace->chooseSilf(script);
if (silf) return silf->silfInfo();
return 0;
}
int gr_face_is_char_supported(const gr_face* pFace, gr_uint32 usv, gr_uint32 script)
{
const Cmap & cmap = pFace->cmap();
gr_uint16 gid = cmap[usv];
if (!gid)
{
const Silf * silf = pFace->chooseSilf(script);
gid = silf->findPseudo(usv);
}
return (gid != 0);
}
#ifndef GRAPHITE2_NFILEFACE
gr_face* gr_make_file_face(const char *filename, unsigned int faceOptions)
{
FileFace* pFileFace = new FileFace(filename);
if (*pFileFace)
{
gr_face* pRes = gr_make_face_with_ops(pFileFace, &FileFace::ops, faceOptions);
if (pRes)
{
pRes->takeFileFace(pFileFace); //takes ownership
return pRes;
}
}
//error when loading
delete pFileFace;
return NULL;
}
gr_face* gr_make_file_face_with_seg_cache(const char* filename, unsigned int, unsigned int faceOptions) //returns NULL on failure. //TBD better error handling
//when finished with, call destroy_face
{
return gr_make_file_face(filename, faceOptions);
}
#endif //!GRAPHITE2_NFILEFACE
} // extern "C"

138
thirdparty/graphite/src/gr_features.cpp vendored Normal file
View File

@ -0,0 +1,138 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "graphite2/Font.h"
#include "inc/Face.h"
#include "inc/FeatureMap.h"
#include "inc/FeatureVal.h"
#include "inc/NameTable.h"
using namespace graphite2;
extern "C" {
gr_uint16 gr_fref_feature_value(const gr_feature_ref* pfeatureref, const gr_feature_val* feats) //returns 0 if either pointer is NULL
{
if (!pfeatureref || !feats) return 0;
return pfeatureref->getFeatureVal(*feats);
}
int gr_fref_set_feature_value(const gr_feature_ref* pfeatureref, gr_uint16 val, gr_feature_val* pDest)
{
if (!pfeatureref || !pDest) return 0;
return pfeatureref->applyValToFeature(val, *pDest);
}
gr_uint32 gr_fref_id(const gr_feature_ref* pfeatureref) //returns 0 if pointer is NULL
{
if (!pfeatureref)
return 0;
return pfeatureref->getId();
}
gr_uint16 gr_fref_n_values(const gr_feature_ref* pfeatureref)
{
if(!pfeatureref)
return 0;
return pfeatureref->getNumSettings();
}
gr_int16 gr_fref_value(const gr_feature_ref* pfeatureref, gr_uint16 settingno)
{
if(!pfeatureref || (settingno >= pfeatureref->getNumSettings()))
{
return 0;
}
return pfeatureref->getSettingValue(settingno);
}
void* gr_fref_label(const gr_feature_ref* pfeatureref, gr_uint16 *langId, gr_encform utf, gr_uint32 *length)
{
if(!pfeatureref)
{
langId = 0;
length = 0;
return NULL;
}
uint16 label = pfeatureref->getNameId();
NameTable * names = pfeatureref->getFace().nameTable();
if (!names)
{
langId = 0;
length = 0;
return NULL;
}
return names->getName(*langId, label, utf, *length);
}
void* gr_fref_value_label(const gr_feature_ref*pfeatureref, gr_uint16 setting,
gr_uint16 *langId, gr_encform utf, gr_uint32 *length)
{
if(!pfeatureref || (setting >= pfeatureref->getNumSettings()))
{
langId = 0;
length = 0;
return NULL;
}
uint16 label = pfeatureref->getSettingName(setting);
NameTable * names = pfeatureref->getFace().nameTable();
if (!names)
{
langId = 0;
length = 0;
return NULL;
}
return names->getName(*langId, label, utf, *length);
}
void gr_label_destroy(void * label)
{
free(label);
}
gr_feature_val* gr_featureval_clone(const gr_feature_val* pfeatures/*may be NULL*/)
{ //When finished with the Features, call features_destroy
return static_cast<gr_feature_val*>(pfeatures ? new Features(*pfeatures) : new Features);
}
void gr_featureval_destroy(gr_feature_val *p)
{
delete static_cast<Features*>(p);
}
} // extern "C"

74
thirdparty/graphite/src/gr_font.cpp vendored Normal file
View File

@ -0,0 +1,74 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "graphite2/Font.h"
#include "inc/Font.h"
using namespace graphite2;
extern "C" {
void gr_engine_version(int *nMajor, int *nMinor, int *nBugFix)
{
if (nMajor) *nMajor = GR2_VERSION_MAJOR;
if (nMinor) *nMinor = GR2_VERSION_MINOR;
if (nBugFix) *nBugFix = GR2_VERSION_BUGFIX;
}
gr_font* gr_make_font(float ppm/*pixels per em*/, const gr_face *face)
{
return gr_make_font_with_advance_fn(ppm, 0, 0, face);
}
gr_font* gr_make_font_with_ops(float ppm/*pixels per em*/, const void* appFontHandle/*non-NULL*/, const gr_font_ops * font_ops, const gr_face * face/*needed for scaling*/)
{ //the appFontHandle must stay alive all the time when the gr_font is alive. When finished with the gr_font, call destroy_gr_font
if (face == 0 || ppm <= 0) return 0;
Font * const res = new Font(ppm, *face, appFontHandle, font_ops);
if (*res)
return static_cast<gr_font*>(res);
else
{
delete res;
return 0;
}
}
gr_font* gr_make_font_with_advance_fn(float ppm/*pixels per em*/, const void* appFontHandle/*non-NULL*/, gr_advance_fn getAdvance, const gr_face * face/*needed for scaling*/)
{
const gr_font_ops ops = {sizeof(gr_font_ops), getAdvance, NULL};
return gr_make_font_with_ops(ppm, appFontHandle, &ops, face);
}
void gr_font_destroy(gr_font *font)
{
delete static_cast<Font*>(font);
}
} // extern "C"

267
thirdparty/graphite/src/gr_logging.cpp vendored Normal file
View File

@ -0,0 +1,267 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cstdio>
#include "graphite2/Log.h"
#include "inc/debug.h"
#include "inc/CharInfo.h"
#include "inc/Slot.h"
#include "inc/Segment.h"
#include "inc/json.h"
#include "inc/Collider.h"
#if defined _WIN32
#include "windows.h"
#endif
using namespace graphite2;
#if !defined GRAPHITE2_NTRACING
json *global_log = 0;
#endif
extern "C" {
bool gr_start_logging(GR_MAYBE_UNUSED gr_face * face, const char *log_path)
{
if (!log_path) return false;
#if !defined GRAPHITE2_NTRACING
gr_stop_logging(face);
#if defined _WIN32
int n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, 0, 0);
if (n == 0 || n > MAX_PATH - 12) return false;
LPWSTR wlog_path = gralloc<WCHAR>(n);
if (!wlog_path) return false;
FILE *log = 0;
if (wlog_path && MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, wlog_path, n))
log = _wfopen(wlog_path, L"wt");
free(wlog_path);
#else // _WIN32
FILE *log = fopen(log_path, "wt");
#endif // _WIN32
if (!log) return false;
if (face)
{
face->setLogger(log);
if (!face->logger()) return false;
*face->logger() << json::array;
#ifdef GRAPHITE2_TELEMETRY
*face->logger() << face->tele;
#endif
}
else
{
global_log = new json(log);
*global_log << json::array;
}
return true;
#else // GRAPHITE2_NTRACING
return false;
#endif // GRAPHITE2_NTRACING
}
bool graphite_start_logging(FILE * /* log */, GrLogMask /* mask */)
{
//#if !defined GRAPHITE2_NTRACING
// graphite_stop_logging();
//
// if (!log) return false;
//
// dbgout = new json(log);
// if (!dbgout) return false;
//
// *dbgout << json::array;
// return true;
//#else
return false;
//#endif
}
void gr_stop_logging(GR_MAYBE_UNUSED gr_face * face)
{
#if !defined GRAPHITE2_NTRACING
if (face && face->logger())
{
FILE * log = face->logger()->stream();
face->setLogger(0);
fclose(log);
}
else if (!face && global_log)
{
FILE * log = global_log->stream();
delete global_log;
global_log = 0;
fclose(log);
}
#endif
}
void graphite_stop_logging()
{
// if (dbgout) delete dbgout;
// dbgout = 0;
}
} // extern "C"
#ifdef GRAPHITE2_TELEMETRY
size_t * graphite2::telemetry::_category = 0UL;
#endif
#if !defined GRAPHITE2_NTRACING
#ifdef GRAPHITE2_TELEMETRY
json & graphite2::operator << (json & j, const telemetry & t) throw()
{
j << json::object
<< "type" << "telemetry"
<< "silf" << t.silf
<< "states" << t.states
<< "starts" << t.starts
<< "transitions" << t.transitions
<< "glyphs" << t.glyph
<< "code" << t.code
<< "misc" << t.misc
<< "total" << (t.silf + t.states + t.starts + t.transitions + t.glyph + t.code + t.misc)
<< json::close;
return j;
}
#else
json & graphite2::operator << (json & j, const telemetry &) throw()
{
return j;
}
#endif
json & graphite2::operator << (json & j, const CharInfo & ci) throw()
{
return j << json::object
<< "offset" << ci.base()
<< "unicode" << ci.unicodeChar()
<< "break" << ci.breakWeight()
<< "flags" << ci.flags()
<< "slot" << json::flat << json::object
<< "before" << ci.before()
<< "after" << ci.after()
<< json::close
<< json::close;
}
json & graphite2::operator << (json & j, const dslot & ds) throw()
{
assert(ds.first);
assert(ds.second);
const Segment & seg = *ds.first;
const Slot & s = *ds.second;
const SlotCollision *cslot = seg.collisionInfo(ds.second);
j << json::object
<< "id" << objectid(ds)
<< "gid" << s.gid()
<< "charinfo" << json::flat << json::object
<< "original" << s.original()
<< "before" << s.before()
<< "after" << s.after()
<< json::close
<< "origin" << s.origin()
<< "shift" << Position(float(s.getAttr(0, gr_slatShiftX, 0)),
float(s.getAttr(0, gr_slatShiftY, 0)))
<< "advance" << s.advancePos()
<< "insert" << s.isInsertBefore()
<< "break" << s.getAttr(&seg, gr_slatBreak, 0);
if (s.just() > 0)
j << "justification" << s.just();
if (s.getBidiLevel() > 0)
j << "bidi" << s.getBidiLevel();
if (!s.isBase())
j << "parent" << json::flat << json::object
<< "id" << objectid(dslot(&seg, s.attachedTo()))
<< "level" << s.getAttr(0, gr_slatAttLevel, 0)
<< "offset" << s.attachOffset()
<< json::close;
j << "user" << json::flat << json::array;
for (int n = 0; n!= seg.numAttrs(); ++n)
j << s.userAttrs()[n];
j << json::close;
if (s.firstChild())
{
j << "children" << json::flat << json::array;
for (const Slot *c = s.firstChild(); c; c = c->nextSibling())
j << objectid(dslot(&seg, c));
j << json::close;
}
if (cslot)
{
// Note: the reason for using Positions to lump together related attributes is to make the
// JSON output slightly more compact.
j << "collision" << json::flat << json::object
// << "shift" << cslot->shift() -- not used pass level, only within the collision routine itself
<< "offset" << cslot->offset()
<< "limit" << cslot->limit()
<< "flags" << cslot->flags()
<< "margin" << Position(cslot->margin(), cslot->marginWt())
<< "exclude" << cslot->exclGlyph()
<< "excludeoffset" << cslot->exclOffset();
if (cslot->seqOrder() != 0)
{
j << "seqclass" << Position(cslot->seqClass(), cslot->seqProxClass())
<< "seqorder" << cslot->seqOrder()
<< "seqabove" << Position(cslot->seqAboveXoff(), cslot->seqAboveWt())
<< "seqbelow" << Position(cslot->seqBelowXlim(), cslot->seqBelowWt())
<< "seqvalign" << Position(cslot->seqValignHt(), cslot->seqValignWt());
}
j << json::close;
}
return j << json::close;
}
graphite2::objectid::objectid(const dslot & ds) throw()
{
const Slot * const p = ds.second;
uint32 s = uint32(reinterpret_cast<size_t>(p));
sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), uint16(p ? p->userAttrs()[ds.first->silf()->numUser()] : 0), uint16(s));
name[sizeof name-1] = 0;
}
graphite2::objectid::objectid(const Segment * const p) throw()
{
uint32 s = uint32(reinterpret_cast<size_t>(p));
sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), 0, uint16(s));
name[sizeof name-1] = 0;
}
#endif

175
thirdparty/graphite/src/gr_segment.cpp vendored Normal file
View File

@ -0,0 +1,175 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "graphite2/Segment.h"
#include "inc/UtfCodec.h"
#include "inc/Segment.h"
using namespace graphite2;
namespace
{
gr_segment* makeAndInitialize(const Font *font, const Face *face, uint32 script, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars, int dir)
{
if (script == 0x20202020) script = 0;
else if ((script & 0x00FFFFFF) == 0x00202020) script = script & 0xFF000000;
else if ((script & 0x0000FFFF) == 0x00002020) script = script & 0xFFFF0000;
else if ((script & 0x000000FF) == 0x00000020) script = script & 0xFFFFFF00;
// if (!font) return NULL;
Segment* pRes=new Segment(nChars, face, script, dir);
if (!pRes->read_text(face, pFeats, enc, pStart, nChars) || !pRes->runGraphite())
{
delete pRes;
return NULL;
}
pRes->finalise(font, true);
return static_cast<gr_segment*>(pRes);
}
template <typename utf_iter>
inline size_t count_unicode_chars(utf_iter first, const utf_iter last, const void **error)
{
size_t n_chars = 0;
uint32 usv = 0;
if (last)
{
if (!first.validate(last))
{
if (error) *error = last - 1;
return 0;
}
for (;first != last; ++first, ++n_chars)
if ((usv = *first) == 0 || first.error()) break;
}
else
{
while ((usv = *first) != 0 && !first.error())
{
++first;
++n_chars;
}
}
if (error) *error = first.error() ? first : 0;
return n_chars;
}
}
extern "C" {
size_t gr_count_unicode_characters(gr_encform enc, const void* buffer_begin, const void* buffer_end/*don't go on or past end, If NULL then ignored*/, const void** pError) //Also stops on nul. Any nul is not in the count
{
assert(buffer_begin);
switch (enc)
{
case gr_utf8: return count_unicode_chars<utf8::const_iterator>(buffer_begin, buffer_end, pError); break;
case gr_utf16: return count_unicode_chars<utf16::const_iterator>(buffer_begin, buffer_end, pError); break;
case gr_utf32: return count_unicode_chars<utf32::const_iterator>(buffer_begin, buffer_end, pError); break;
default: return 0;
}
}
gr_segment* gr_make_seg(const gr_font *font, const gr_face *face, gr_uint32 script, const gr_feature_val* pFeats, gr_encform enc, const void* pStart, size_t nChars, int dir)
{
if (!face) return nullptr;
const gr_feature_val * tmp_feats = 0;
if (pFeats == 0)
pFeats = tmp_feats = static_cast<const gr_feature_val*>(face->theSill().cloneFeatures(0));
gr_segment * seg = makeAndInitialize(font, face, script, pFeats, enc, pStart, nChars, dir);
delete static_cast<const FeatureVal*>(tmp_feats);
return seg;
}
void gr_seg_destroy(gr_segment* p)
{
delete static_cast<Segment*>(p);
}
float gr_seg_advance_X(const gr_segment* pSeg/*not NULL*/)
{
assert(pSeg);
return pSeg->advance().x;
}
float gr_seg_advance_Y(const gr_segment* pSeg/*not NULL*/)
{
assert(pSeg);
return pSeg->advance().y;
}
unsigned int gr_seg_n_cinfo(const gr_segment* pSeg/*not NULL*/)
{
assert(pSeg);
return static_cast<unsigned int>(pSeg->charInfoCount());
}
const gr_char_info* gr_seg_cinfo(const gr_segment* pSeg/*not NULL*/, unsigned int index/*must be <number_of_CharInfo*/)
{
assert(pSeg);
return static_cast<const gr_char_info*>(pSeg->charinfo(index));
}
unsigned int gr_seg_n_slots(const gr_segment* pSeg/*not NULL*/)
{
assert(pSeg);
return static_cast<unsigned int>(pSeg->slotCount());
}
const gr_slot* gr_seg_first_slot(gr_segment* pSeg/*not NULL*/)
{
assert(pSeg);
return static_cast<const gr_slot*>(pSeg->first());
}
const gr_slot* gr_seg_last_slot(gr_segment* pSeg/*not NULL*/)
{
assert(pSeg);
return static_cast<const gr_slot*>(pSeg->last());
}
float gr_seg_justify(gr_segment* pSeg/*not NULL*/, const gr_slot* pSlot/*not NULL*/, const gr_font *pFont, double width, enum gr_justFlags flags, const gr_slot *pFirst, const gr_slot *pLast)
{
assert(pSeg);
assert(pSlot);
return pSeg->justify(const_cast<gr_slot *>(pSlot), pFont, float(width), justFlags(flags), const_cast<gr_slot *>(pFirst), const_cast<gr_slot *>(pLast));
}
} // extern "C"

173
thirdparty/graphite/src/gr_slot.cpp vendored Normal file
View File

@ -0,0 +1,173 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include "graphite2/Segment.h"
#include "inc/Segment.h"
#include "inc/Slot.h"
#include "inc/Font.h"
extern "C" {
const gr_slot* gr_slot_next_in_segment(const gr_slot* p/*not NULL*/)
{
assert(p);
return static_cast<const gr_slot*>(p->next());
}
const gr_slot* gr_slot_prev_in_segment(const gr_slot* p/*not NULL*/)
{
assert(p);
return static_cast<const gr_slot*>(p->prev());
}
const gr_slot* gr_slot_attached_to(const gr_slot* p/*not NULL*/) //returns NULL iff base. If called repeatedly on result, will get to a base
{
assert(p);
return static_cast<const gr_slot*>(p->attachedTo());
}
const gr_slot* gr_slot_first_attachment(const gr_slot* p/*not NULL*/) //returns NULL iff no attachments.
{ //if slot_first_attachment(p) is not NULL, then slot_attached_to(slot_first_attachment(p))==p.
assert(p);
return static_cast<const gr_slot*>(p->firstChild());
}
const gr_slot* gr_slot_next_sibling_attachment(const gr_slot* p/*not NULL*/) //returns NULL iff no more attachments.
{ //if slot_next_sibling_attachment(p) is not NULL, then slot_attached_to(slot_next_sibling_attachment(p))==slot_attached_to(p).
assert(p);
return static_cast<const gr_slot*>(p->nextSibling());
}
unsigned short gr_slot_gid(const gr_slot* p/*not NULL*/)
{
assert(p);
return p->glyph();
}
float gr_slot_origin_X(const gr_slot* p/*not NULL*/)
{
assert(p);
return p->origin().x;
}
float gr_slot_origin_Y(const gr_slot* p/*not NULL*/)
{
assert(p);
return p->origin().y;
}
float gr_slot_advance_X(const gr_slot* p/*not NULL*/, const gr_face *face, const gr_font *font)
{
assert(p);
float scale = 1.0;
float res = p->advance();
if (font)
{
scale = font->scale();
int gid = p->glyph();
if (face && font->isHinted() && gid < face->glyphs().numGlyphs())
res = (res - face->glyphs().glyph(gid)->theAdvance().x) * scale + font->advance(gid);
else
res = res * scale;
}
return res;
}
float gr_slot_advance_Y(const gr_slot *p/*not NULL*/, GR_MAYBE_UNUSED const gr_face *face, const gr_font *font)
{
assert(p);
float res = p->advancePos().y;
if (font)
return res * font->scale();
else
return res;
}
int gr_slot_before(const gr_slot* p/*not NULL*/)
{
assert(p);
return p->before();
}
int gr_slot_after(const gr_slot* p/*not NULL*/)
{
assert(p);
return p->after();
}
unsigned int gr_slot_index(const gr_slot *p/*not NULL*/)
{
assert(p);
return p->index();
}
int gr_slot_attr(const gr_slot* p/*not NULL*/, const gr_segment* pSeg/*not NULL*/, gr_attrCode index, gr_uint8 subindex)
{
assert(p);
return p->getAttr(pSeg, index, subindex);
}
int gr_slot_can_insert_before(const gr_slot* p/*not NULL*/)
{
assert(p);
return (p->isInsertBefore())? 1 : 0;
}
int gr_slot_original(const gr_slot* p/*not NULL*/)
{
assert(p);
return p->original();
}
void gr_slot_linebreak_before(gr_slot* p/*not NULL*/)
{
assert(p);
gr_slot *prev = (gr_slot *)p->prev();
prev->sibling(NULL);
prev->next(NULL);
p->prev(NULL);
}
#if 0 //what should this be
size_t id(const gr_slot* p/*not NULL*/)
{
return (size_t)p->id();
}
#endif
} // extern "C"

66
thirdparty/graphite/src/inc/CharInfo.h vendored Normal file
View File

@ -0,0 +1,66 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Main.h"
namespace graphite2 {
class CharInfo
{
public:
CharInfo() : m_char(0), m_before(-1), m_after(-1), m_base(0), m_featureid(0), m_break(0), m_flags(0) {}
void init(int cid) { m_char = cid; }
unsigned int unicodeChar() const { return m_char; }
void feats(int offset) { m_featureid = offset; }
int fid() const { return m_featureid; }
int breakWeight() const { return m_break; }
void breakWeight(int val) { m_break = val; }
int after() const { return m_after; }
void after(int val) { m_after = val; }
int before() const { return m_before; }
void before(int val) { m_before = val; }
size_t base() const { return m_base; }
void base(size_t offset) { m_base = offset; }
void addflags(uint8 val) { m_flags |= val; }
uint8 flags() const { return m_flags; }
CLASS_NEW_DELETE
private:
int m_char; // Unicode character from character stream
int m_before; // slot index before us, comes before
int m_after; // slot index after us, comes after
size_t m_base; // offset into input string corresponding to this charinfo
uint8 m_featureid; // index into features list in the segment
int8 m_break; // breakweight coming from lb table
uint8 m_flags; // 0,1 segment split.
};
} // namespace graphite2
struct gr_char_info : public graphite2::CharInfo {};

82
thirdparty/graphite/src/inc/CmapCache.h vendored Normal file
View File

@ -0,0 +1,82 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Main.h"
#include "inc/Face.h"
namespace graphite2 {
class Face;
class Cmap
{
public:
virtual ~Cmap() throw() {}
virtual uint16 operator [] (const uint32) const throw() { return 0; }
virtual operator bool () const throw() { return false; }
CLASS_NEW_DELETE;
};
class DirectCmap : public Cmap
{
DirectCmap(const DirectCmap &);
DirectCmap & operator = (const DirectCmap &);
public:
DirectCmap(const Face &);
virtual uint16 operator [] (const uint32 usv) const throw();
virtual operator bool () const throw();
CLASS_NEW_DELETE;
private:
const Face::Table _cmap;
const void * _smp,
* _bmp;
};
class CachedCmap : public Cmap
{
CachedCmap(const CachedCmap &);
CachedCmap & operator = (const CachedCmap &);
public:
CachedCmap(const Face &);
virtual ~CachedCmap() throw();
virtual uint16 operator [] (const uint32 usv) const throw();
virtual operator bool () const throw();
CLASS_NEW_DELETE;
private:
bool m_isBmpOnly;
uint16 ** m_blocks;
};
} // namespace graphite2

171
thirdparty/graphite/src/inc/Code.h vendored Normal file
View File

@ -0,0 +1,171 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This class represents loaded graphite stack machine code. It performs
// basic sanity checks, on the incoming code to prevent more obvious problems
// from crashing graphite.
// Author: Tim Eves
#pragma once
#include <cassert>
#include <graphite2/Types.h>
#include "inc/Main.h"
#include "inc/Machine.h"
namespace graphite2 {
class Silf;
class Face;
enum passtype {
PASS_TYPE_UNKNOWN = 0,
PASS_TYPE_LINEBREAK,
PASS_TYPE_SUBSTITUTE,
PASS_TYPE_POSITIONING,
PASS_TYPE_JUSTIFICATION
};
namespace vm {
class Machine::Code
{
public:
enum status_t
{
loaded,
alloc_failed,
invalid_opcode,
unimplemented_opcode_used,
out_of_range_data,
jump_past_end,
arguments_exhausted,
missing_return,
nested_context_item,
underfull_stack
};
private:
class decoder;
instr * _code;
byte * _data;
size_t _data_size,
_instr_count;
byte _max_ref;
mutable status_t _status;
bool _constraint,
_modify,
_delete;
mutable bool _own;
void release_buffers() throw ();
void failure(const status_t) throw();
public:
static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots);
Code() throw();
Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
enum passtype pt, byte * * const _out = 0);
Code(const Machine::Code &) throw();
~Code() throw();
Code & operator=(const Code &rhs) throw();
operator bool () const throw() { return _code && status() == loaded; }
status_t status() const throw() { return _status; }
bool constraint() const throw() { return _constraint; }
size_t dataSize() const throw() { return _data_size; }
size_t instructionCount() const throw() { return _instr_count; }
bool immutable() const throw() { return !(_delete || _modify); }
bool deletes() const throw() { return _delete; }
size_t maxRef() const throw() { return _max_ref; }
void externalProgramMoved(ptrdiff_t) throw();
int32 run(Machine &m, slotref * & map) const;
CLASS_NEW_DELETE;
};
inline
size_t Machine::Code::estimateCodeDataOut(size_t n_bc, int nRules, int nSlots)
{
// max is: all codes are instructions + 1 for each rule + max tempcopies
// allocate space for separate maximal code and data then merge them later
return (n_bc + nRules + nSlots) * sizeof(instr) + n_bc * sizeof(byte);
}
inline Machine::Code::Code() throw()
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
_status(loaded), _constraint(false), _modify(false), _delete(false),
_own(false)
{
}
inline Machine::Code::Code(const Machine::Code &obj) throw ()
: _code(obj._code),
_data(obj._data),
_data_size(obj._data_size),
_instr_count(obj._instr_count),
_max_ref(obj._max_ref),
_status(obj._status),
_constraint(obj._constraint),
_modify(obj._modify),
_delete(obj._delete),
_own(obj._own)
{
obj._own = false;
}
inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw() {
if (_instr_count > 0)
release_buffers();
_code = rhs._code;
_data = rhs._data;
_data_size = rhs._data_size;
_instr_count = rhs._instr_count;
_status = rhs._status;
_constraint = rhs._constraint;
_modify = rhs._modify;
_delete = rhs._delete;
_own = rhs._own;
rhs._own = false;
return *this;
}
inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
{
if (_code && !_own)
{
_code += dist / signed(sizeof(instr));
_data += dist;
}
}
} // namespace vm
} // namespace graphite2

245
thirdparty/graphite/src/inc/Collider.h vendored Normal file
View File

@ -0,0 +1,245 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/List.h"
#include "inc/Position.h"
#include "inc/Intervals.h"
#include "inc/debug.h"
namespace graphite2 {
class json;
class Slot;
class Segment;
#define SLOTCOLSETUINTPROP(x, y) uint16 x() const { return _ ##x; } void y (uint16 v) { _ ##x = v; }
#define SLOTCOLSETINTPROP(x, y) int16 x() const { return _ ##x; } void y (int16 v) { _ ##x = v; }
#define SLOTCOLSETPOSITIONPROP(x, y) const Position &x() const { return _ ##x; } void y (const Position &v) { _ ##x = v; }
// Slot attributes related to collision-fixing
class SlotCollision
{
public:
enum {
// COLL_TESTONLY = 0, // default - test other glyphs for collision with this one, but don't move this one
COLL_FIX = 1, // fix collisions involving this glyph
COLL_IGNORE = 2, // ignore this glyph altogether
COLL_START = 4, // start of range of possible collisions
COLL_END = 8, // end of range of possible collisions
COLL_KERN = 16, // collisions with this glyph are fixed by adding kerning space after it
COLL_ISCOL = 32, // this glyph has a collision
COLL_KNOWN = 64, // we've figured out what's happening with this glyph
COLL_ISSPACE = 128, // treat this glyph as a space with regard to kerning
COLL_TEMPLOCK = 256, // Lock glyphs that have been given priority positioning
////COLL_JUMPABLE = 128, // moving glyphs may jump this stationary glyph in any direction - DELETE
////COLL_OVERLAP = 256, // use maxoverlap to restrict - DELETE
};
// Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set
// Allows for easier inversion.
enum {
SEQ_ORDER_LEFTDOWN = 1,
SEQ_ORDER_RIGHTUP = 2,
SEQ_ORDER_NOABOVE = 4,
SEQ_ORDER_NOBELOW = 8,
SEQ_ORDER_NOLEFT = 16,
SEQ_ORDER_NORIGHT = 32
};
SlotCollision(Segment *seg, Slot *slot);
void initFromSlot(Segment *seg, Slot *slot);
const Rect &limit() const { return _limit; }
void setLimit(const Rect &r) { _limit = r; }
SLOTCOLSETPOSITIONPROP(shift, setShift)
SLOTCOLSETPOSITIONPROP(offset, setOffset)
SLOTCOLSETPOSITIONPROP(exclOffset, setExclOffset)
SLOTCOLSETUINTPROP(margin, setMargin)
SLOTCOLSETUINTPROP(marginWt, setMarginWt)
SLOTCOLSETUINTPROP(flags, setFlags)
SLOTCOLSETUINTPROP(exclGlyph, setExclGlyph)
SLOTCOLSETUINTPROP(seqClass, setSeqClass)
SLOTCOLSETUINTPROP(seqProxClass, setSeqProxClass)
SLOTCOLSETUINTPROP(seqOrder, setSeqOrder)
SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff)
SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt)
SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim)
SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt)
SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt)
SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)
float getKern(int dir) const;
bool ignore() const;
private:
Rect _limit;
Position _shift; // adjustment within the given pass
Position _offset; // total adjustment for collisions
Position _exclOffset;
uint16 _margin;
uint16 _marginWt;
uint16 _flags;
uint16 _exclGlyph;
uint16 _seqClass;
uint16 _seqProxClass;
uint16 _seqOrder;
int16 _seqAboveXoff;
uint16 _seqAboveWt;
int16 _seqBelowXlim;
uint16 _seqBelowWt;
uint16 _seqValignHt;
uint16 _seqValignWt;
}; // end of class SlotColllision
struct BBox;
struct SlantBox;
class ShiftCollider
{
public:
typedef std::pair<float, float> fpair;
typedef Vector<fpair> vfpairs;
typedef vfpairs::iterator ivfpairs;
ShiftCollider(json *dbgout);
~ShiftCollider() throw() { };
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
float margin, float marginMin, const Position &currShift,
const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout);
bool mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cinfo, const Position &currShift, bool isAfter,
bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json * const dbgout);
Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout);
void addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int mode);
void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode);
const Position &origin() const { return _origin; }
#if !defined GRAPHITE2_NTRACING
void outputJsonDbg(json * const dbgout, Segment *seg, int axis);
void outputJsonDbgStartSlot(json * const dbgout, Segment *seg);
void outputJsonDbgEndSlot(json * const dbgout, Position resultPos, int bestAxis, bool isCol);
void outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal);
void outputJsonDbgRawRanges(json * const dbgout, int axis);
void outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg);
#endif
CLASS_NEW_DELETE;
protected:
Zones _ranges[4]; // possible movements in 4 directions (horizontally, vertically, diagonally);
Slot * _target; // the glyph to fix
Rect _limit;
Position _currShift;
Position _currOffset;
Position _origin; // Base for all relative calculations
float _margin;
float _marginWt;
float _len[4];
uint16 _seqClass;
uint16 _seqProxClass;
uint16 _seqOrder;
//bool _scraping[4];
}; // end of class ShiftCollider
inline
ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
: _target(0),
_margin(0.0),
_marginWt(0.0),
_seqClass(0),
_seqProxClass(0),
_seqOrder(0)
{
#if !defined GRAPHITE2_NTRACING
for (int i = 0; i < 4; ++i)
_ranges[i].setdebug(dbgout);
#endif
}
class KernCollider
{
public:
KernCollider(json *dbg);
~KernCollider() throw() { };
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
const Position &currShift, const Position &offsetPrev, int dir,
float ymin, float ymax, json * const dbgout);
bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json * const dbgout);
Position resolve(Segment *seg, Slot *slot, int dir, json * const dbgout);
void shift(const Position &mv, int dir);
CLASS_NEW_DELETE;
private:
Slot * _target; // the glyph to fix
Rect _limit;
float _margin;
Position _offsetPrev; // kern from a previous pass
Position _currShift; // NOT USED??
float _miny; // y-coordinates offset by global slot position
float _maxy;
Vector<float> _edges; // edges of horizontal slices
float _sliceWidth; // width of each slice
float _mingap;
float _xbound; // max or min edge
bool _hit;
#if !defined GRAPHITE2_NTRACING
// Debugging
Segment * _seg;
Vector<float> _nearEdges; // closest potential collision in each slice
Vector<Slot*> _slotNear;
#endif
}; // end of class KernCollider
inline
float sqr(float x) {
return x * x;
}
inline
KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg)
: _target(0),
_margin(0.0f),
_miny(-1e38f),
_maxy(1e38f),
_sliceWidth(0.0f),
_mingap(0.0f),
_xbound(0.0),
_hit(false)
{
#if !defined GRAPHITE2_NTRACING
_seg = 0;
#endif
};
}; // end of namespace graphite2

View File

@ -0,0 +1,104 @@
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cassert>
#include <cstddef>
#include <cstring>
namespace
{
#if defined(_MSC_VER)
typedef unsigned __int8 u8;
typedef unsigned __int16 u16;
typedef unsigned __int32 u32;
typedef unsigned __int64 u64;
#else
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#endif
ptrdiff_t const MINMATCH = 4,
LASTLITERALS = 5,
MINCODA = LASTLITERALS+1,
MINSRCSIZE = 13;
template<int S>
inline
void unaligned_copy(void * d, void const * s) {
::memcpy(d, s, S);
}
inline
size_t align(size_t p) {
return (p + sizeof(unsigned long)-1) & ~(sizeof(unsigned long)-1);
}
inline
u8 * safe_copy(u8 * d, u8 const * s, size_t n) {
while (n--) *d++ = *s++;
return d;
}
inline
u8 * overrun_copy(u8 * d, u8 const * s, size_t n) {
size_t const WS = sizeof(unsigned long);
u8 const * e = s + n;
do
{
unaligned_copy<WS>(d, s);
d += WS;
s += WS;
}
while (s < e);
d-=(s-e);
return d;
}
inline
u8 * fast_copy(u8 * d, u8 const * s, size_t n) {
size_t const WS = sizeof(unsigned long);
size_t wn = n/WS;
while (wn--)
{
unaligned_copy<WS>(d, s);
d += WS;
s += WS;
}
n &= WS-1;
return safe_copy(d, s, n);
}
} // end of anonymous namespace

View File

@ -0,0 +1,54 @@
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstddef>
namespace lz4
{
// decompress an LZ4 block
// Parameters:
// @in - Input buffer containing an LZ4 block.
// @in_size - Size of the input LZ4 block in bytes.
// @out - Output buffer to hold decompressed results.
// @out_size - The size of the buffer pointed to by @out.
// Invariants:
// @in - This buffer must be at least 1 machine word in length,
// regardless of the actual LZ4 block size.
// @in_size - This must be at least 4 and must also be <= to the
// allocated buffer @in.
// @out - This must be bigger than the input buffer and at least
// 13 bytes.
// @out_size - Must always be big enough to hold the expected size.
// Return:
// -1 - Decompression failed.
// size - Actual number of bytes decompressed.
int decompress(void const *in, size_t in_size, void *out, size_t out_size);
} // end of namespace shrinker

111
thirdparty/graphite/src/inc/Endian.h vendored Normal file
View File

@ -0,0 +1,111 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
/*
Description:
A set of fast template based decoders for decoding values of any C integer
type up to long int size laid out with most significant byte first or least
significant byte first (aka big endian or little endian). These are CPU
byte order agnostic and will function the same regardless of the CPUs native
byte order.
Being template based means if the either le or be class is not used then
template code of unused functions will not be instantiated by the compiler
and thus shouldn't cause any overhead.
*/
#include <cstddef>
#pragma once
class be
{
template<int S>
inline static unsigned long int _peek(const unsigned char * p) {
return _peek<S/2>(p) << (S/2)*8 | _peek<S/2>(p+S/2);
}
public:
template<typename T>
inline static T peek(const void * p) {
return T(_peek<sizeof(T)>(static_cast<const unsigned char *>(p)));
}
template<typename T>
inline static T read(const unsigned char * &p) {
const T r = T(_peek<sizeof(T)>(p));
p += sizeof r;
return r;
}
template<typename T>
inline static T swap(const T x) {
return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
}
template<typename T>
inline static void skip(const unsigned char * &p, size_t n=1) {
p += sizeof(T)*n;
}
};
template<>
inline unsigned long int be::_peek<1>(const unsigned char * p) { return *p; }
class le
{
template<int S>
inline static unsigned long int _peek(const unsigned char * p) {
return _peek<S/2>(p) | _peek<S/2>(p+S/2) << (S/2)*8;
}
public:
template<typename T>
inline static T peek(const void * p) {
return T(_peek<sizeof(T)>(static_cast<const unsigned char *>(p)));
}
template<typename T>
inline static T read(const unsigned char * &p) {
const T r = T(_peek<sizeof(T)>(p));
p += sizeof r;
return r;
}
template<typename T>
inline static T swap(const T x) {
return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
}
template<typename T>
inline static void skip(const unsigned char * &p, size_t n=1) {
p += sizeof(T)*n;
}
};
template<>
inline unsigned long int le::_peek<1>(const unsigned char * p) { return *p; }

134
thirdparty/graphite/src/inc/Error.h vendored Normal file
View File

@ -0,0 +1,134 @@
/* GRAPHITE2 LICENSING
Copyright 2013, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
// numbers are explicitly assigned for future proofing
namespace graphite2
{
class Error
{
public:
Error() : _e(0) {};
operator bool() { return (_e != 0); }
int error() { return _e; }
void error(int e) { _e = e; }
bool test(bool pr, int err) { return (_e = int(pr) * err); }
private:
int _e;
};
enum errcontext {
EC_READGLYPHS = 1, // while reading glyphs
EC_READSILF = 2, // in Silf table
EC_ASILF = 3, // in Silf %d
EC_APASS = 4, // in Silf %d, pass %d
EC_PASSCCODE = 5, // in pass constraint code for Silf %d, pass %d
EC_ARULE = 6, // in Silf %d, pass %d, rule %d
EC_ASTARTS = 7, // in Silf %d, pass %d, start state %d
EC_ATRANS = 8, // in Silf %d, pass %d, fsm state %d
EC_ARULEMAP = 9 // in Silf %d, pass %d, state %d
};
enum errors {
E_OUTOFMEM = 1, // Out of memory
E_NOGLYPHS = 2, // There are no glyphs in the font
E_BADUPEM = 3, // The units per em for the font is bad (0)
E_BADCMAP = 4, // The font does not contain any useful cmaps
E_NOSILF = 5, // Missing Silf table
E_TOOOLD = 6, // Silf table version is too old
E_BADSIZE = 7, // context object has the wrong structural size
// Silf Subtable Errors take a Silf subtable number * 256 in the context
E_BADMAXGLYPH = 8, // Silf max glyph id is too high
E_BADNUMJUSTS = 9, // Number of Silf justification blocks is too high
E_BADENDJUSTS = 10, // Silf justification blocks take too much of the Silf table space
E_BADCRITFEATURES = 11, // Critical features section in a Silf table is too big
E_BADSCRIPTTAGS = 12, // Silf script tags area is too big
E_BADAPSEUDO = 13, // The pseudo glyph attribute number is too high
E_BADABREAK = 14, // The linebreak glyph attribute number is too high
E_BADABIDI = 15, // The bidi glyph attribute number is too high
E_BADAMIRROR = 16, // The mirrored glyph attribute number is too high
E_BADNUMPASSES = 17, // The number of passes is > 128
E_BADPASSESSTART = 18, // The Silf table is too small to hold any passes
E_BADPASSBOUND = 19, // The positioning pass number is too low or the substitution pass number is too high
E_BADPPASS = 20, // The positioning pass number is too high
E_BADSPASS = 21, // the substitution pass number is too high
E_BADJPASSBOUND = 22, // the justification pass must be higher than the positioning pass
E_BADJPASS = 23, // the justification pass is too high
E_BADALIG = 24, // the number of initial ligature component glyph attributes is too high
E_BADBPASS = 25, // the bidi pass number is specified and is either too high or too low
E_BADNUMPSEUDO = 26, // The number of pseudo glyphs is too high
E_BADCLASSSIZE = 27, // The size of the classes block is bad
E_TOOMANYLINEAR = 28, // The number of linear classes in the silf table is too high
E_CLASSESTOOBIG = 29, // There are too many classes for the space allocated in the Silf subtable
E_MISALIGNEDCLASSES = 30, // The class offsets in the class table don't line up with the number of classes
E_HIGHCLASSOFFSET = 31, // The class offsets point out of the class table
E_BADCLASSOFFSET = 32, // A class offset is less than one following it
E_BADCLASSLOOKUPINFO = 33, // The search header info for a non-linear class has wrong values in it
// Pass subtable errors. Context has pass number * 65536
E_BADPASSSTART = 34, // The start offset for a particular pass is bad
E_BADPASSEND = 35, // The end offset for a particular pass is bad
E_BADPASSLENGTH = 36, // The length of the pass is too small
E_BADNUMTRANS = 37, // The number of transition states in the fsm is bad
E_BADNUMSUCCESS = 38, // The number of success states in the fsm is bad
E_BADNUMSTATES = 39, // The number of states in the fsm is bad
E_NORANGES = 40, // There are no columns in the fsm
E_BADRULEMAPLEN = 41, // The size of the success state to rule mapping is bad
E_BADCTXTLENBOUNDS = 42, // The precontext maximum is greater than its minimum
E_BADCTXTLENS = 43, // The lists of rule lengths or pre context lengths is bad
E_BADPASSCCODEPTR = 44, // The pass constraint code position does not align with where the forward reference says it should be
E_BADRULECCODEPTR = 45, // The rule constraint code position does not align with where the forward reference says it should be
E_BADCCODELEN = 46, // Bad rule/pass constraint code length
E_BADACTIONCODEPTR = 47, // The action code position does not align with where the forward reference says it should be
E_MUTABLECCODE = 48, // Constraint code edits slots. It shouldn't.
E_BADSTATE = 49, // Bad state transition referencing an illegal state
E_BADRULEMAPPING = 50, // The structure of the rule mapping is bad
E_BADRANGE = 51, // Bad column range structure including a glyph in more than one column
E_BADRULENUM = 52, // A reference to a rule is out of range (too high)
E_BADACOLLISION = 53, // Bad Silf table collision attribute number (too high)
E_BADEMPTYPASS = 54, // Can't have empty passes (no rules) except for collision passes
E_BADSILFVERSION = 55, // The Silf table has a bad version (probably too high)
E_BADCOLLISIONPASS = 56, // Collision flags set on a non positioning pass
E_BADNUMCOLUMNS = 57, // Arbitrarily limit number of columns in fsm
// Code errors
E_CODEFAILURE = 60, // Base code error. The following subcodes must align with Machine::Code::status_t in Code.h
E_CODEALLOC = 61, // Out of memory
E_INVALIDOPCODE = 62, // Invalid op code
E_UNIMPOPCODE = 63, // Unimplemented op code encountered
E_OUTOFRANGECODE = 64, // Code argument out of range
E_BADJUMPCODE = 65, // Code jumps past end of op codes
E_CODEBADARGS = 66, // Code arguments exhausted
E_CODENORETURN = 67, // Missing return type op code at end of code
E_CODENESTEDCTXT = 68, // Nested context encountered in code
// Compression errors
E_BADSCHEME = 69,
E_SHRINKERFAILED = 70,
};
}

225
thirdparty/graphite/src/inc/Face.h vendored Normal file
View File

@ -0,0 +1,225 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstdio>
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/FeatureMap.h"
#include "inc/TtfUtil.h"
#include "inc/Silf.h"
#include "inc/Error.h"
namespace graphite2 {
class Cmap;
class FileFace;
class GlyphCache;
class NameTable;
class json;
class Font;
using TtfUtil::Tag;
// These are the actual tags, as distinct from the consecutive IDs in TtfUtil.h
class Face
{
// Prevent any kind of copying
Face(const Face&);
Face& operator=(const Face&);
public:
class Table;
static float default_glyph_advance(const void* face_ptr, gr_uint16 glyphid);
Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops);
virtual ~Face();
virtual bool runGraphite(Segment *seg, const Silf *silf) const;
public:
bool readGlyphs(uint32 faceOptions);
bool readGraphite(const Table & silf);
bool readFeatures();
void takeFileFace(FileFace* pFileFace/*takes ownership*/);
const SillMap & theSill() const;
const GlyphCache & glyphs() const;
Cmap & cmap() const;
NameTable * nameTable() const;
void setLogger(FILE *log_file);
json * logger() const throw();
const Silf * chooseSilf(uint32 script) const;
uint16 languageForLocale(const char * locale) const;
// Features
uint16 numFeatures() const;
const FeatureRef * featureById(uint32 id) const;
const FeatureRef * feature(uint16 index) const;
// Glyph related
int32 getGlyphMetric(uint16 gid, uint8 metric) const;
uint16 findPseudo(uint32 uid) const;
// Errors
unsigned int error() const { return m_error; }
bool error(Error e) { m_error = e.error(); return false; }
unsigned int error_context() const { return m_error; }
void error_context(unsigned int errcntxt) { m_errcntxt = errcntxt; }
CLASS_NEW_DELETE;
private:
SillMap m_Sill;
gr_face_ops m_ops;
const void * m_appFaceHandle; // non-NULL
FileFace * m_pFileFace; //owned
mutable GlyphCache * m_pGlyphFaceCache; // owned - never NULL
mutable Cmap * m_cmap; // cmap cache if available
mutable NameTable * m_pNames;
mutable json * m_logger;
unsigned int m_error;
unsigned int m_errcntxt;
protected:
Silf * m_silfs; // silf subtables.
uint16 m_numSilf; // num silf subtables in the silf table
private:
uint16 m_ascent,
m_descent;
#ifdef GRAPHITE2_TELEMETRY
public:
mutable telemetry tele;
#endif
};
inline
const SillMap & Face::theSill() const
{
return m_Sill;
}
inline
uint16 Face::numFeatures() const
{
return m_Sill.theFeatureMap().numFeats();
}
inline
const FeatureRef * Face::featureById(uint32 id) const
{
return m_Sill.theFeatureMap().findFeatureRef(id);
}
inline
const FeatureRef *Face::feature(uint16 index) const
{
return m_Sill.theFeatureMap().feature(index);
}
inline
const GlyphCache & Face::glyphs() const
{
return *m_pGlyphFaceCache;
}
inline
Cmap & Face::cmap() const
{
return *m_cmap;
};
inline
json * Face::logger() const throw()
{
return m_logger;
}
class Face::Table
{
const Face * _f;
mutable const byte * _p;
size_t _sz;
bool _compressed;
Error decompress();
void release();
public:
Table() throw();
Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
~Table() throw();
Table(const Table && rhs) throw();
operator const byte * () const throw();
size_t size() const throw();
Table & operator = (const Table && rhs) throw();
};
inline
Face::Table::Table() throw()
: _f(0), _p(0), _sz(0), _compressed(false)
{
}
inline
Face::Table::Table(const Table && rhs) throw()
: _f(rhs._f), _p(rhs._p), _sz(rhs._sz), _compressed(rhs._compressed)
{
rhs._p = 0;
}
inline
Face::Table::~Table() throw()
{
release();
}
inline
Face::Table::operator const byte * () const throw()
{
return _p;
}
inline
size_t Face::Table::size() const throw()
{
return _sz;
}
} // namespace graphite2
struct gr_face : public graphite2::Face {};

198
thirdparty/graphite/src/inc/FeatureMap.h vendored Normal file
View File

@ -0,0 +1,198 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Main.h"
#include "inc/FeatureVal.h"
namespace graphite2 {
// Forward declarations for implmentation types
class FeatureMap;
class Face;
class FeatureSetting
{
public:
FeatureSetting(int16 theValue, uint16 labelId) : m_label(labelId), m_value(theValue) {};
uint16 label() const { return m_label; }
int16 value() const { return m_value; }
CLASS_NEW_DELETE;
private:
FeatureSetting(const FeatureSetting & fs) : m_label(fs.m_label), m_value(fs.m_value) {};
uint16 m_label;
int16 m_value;
};
class FeatureRef
{
typedef uint32 chunk_t;
static const uint8 SIZEOF_CHUNK = sizeof(chunk_t)*8;
public:
enum flags_t : uint16 {
HIDDEN = 0x0800
};
FeatureRef() throw();
FeatureRef(const Face & face, unsigned short & bits_offset, uint32 max_val,
uint32 name, uint16 uiName, flags_t flags,
FeatureSetting *settings, uint16 num_set) throw();
~FeatureRef() throw();
bool applyValToFeature(uint32 val, Features& pDest) const; //defined in GrFaceImp.h
void maskFeature(Features & pDest) const {
if (m_index < pDest.size()) //defensive
pDest[m_index] |= m_mask;
}
uint32 getFeatureVal(const Features& feats) const; //defined in GrFaceImp.h
uint32 getId() const { return m_id; }
uint16 getNameId() const { return m_nameid; }
uint16 getNumSettings() const { return m_numSet; }
uint16 getSettingName(uint16 index) const { return m_nameValues[index].label(); }
int16 getSettingValue(uint16 index) const { return m_nameValues[index].value(); }
flags_t getFlags() const { return m_flags; }
uint32 maxVal() const { return m_max; }
const Face & getFace() const { assert(m_face); return *m_face;}
const FeatureMap* getFeatureMap() const;// { return m_pFace;}
CLASS_NEW_DELETE;
private:
FeatureRef(const FeatureRef & rhs);
const Face * m_face;
FeatureSetting * m_nameValues; // array of name table ids for feature values
chunk_t m_mask, // bit mask to get the value from the vector
m_max; // max value the value can take
uint32 m_id; // feature identifier/name
uint16 m_nameid, // Name table id for feature name
m_numSet; // number of values (number of entries in m_nameValues)
flags_t m_flags; // feature flags see FeatureRef::flags_t.
byte m_bits, // how many bits to shift the value into place
m_index; // index into the array to find the ulong to mask
private: //unimplemented
FeatureRef& operator=(const FeatureRef&);
};
inline
FeatureRef::FeatureRef() throw()
: m_face(0),
m_nameValues(0),
m_mask(0), m_max(0),
m_id(0), m_nameid(0), m_numSet(0),
m_flags(flags_t(0)),
m_bits(0), m_index(0)
{
}
class NameAndFeatureRef
{
public:
NameAndFeatureRef(uint32 name = 0) : m_name(name) , m_pFRef(NULL){}
NameAndFeatureRef(FeatureRef const & p) : m_name(p.getId()), m_pFRef(&p) {}
bool operator<(const NameAndFeatureRef& rhs) const //orders by m_name
{ return m_name<rhs.m_name; }
CLASS_NEW_DELETE
uint32 m_name;
const FeatureRef* m_pFRef;
};
class FeatureMap
{
public:
FeatureMap() : m_numFeats(0), m_feats(NULL), m_pNamedFeats(NULL) {}
~FeatureMap() { delete[] m_feats; delete[] m_pNamedFeats; }
bool readFeats(const Face & face);
const FeatureRef *findFeatureRef(uint32 name) const;
FeatureRef *feature(uint16 index) const { return m_feats + index; }
//GrFeatureRef *featureRef(byte index) { return index < m_numFeats ? m_feats + index : NULL; }
const FeatureRef *featureRef(byte index) const { return index < m_numFeats ? m_feats + index : NULL; }
FeatureVal* cloneFeatures(uint32 langname/*0 means default*/) const; //call destroy_Features when done.
uint16 numFeats() const { return m_numFeats; };
CLASS_NEW_DELETE
private:
friend class SillMap;
uint16 m_numFeats;
FeatureRef *m_feats;
NameAndFeatureRef* m_pNamedFeats; //owned
FeatureVal m_defaultFeatures; //owned
private: //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
FeatureMap(const FeatureMap&);
FeatureMap& operator=(const FeatureMap&);
};
class SillMap
{
private:
class LangFeaturePair
{
LangFeaturePair(const LangFeaturePair &);
LangFeaturePair & operator = (const LangFeaturePair &);
public:
LangFeaturePair() : m_lang(0), m_pFeatures(0) {}
~LangFeaturePair() { delete m_pFeatures; }
uint32 m_lang;
Features* m_pFeatures; //owns
CLASS_NEW_DELETE
};
public:
SillMap() : m_langFeats(NULL), m_numLanguages(0) {}
~SillMap() { delete[] m_langFeats; }
bool readFace(const Face & face);
bool readSill(const Face & face);
FeatureVal* cloneFeatures(uint32 langname/*0 means default*/) const; //call destroy_Features when done.
uint16 numLanguages() const { return m_numLanguages; };
uint32 getLangName(uint16 index) const { return (index < m_numLanguages)? m_langFeats[index].m_lang : 0; };
const FeatureMap & theFeatureMap() const { return m_FeatureMap; };
private:
FeatureMap m_FeatureMap; //of face
LangFeaturePair * m_langFeats;
uint16 m_numLanguages;
private: //defensive on m_langFeats
SillMap(const SillMap&);
SillMap& operator=(const SillMap&);
};
} // namespace graphite2
struct gr_feature_ref : public graphite2::FeatureRef {};

View File

@ -0,0 +1,68 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstring>
#include <cassert>
#include "inc/Main.h"
#include "inc/List.h"
namespace graphite2 {
class FeatureRef;
class FeatureMap;
class FeatureVal : public Vector<uint32>
{
public:
FeatureVal() : m_pMap(0) { }
FeatureVal(int num, const FeatureMap & pMap) : Vector<uint32>(num), m_pMap(&pMap) {}
FeatureVal(const FeatureVal & rhs) : Vector<uint32>(rhs), m_pMap(rhs.m_pMap) {}
FeatureVal & operator = (const FeatureVal & rhs) { Vector<uint32>::operator = (rhs); m_pMap = rhs.m_pMap; return *this; }
bool operator ==(const FeatureVal & b) const
{
size_t n = size();
if (n != b.size()) return false;
for(const_iterator l = begin(), r = b.begin(); n && *l == *r; --n, ++l, ++r);
return n == 0;
}
CLASS_NEW_DELETE
private:
friend class FeatureRef; //so that FeatureRefs can manipulate m_vec directly
const FeatureMap* m_pMap;
};
typedef FeatureVal Features;
} // namespace graphite2
struct gr_feature_val : public graphite2::FeatureVal {};

80
thirdparty/graphite/src/inc/FileFace.h vendored Normal file
View File

@ -0,0 +1,80 @@
/* GRAPHITE2 LICENSING
Copyright 2012, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
//#include "inc/FeatureMap.h"
//#include "inc/GlyphsCache.h"
//#include "inc/Silf.h"
#ifndef GRAPHITE2_NFILEFACE
#include <cstdio>
#include <cassert>
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/TtfTypes.h"
#include "inc/TtfUtil.h"
namespace graphite2 {
class FileFace
{
static const void * get_table_fn(const void* appFaceHandle, unsigned int name, size_t *len);
static void rel_table_fn(const void* appFaceHandle, const void *table_buffer);
public:
static const gr_face_ops ops;
FileFace(const char *filename);
~FileFace();
operator bool () const throw();
CLASS_NEW_DELETE;
private: //defensive
FILE * _file;
size_t _file_len;
TtfUtil::Sfnt::OffsetSubTable * _header_tbl;
TtfUtil::Sfnt::OffsetSubTable::Entry * _table_dir;
FileFace(const FileFace&);
FileFace& operator=(const FileFace&);
};
inline
FileFace::operator bool() const throw()
{
return _file && _header_tbl && _table_dir;
}
} // namespace graphite2
#endif //!GRAPHITE2_NFILEFACE

90
thirdparty/graphite/src/inc/Font.h vendored Normal file
View File

@ -0,0 +1,90 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cassert>
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/Face.h"
namespace graphite2 {
#define INVALID_ADVANCE -1e38f // can't be a static const because non-integral
class Font
{
public:
Font(float ppm, const Face & face, const void * appFontHandle=0, const gr_font_ops * ops=0);
virtual ~Font();
float advance(unsigned short glyphid) const;
float scale() const;
bool isHinted() const;
const Face & face() const;
operator bool () const throw() { return m_advances; }
CLASS_NEW_DELETE;
private:
gr_font_ops m_ops;
const void * const m_appFontHandle;
float * m_advances; // One advance per glyph in pixels. Nan if not defined
const Face & m_face;
float m_scale; // scales from design units to ppm
bool m_hinted;
Font(const Font&);
Font& operator=(const Font&);
};
inline
float Font::advance(unsigned short glyphid) const
{
if (m_advances[glyphid] == INVALID_ADVANCE)
m_advances[glyphid] = (*m_ops.glyph_advance_x)(m_appFontHandle, glyphid);
return m_advances[glyphid];
}
inline
float Font::scale() const
{
return m_scale;
}
inline
bool Font::isHinted() const
{
return m_hinted;
}
inline
const Face & Font::face() const
{
return m_face;
}
} // namespace graphite2
struct gr_font : public graphite2::Font {};

223
thirdparty/graphite/src/inc/GlyphCache.h vendored Normal file
View File

@ -0,0 +1,223 @@
/* GRAPHITE2 LICENSING
Copyright 2012, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/Position.h"
#include "inc/GlyphFace.h"
namespace graphite2 {
class Face;
class FeatureVal;
class Segment;
struct SlantBox
{
static const SlantBox empty;
// SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
float width() const { return sa - si; }
float height() const { return da - di; }
float si; // min
float di; // min
float sa; // max
float da; // max
};
struct BBox
{
BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {};
float width() const { return xa - xi; }
float height() const { return ya - yi; }
float xi; // min
float yi; // min
float xa; // max
float ya; // max
};
class GlyphBox
{
GlyphBox(const GlyphBox &);
GlyphBox & operator = (const GlyphBox &);
public:
GlyphBox(uint8 numsubs, unsigned short bitmap, Rect *slanted) : _num(numsubs), _bitmap(bitmap), _slant(*slanted) {};
void addSubBox(int subindex, int boundary, Rect *val) { _subs[subindex * 2 + boundary] = *val; }
Rect &subVal(int subindex, int boundary) { return _subs[subindex * 2 + boundary]; }
const Rect &slant() const { return _slant; }
uint8 num() const { return _num; }
const Rect *subs() const { return _subs; }
private:
uint8 _num;
unsigned short _bitmap;
Rect _slant;
Rect _subs[1];
};
class GlyphCache
{
class Loader;
GlyphCache(const GlyphCache&);
GlyphCache& operator=(const GlyphCache&);
public:
GlyphCache(const Face & face, const uint32 face_options);
~GlyphCache();
unsigned short numGlyphs() const throw();
unsigned short numAttrs() const throw();
unsigned short unitsPerEm() const throw();
const GlyphFace *glyph(unsigned short glyphid) const; //result may be changed by subsequent call with a different glyphid
const GlyphFace *glyphSafe(unsigned short glyphid) const;
float getBoundingMetric(unsigned short glyphid, uint8 metric) const;
uint8 numSubBounds(unsigned short glyphid) const;
float getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; }
const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
const BBox & getBoundingBBox(unsigned short glyphid) const;
const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
const BBox & getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
bool check(unsigned short glyphid) const;
bool hasBoxes() const { return _boxes != 0; }
CLASS_NEW_DELETE;
private:
const Rect _empty_slant_box;
const Loader * _glyph_loader;
const GlyphFace * * _glyphs;
GlyphBox * * _boxes;
unsigned short _num_glyphs,
_num_attrs,
_upem;
};
inline
unsigned short GlyphCache::numGlyphs() const throw()
{
return _num_glyphs;
}
inline
unsigned short GlyphCache::numAttrs() const throw()
{
return _num_attrs;
}
inline
unsigned short GlyphCache::unitsPerEm() const throw()
{
return _upem;
}
inline
bool GlyphCache::check(unsigned short glyphid) const
{
return _boxes && glyphid < _num_glyphs;
}
inline
const GlyphFace *GlyphCache::glyphSafe(unsigned short glyphid) const
{
return glyphid < _num_glyphs ? glyph(glyphid) : NULL;
}
inline
float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
{
if (glyphid >= _num_glyphs) return 0.;
switch (metric) {
case 0: return (float)(glyph(glyphid)->theBBox().bl.x); // x_min
case 1: return (float)(glyph(glyphid)->theBBox().bl.y); // y_min
case 2: return (float)(glyph(glyphid)->theBBox().tr.x); // x_max
case 3: return (float)(glyph(glyphid)->theBBox().tr.y); // y_max
case 4: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.x : 0.f); // sum_min
case 5: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.y : 0.f); // diff_min
case 6: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.x : 0.f); // sum_max
case 7: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.y : 0.f); // diff_max
default: return 0.;
}
}
inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
{
return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty;
}
inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
{
return *(BBox *)(&(glyph(glyphid)->theBBox()));
}
inline
float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const
{
GlyphBox *b = _boxes[glyphid];
if (b == NULL || subindex >= b->num()) return 0;
switch (metric) {
case 0: return b->subVal(subindex, 0).bl.x;
case 1: return b->subVal(subindex, 0).bl.y;
case 2: return b->subVal(subindex, 0).tr.x;
case 3: return b->subVal(subindex, 0).tr.y;
case 4: return b->subVal(subindex, 1).bl.x;
case 5: return b->subVal(subindex, 1).bl.y;
case 6: return b->subVal(subindex, 1).tr.x;
case 7: return b->subVal(subindex, 1).tr.y;
default: return 0.;
}
}
inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
{
GlyphBox *b = _boxes[glyphid];
return *(SlantBox *)(b->subs() + 2 * subindex + 1);
}
inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
{
GlyphBox *b = _boxes[glyphid];
return *(BBox *)(b->subs() + 2 * subindex);
}
inline
uint8 GlyphCache::numSubBounds(unsigned short glyphid) const
{
return _boxes[glyphid] ? _boxes[glyphid]->num() : 0;
}
} // namespace graphite2

83
thirdparty/graphite/src/inc/GlyphFace.h vendored Normal file
View File

@ -0,0 +1,83 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Main.h"
#include "inc/Position.h"
#include "inc/Sparse.h"
namespace graphite2 {
enum metrics {
kgmetLsb = 0, kgmetRsb,
kgmetBbTop, kgmetBbBottom, kgmetBbLeft, kgmetBbRight,
kgmetBbHeight, kgmetBbWidth,
kgmetAdvWidth, kgmetAdvHeight,
kgmetAscent, kgmetDescent
};
class GlyphFace
{
public:
GlyphFace();
template<typename I>
GlyphFace(const Rect & bbox, const Position & adv, I first, const I last);
const Position & theAdvance() const;
const Rect & theBBox() const { return m_bbox; }
const sparse & attrs() const { return m_attrs; }
int32 getMetric(uint8 metric) const;
CLASS_NEW_DELETE;
private:
Rect m_bbox; // bounding box metrics in design units
Position m_advance; // Advance width and height in design units
sparse m_attrs;
};
// Inlines: class GlyphFace
//
inline
GlyphFace::GlyphFace()
{}
template<typename I>
GlyphFace::GlyphFace(const Rect & bbox, const Position & adv, I first, const I last)
: m_bbox(bbox),
m_advance(adv),
m_attrs(first, last)
{
}
inline
const Position & GlyphFace::theAdvance() const {
return m_advance;
}
} // namespace graphite2

234
thirdparty/graphite/src/inc/Intervals.h vendored Normal file
View File

@ -0,0 +1,234 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <utility>
#include "inc/Main.h"
#include "inc/List.h"
#include "inc/json.h"
#include "inc/Position.h"
// An IntervalSet represents the possible movement of a given glyph in a given direction
// (horizontally, vertically, or diagonally).
// A vector is needed to represent disjoint ranges, eg, -300..-150, 20..200, 500..750.
// Each pair represents the min/max of a sub-range.
namespace graphite2 {
class Segment;
enum zones_t {SD, XY};
class Zones
{
struct Exclusion
{
template<zones_t O>
static Exclusion weighted(float xmin, float xmax, float f, float a0,
float m, float xi, float ai, float c, bool nega);
float x, // x position
xm, // xmax position
c, // constant + sum(MiXi^2)
sm, // sum(Mi)
smx; // sum(MiXi)
bool open;
Exclusion(float x, float w, float smi, float smxi, float c);
Exclusion & operator += (Exclusion const & rhs);
uint8 outcode(float p) const;
Exclusion split_at(float p);
void left_trim(float p);
bool track_cost(float & cost, float & x, float origin) const;
private:
float test_position(float origin) const;
float cost(float x) const;
};
typedef Vector<Exclusion> exclusions;
typedef exclusions::iterator iterator;
typedef Exclusion * pointer;
typedef Exclusion & reference;
typedef std::reverse_iterator<iterator> reverse_iterator;
public:
typedef exclusions::const_iterator const_iterator;
typedef Exclusion const * const_pointer;
typedef Exclusion const & const_reference;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
#if !defined GRAPHITE2_NTRACING
struct Debug
{
Exclusion _excl;
bool _isdel;
Vector<void *> _env;
Debug(Exclusion *e, bool isdel, json *dbg) : _excl(*e), _isdel(isdel), _env(dbg->getenvs()) { };
};
typedef Vector<Debug> debugs;
typedef debugs::const_iterator idebugs;
void addDebug(Exclusion *e);
void removeDebug(float pos, float posm);
void setdebug(json *dbgout) { _dbg = dbgout; }
idebugs dbgs_begin() const { return _dbgs.begin(); }
idebugs dbgs_end() const { return _dbgs.end(); }
void jsonDbgOut(Segment *seg) const;
Position position() const { return Position(_pos, _posm); }
#endif
Zones();
template<zones_t O>
void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao);
void exclude(float xmin, float xmax);
void exclude_with_margins(float xmin, float xmax, int axis);
template<zones_t O>
void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
float closest( float origin, float &cost) const;
const_iterator begin() const { return _exclusions.begin(); }
const_iterator end() const { return _exclusions.end(); }
private:
exclusions _exclusions;
#if !defined GRAPHITE2_NTRACING
json * _dbg;
debugs _dbgs;
#endif
float _margin_len,
_margin_weight,
_pos,
_posm;
void insert(Exclusion e);
void remove(float x, float xm);
const_iterator find_exclusion_under(float x) const;
};
inline
Zones::Zones()
: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
{
#if !defined GRAPHITE2_NTRACING
_dbg = 0;
#endif
_exclusions.reserve(8);
}
inline
Zones::Exclusion::Exclusion(float x_, float xm_, float smi, float smxi, float c_)
: x(x_), xm(xm_), c(c_), sm(smi), smx(smxi), open(false)
{ }
template<zones_t O>
inline
void Zones::initialise(float xmin, float xmax, float margin_len,
float margin_weight, float a0)
{
_margin_len = margin_len;
_margin_weight = margin_weight;
_pos = xmin;
_posm = xmax;
_exclusions.clear();
_exclusions.push_back(Exclusion::weighted<O>(xmin, xmax, 1, a0, 0, 0, 0, 0, false));
_exclusions.front().open = true;
#if !defined GRAPHITE2_NTRACING
_dbgs.clear();
#endif
}
inline
void Zones::exclude(float xmin, float xmax) {
remove(xmin, xmax);
}
template<zones_t O>
inline
void Zones::weighted(float xmin, float xmax, float f, float a0,
float m, float xi, float ai, float c, bool nega) {
insert(Exclusion::weighted<O>(xmin, xmax, f, a0, m, xi, ai, c, nega));
}
inline
void Zones::weightedAxis(int axis, float xmin, float xmax, float f, float a0,
float m, float xi, float ai, float c, bool nega) {
if (axis < 2)
weighted<XY>(xmin, xmax, f, a0, m, xi, ai, c, nega);
else
weighted<SD>(xmin, xmax, f, a0, m, xi, ai, c, nega);
}
#if !defined GRAPHITE2_NTRACING
inline
void Zones::addDebug(Exclusion *e) {
if (_dbg)
_dbgs.push_back(Debug(e, false, _dbg));
}
inline
void Zones::removeDebug(float pos, float posm) {
if (_dbg)
{
Exclusion e(pos, posm, 0, 0, 0);
_dbgs.push_back(Debug(&e, true, _dbg));
}
}
#endif
template<>
inline
Zones::Exclusion Zones::Exclusion::weighted<XY>(float xmin, float xmax, float f, float a0,
float m, float xi, GR_MAYBE_UNUSED float ai, float c, GR_MAYBE_UNUSED bool nega) {
return Exclusion(xmin, xmax,
m + f,
m * xi,
m * xi * xi + f * a0 * a0 + c);
}
template<>
inline
Zones::Exclusion Zones::Exclusion::weighted<SD>(float xmin, float xmax, float f, float a0,
float m, float xi, float ai,float c, bool nega) {
float xia = nega ? xi - ai : xi + ai;
return Exclusion(xmin, xmax,
0.25f * (m + 2.f * f),
0.25f * m * xia,
0.25f * (m * xia * xia + 2.f * f * a0 * a0) + c);
}
} // end of namespace graphite2

168
thirdparty/graphite/src/inc/List.h vendored Normal file
View File

@ -0,0 +1,168 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// designed to have a limited subset of the std::vector api
#pragma once
#include <cstddef>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <new>
#include "Main.h"
namespace graphite2 {
template <typename T>
inline
ptrdiff_t distance(T* first, T* last) { return last-first; }
template <typename T>
class Vector
{
T * m_first, *m_last, *m_end;
public:
typedef T & reference;
typedef const T & const_reference;
typedef T * iterator;
typedef const T * const_iterator;
Vector() : m_first(0), m_last(0), m_end(0) {}
Vector(size_t n, const T& value = T()) : m_first(0), m_last(0), m_end(0) { insert(begin(), n, value); }
Vector(const Vector<T> &rhs) : m_first(0), m_last(0), m_end(0) { insert(begin(), rhs.begin(), rhs.end()); }
template <typename I>
Vector(I first, const I last) : m_first(0), m_last(0), m_end(0) { insert(begin(), first, last); }
~Vector() { clear(); free(m_first); }
iterator begin() { return m_first; }
const_iterator begin() const { return m_first; }
iterator end() { return m_last; }
const_iterator end() const { return m_last; }
bool empty() const { return m_first == m_last; }
size_t size() const { return m_last - m_first; }
size_t capacity() const{ return m_end - m_first; }
void reserve(size_t n);
void resize(size_t n, const T & v = T());
reference front() { assert(size() > 0); return *begin(); }
const_reference front() const { assert(size() > 0); return *begin(); }
reference back() { assert(size() > 0); return *(end()-1); }
const_reference back() const { assert(size() > 0); return *(end()-1); }
Vector<T> & operator = (const Vector<T> & rhs) { assign(rhs.begin(), rhs.end()); return *this; }
reference operator [] (size_t n) { assert(size() > n); return m_first[n]; }
const_reference operator [] (size_t n) const { assert(size() > n); return m_first[n]; }
void assign(size_t n, const T& u) { clear(); insert(begin(), n, u); }
void assign(const_iterator first, const_iterator last) { clear(); insert(begin(), first, last); }
iterator insert(iterator p, const T & x) { p = _insert_default(p, 1); new (p) T(x); return p; }
void insert(iterator p, size_t n, const T & x);
void insert(iterator p, const_iterator first, const_iterator last);
void pop_back() { assert(size() > 0); --m_last; }
void push_back(const T &v) { if (m_last == m_end) reserve(size()+1); new (m_last++) T(v); }
void clear() { erase(begin(), end()); }
iterator erase(iterator p) { return erase(p, p+1); }
iterator erase(iterator first, iterator last);
private:
iterator _insert_default(iterator p, size_t n);
};
template <typename T>
inline
void Vector<T>::reserve(size_t n)
{
if (n > capacity())
{
const ptrdiff_t sz = size();
size_t requested;
if (checked_mul(n,sizeof(T), requested)) std::abort();
m_first = static_cast<T*>(realloc(m_first, requested));
if (!m_first) std::abort();
m_last = m_first + sz;
m_end = m_first + n;
}
}
template <typename T>
inline
void Vector<T>::resize(size_t n, const T & v) {
const ptrdiff_t d = n-size();
if (d < 0) erase(end()+d, end());
else if (d > 0) insert(end(), d, v);
}
template<typename T>
inline
typename Vector<T>::iterator Vector<T>::_insert_default(iterator p, size_t n)
{
assert(begin() <= p && p <= end());
const ptrdiff_t i = p - begin();
reserve(((size() + n + 7) >> 3) << 3);
p = begin() + i;
// Move tail if there is one
if (p != end()) memmove(p + n, p, distance(p,end())*sizeof(T));
m_last += n;
return p;
}
template<typename T>
inline
void Vector<T>::insert(iterator p, size_t n, const T & x)
{
p = _insert_default(p, n);
// Copy in elements
for (; n; --n, ++p) { new (p) T(x); }
}
template<typename T>
inline
void Vector<T>::insert(iterator p, const_iterator first, const_iterator last)
{
p = _insert_default(p, distance(first, last));
// Copy in elements
for (;first != last; ++first, ++p) { new (p) T(*first); }
}
template<typename T>
inline
typename Vector<T>::iterator Vector<T>::erase(iterator first, iterator last)
{
for (iterator e = first; e != last; ++e) e->~T();
const size_t sz = distance(first, last);
if (m_last != last) memmove(first, last, distance(last,end())*sizeof(T));
m_last -= sz;
return first;
}
} // namespace graphite2

207
thirdparty/graphite/src/inc/Machine.h vendored Normal file
View File

@ -0,0 +1,207 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This general interpreter interface.
// Author: Tim Eves
// Build one of direct_machine.cpp or call_machine.cpp to implement this
// interface.
#pragma once
#include <cstring>
#include <limits>
#include <graphite2/Types.h>
#include "inc/Main.h"
#if defined(__GNUC__)
#if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ * 10) < 430
#define HOT
#if defined(__x86_64)
#define REGPARM(n) __attribute__((regparm(n)))
#else
#define REGPARM(n)
#endif
#else
#define HOT __attribute__((hot))
#if defined(__x86_64)
#define REGPARM(n) __attribute__((hot, regparm(n)))
#else
#define REGPARM(n)
#endif
#endif
#else
#define HOT
#define REGPARM(n)
#endif
#if defined(__MINGW32__)
// MinGW's <limits> at some point includes winnt.h which #define's a
// DELETE macro, which conflicts with enum opcode below, so we undefine
// it here.
#undef DELETE
#endif
namespace graphite2 {
// Forward declarations
class Segment;
class Slot;
class SlotMap;
namespace vm
{
typedef void * instr;
typedef Slot * slotref;
enum {VARARGS = 0xff, MAX_NAME_LEN=32};
enum opcode {
NOP = 0,
PUSH_BYTE, PUSH_BYTEU, PUSH_SHORT, PUSH_SHORTU, PUSH_LONG,
ADD, SUB, MUL, DIV,
MIN_, MAX_,
NEG,
TRUNC8, TRUNC16,
COND,
AND, OR, NOT,
EQUAL, NOT_EQ,
LESS, GTR, LESS_EQ, GTR_EQ,
NEXT, NEXT_N, COPY_NEXT,
PUT_GLYPH_8BIT_OBS, PUT_SUBS_8BIT_OBS, PUT_COPY,
INSERT, DELETE,
ASSOC,
CNTXT_ITEM,
ATTR_SET, ATTR_ADD, ATTR_SUB,
ATTR_SET_SLOT,
IATTR_SET_SLOT,
PUSH_SLOT_ATTR, PUSH_GLYPH_ATTR_OBS,
PUSH_GLYPH_METRIC, PUSH_FEAT,
PUSH_ATT_TO_GATTR_OBS, PUSH_ATT_TO_GLYPH_METRIC,
PUSH_ISLOT_ATTR,
PUSH_IGLYPH_ATTR, // not implemented
POP_RET, RET_ZERO, RET_TRUE,
IATTR_SET, IATTR_ADD, IATTR_SUB,
PUSH_PROC_STATE, PUSH_VERSION,
PUT_SUBS, PUT_SUBS2, PUT_SUBS3,
PUT_GLYPH, PUSH_GLYPH_ATTR, PUSH_ATT_TO_GLYPH_ATTR,
BITOR, BITAND, BITNOT,
BITSET, SET_FEAT,
MAX_OPCODE,
// private opcodes for internal use only, comes after all other on disk opcodes
TEMP_COPY = MAX_OPCODE
};
struct opcode_t
{
instr impl[2];
uint8 param_sz;
char name[MAX_NAME_LEN];
};
class Machine
{
public:
typedef int32 stack_t;
static size_t const STACK_ORDER = 10,
STACK_MAX = 1 << STACK_ORDER,
STACK_GUARD = 2;
class Code;
enum status_t {
finished = 0,
stack_underflow,
stack_not_empty,
stack_overflow,
slot_offset_out_bounds,
died_early
};
Machine(SlotMap &) throw();
static const opcode_t * getOpcodeTable() throw();
CLASS_NEW_DELETE;
SlotMap & slotMap() const throw();
status_t status() const throw();
// operator bool () const throw();
private:
void check_final_stack(const stack_t * const sp);
stack_t run(const instr * program, const byte * data,
slotref * & map) HOT;
SlotMap & _map;
stack_t _stack[STACK_MAX + 2*STACK_GUARD];
status_t _status;
};
inline Machine::Machine(SlotMap & map) throw()
: _map(map), _status(finished)
{
// Initialise stack guard +1 entries as the stack pointer points to the
// current top of stack, hence the first push will never write entry 0.
// Initialising the guard space like this is unnecessary and is only
// done to keep valgrind happy during fuzz testing. Hopefully loop
// unrolling will flatten this.
for (size_t n = STACK_GUARD + 1; n; --n) _stack[n-1] = 0;
}
inline SlotMap& Machine::slotMap() const throw()
{
return _map;
}
inline Machine::status_t Machine::status() const throw()
{
return _status;
}
inline void Machine::check_final_stack(const stack_t * const sp)
{
if (_status != finished) return;
stack_t const * const base = _stack + STACK_GUARD,
* const limit = base + STACK_MAX;
if (sp < base) _status = stack_underflow; // This should be impossible now.
else if (sp >= limit) _status = stack_overflow; // So should this.
else if (sp != base) _status = stack_not_empty;
}
} // namespace vm
} // namespace graphite2

199
thirdparty/graphite/src/inc/Main.h vendored Normal file
View File

@ -0,0 +1,199 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstdlib>
#include "graphite2/Types.h"
#ifdef GRAPHITE2_CUSTOM_HEADER
#include GRAPHITE2_CUSTOM_HEADER
#endif
namespace graphite2 {
typedef gr_uint8 uint8;
typedef gr_uint8 byte;
typedef gr_uint16 uint16;
typedef gr_uint32 uint32;
typedef gr_int8 int8;
typedef gr_int16 int16;
typedef gr_int32 int32;
typedef size_t uintptr;
#ifdef GRAPHITE2_TELEMETRY
struct telemetry
{
class category;
static size_t * _category;
static void set_category(size_t & t) throw() { _category = &t; }
static void stop() throw() { _category = 0; }
static void count_bytes(size_t n) throw() { if (_category) *_category += n; }
size_t misc,
silf,
glyph,
code,
states,
starts,
transitions;
telemetry() : misc(0), silf(0), glyph(0), code(0), states(0), starts(0), transitions(0) {}
};
class telemetry::category
{
size_t * _prev;
public:
category(size_t & t) : _prev(_category) { _category = &t; }
~category() { _category = _prev; }
};
#else
struct telemetry {};
#endif
// Checked multiplaction to catch overflow or underflow when allocating memory
#if defined(__has_builtin)
#if __has_builtin(__builtin_mul_overflow)
#define HAVE_BUILTIN_OVERFLOW
#endif
#elif defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__INTEL_COMPILER)
#define HAVE_BUILTIN_OVERFLOW
#endif
#if defined(__has_include)
#if __has_include(<intsafe.h>) && !defined(__CYGWIN__)
#define HAVE_INTSAFE_H
#endif
#elif defined(_WIN32)
#define HAVE_INTSAFE_H
#endif
// Need to import intsafe into the top level namespace
#if defined(HAVE_INTSAFE_H)
} // namespace graphite2
#include <intsafe.h>
namespace graphite2 {
#endif
#if defined(HAVE_BUILTIN_OVERFLOW)
inline
bool checked_mul(const size_t a, const size_t b, size_t & t) {
return __builtin_mul_overflow(a, b, &t);
}
#elif defined(HAVE_INTSAFE_H)
inline
bool checked_mul(const size_t a, const size_t b, size_t & t) {
return SizeTMult(a, b, &t) == INTSAFE_E_ARITHMETIC_OVERFLOW;
}
#else
inline
bool checked_mul(const size_t a, const size_t b, size_t & t) {
t = a*b;
return (((a | b) & (~size_t(0) << (sizeof(size_t) << 2))) && (t / a != b));
}
#endif
// typesafe wrapper around malloc for simple types
// use free(pointer) to deallocate
template <typename T> T * gralloc(size_t n)
{
size_t total;
if (checked_mul(n, sizeof(T), total))
return 0;
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(total);
#endif
return static_cast<T*>(malloc(total));
}
template <typename T> T * grzeroalloc(size_t n)
{
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
return static_cast<T*>(calloc(n, sizeof(T)));
}
template <typename T>
inline T min(const T a, const T b)
{
return a < b ? a : b;
}
template <typename T>
inline T max(const T a, const T b)
{
return a > b ? a : b;
}
} // namespace graphite2
#define CLASS_NEW_DELETE \
void * operator new (size_t size){ return gralloc<byte>(size);} \
void * operator new (size_t, void * p) throw() { return p; } \
void * operator new[] (size_t size) {return gralloc<byte>(size);} \
void * operator new[] (size_t, void * p) throw() { return p; } \
void operator delete (void * p) throw() { free(p);} \
void operator delete (void *, void *) throw() {} \
void operator delete[] (void * p)throw() { free(p); } \
void operator delete[] (void *, void *) throw() {}
#if defined(__GNUC__) || defined(__clang__)
#define GR_MAYBE_UNUSED __attribute__((unused))
#else
#define GR_MAYBE_UNUSED
#endif
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(clang::fallthrough)
# define GR_FALLTHROUGH [[clang::fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
# define GR_FALLTHROUGH [[gnu::fallthrough]]
#elif defined(_MSC_VER)
/*
* MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
* https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
*/
#include <sal.h>
#define GR_FALLTHROUGH __fallthrough
#elif __GNUC__ >= 7
#define GR_FALLTHROUGH __attribute__ ((fallthrough))
#else
#define GR_FALLTHROUGH /* fallthrough */
#endif
#ifdef _MSC_VER
#pragma warning(disable: 4800)
#pragma warning(disable: 4355)
#endif

65
thirdparty/graphite/src/inc/NameTable.h vendored Normal file
View File

@ -0,0 +1,65 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <graphite2/Segment.h>
#include "inc/TtfTypes.h"
#include "inc/locale2lcid.h"
namespace graphite2 {
class NameTable
{
NameTable(const NameTable &);
NameTable & operator = (const NameTable &);
public:
NameTable(const void * data, size_t length, uint16 platfromId=3, uint16 encodingID = 1);
~NameTable() { free(const_cast<TtfUtil::Sfnt::FontNames *>(m_table)); }
enum eNameFallback {
eNoFallback = 0,
eEnUSFallbackOnly = 1,
eEnOrAnyFallback = 2
};
uint16 setPlatformEncoding(uint16 platfromId=3, uint16 encodingID = 1);
void * getName(uint16 & languageId, uint16 nameId, gr_encform enc, uint32 & length);
uint16 getLanguageId(const char * bcp47Locale);
CLASS_NEW_DELETE
private:
uint16 m_platformId;
uint16 m_encodingId;
uint16 m_languageCount;
uint16 m_platformOffset; // offset of first NameRecord with for platform 3, encoding 1
uint16 m_platformLastRecord;
uint16 m_nameDataLength;
const TtfUtil::Sfnt::FontNames * m_table;
const uint8 * m_nameData;
Locale2Lang m_locale2Lang;
};
} // namespace graphite2

118
thirdparty/graphite/src/inc/Pass.h vendored Normal file
View File

@ -0,0 +1,118 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstdlib>
#include "inc/Code.h"
namespace graphite2 {
class Segment;
class Face;
class Silf;
struct Rule;
struct RuleEntry;
struct State;
class FiniteStateMachine;
class Error;
class ShiftCollider;
class KernCollider;
class json;
enum passtype;
class Pass
{
public:
Pass();
~Pass();
bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face,
enum passtype pt, uint32 version, Error &e);
bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const;
void init(Silf *silf) { m_silf = silf; }
byte collisionLoops() const { return m_numCollRuns; }
bool reverseDir() const { return m_isReverseDir; }
CLASS_NEW_DELETE
private:
void findNDoRule(Slot* & iSlot, vm::Machine &, FiniteStateMachine& fsm) const;
int doAction(const vm::Machine::Code* codeptr, Slot * & slot_out, vm::Machine &) const;
bool testPassConstraint(vm::Machine & m) const;
bool testConstraint(const Rule & r, vm::Machine &) const;
bool readRules(const byte * rule_map, const size_t num_entries,
const byte *precontext, const uint16 * sort_key,
const uint16 * o_constraint, const byte *constraint_data,
const uint16 * o_action, const byte * action_data,
Face &, enum passtype pt, Error &e);
bool readStates(const byte * starts, const byte * states, const byte * o_rule_map, Face &, Error &e);
bool readRanges(const byte * ranges, size_t num_ranges, Error &e);
uint16 glyphToCol(const uint16 gid) const;
bool runFSM(FiniteStateMachine & fsm, Slot * slot) const;
void dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
void dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
void adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
bool collisionShift(Segment *seg, int dir, json * const dbgout) const;
bool collisionKern(Segment *seg, int dir, json * const dbgout) const;
bool collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const;
bool resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev,
int dir, bool &moved, bool &hasCol, json * const dbgout) const;
float resolveKern(Segment *seg, Slot *slot, Slot *start, int dir,
float &ymin, float &ymax, json *const dbgout) const;
const Silf * m_silf;
uint16 * m_cols;
Rule * m_rules; // rules
RuleEntry * m_ruleMap;
uint16 * m_startStates; // prectxt length
uint16 * m_transitions;
State * m_states;
vm::Machine::Code * m_codes;
byte * m_progs;
byte m_numCollRuns;
byte m_kernColls;
byte m_iMaxLoop;
uint16 m_numGlyphs;
uint16 m_numRules;
uint16 m_numStates;
uint16 m_numTransition;
uint16 m_numSuccess;
uint16 m_successStart;
uint16 m_numColumns;
byte m_minPreCtxt;
byte m_maxPreCtxt;
byte m_colThreshold;
bool m_isReverseDir;
vm::Machine::Code m_cPConstraint;
private: //defensive
Pass(const Pass&);
Pass& operator=(const Pass&);
};
} // namespace graphite2

68
thirdparty/graphite/src/inc/Position.h vendored Normal file
View File

@ -0,0 +1,68 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
namespace graphite2 {
class Position
{
public:
Position() : x(0), y(0) { }
Position(const float inx, const float iny) : x(inx), y(iny) {}
Position operator + (const Position& a) const { return Position(x + a.x, y + a.y); }
Position operator - (const Position& a) const { return Position(x - a.x, y - a.y); }
Position operator * (const float m) const { return Position(x * m, y * m); }
Position &operator += (const Position &a) { x += a.x; y += a.y; return *this; }
Position &operator *= (const float m) { x *= m; y *= m; return *this; }
float x;
float y;
};
class Rect
{
public :
Rect() {}
Rect(const Position& botLeft, const Position& topRight): bl(botLeft), tr(topRight) {}
Rect widen(const Rect& other) { return Rect(Position(bl.x > other.bl.x ? other.bl.x : bl.x, bl.y > other.bl.y ? other.bl.y : bl.y), Position(tr.x > other.tr.x ? tr.x : other.tr.x, tr.y > other.tr.y ? tr.y : other.tr.y)); }
Rect operator + (const Position &a) const { return Rect(Position(bl.x + a.x, bl.y + a.y), Position(tr.x + a.x, tr.y + a.y)); }
Rect operator - (const Position &a) const { return Rect(Position(bl.x - a.x, bl.y - a.y), Position(tr.x - a.x, tr.y - a.y)); }
Rect operator * (float m) const { return Rect(Position(bl.x, bl.y) * m, Position(tr.x, tr.y) * m); }
float width() const { return tr.x - bl.x; }
float height() const { return tr.y - bl.y; }
bool hitTest(Rect &other);
// returns Position(overlapx, overlapy) where overlap<0 if overlapping else positive)
Position overlap(Position &offset, Rect &other, Position &otherOffset);
//Position constrainedAvoid(Position &offset, Rect &box, Rect &sdbox, Position &other, Rect &obox, Rect &osdbox);
Position bl;
Position tr;
};
} // namespace graphite2

305
thirdparty/graphite/src/inc/Rule.h vendored Normal file
View File

@ -0,0 +1,305 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Code.h"
#include "inc/Slot.h"
namespace graphite2 {
struct Rule {
const vm::Machine::Code * constraint,
* action;
unsigned short sort;
byte preContext;
#ifndef NDEBUG
uint16 rule_idx;
#endif
Rule();
~Rule() {}
CLASS_NEW_DELETE;
private:
Rule(const Rule &);
Rule & operator = (const Rule &);
};
inline
Rule::Rule()
: constraint(0),
action(0),
sort(0),
preContext(0)
{
#ifndef NDEBUG
rule_idx = 0;
#endif
}
struct RuleEntry
{
const Rule * rule;
inline
bool operator < (const RuleEntry &r) const
{
const unsigned short lsort = rule->sort, rsort = r.rule->sort;
return lsort > rsort || (lsort == rsort && rule < r.rule);
}
inline
bool operator == (const RuleEntry &r) const
{
return rule == r.rule;
}
};
struct State
{
const RuleEntry * rules,
* rules_end;
bool empty() const;
};
inline
bool State::empty() const
{
return rules_end == rules;
}
class SlotMap
{
public:
enum {MAX_SLOTS=64};
SlotMap(Segment & seg, uint8 direction, size_t maxSize);
Slot * * begin();
Slot * * end();
size_t size() const;
unsigned short context() const;
void reset(Slot &, unsigned short);
Slot * const & operator[](int n) const;
Slot * & operator [] (int);
void pushSlot(Slot * const slot);
void collectGarbage(Slot *& aSlot);
Slot * highwater() { return m_highwater; }
void highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
bool highpassed() const { return m_highpassed; }
void highpassed(bool v) { m_highpassed = v; }
uint8 dir() const { return m_dir; }
int decMax() { return --m_maxSize; }
Segment & segment;
private:
Slot * m_slot_map[MAX_SLOTS+1];
unsigned short m_size;
unsigned short m_precontext;
Slot * m_highwater;
int m_maxSize;
uint8 m_dir;
bool m_highpassed;
};
class FiniteStateMachine
{
public:
enum {MAX_RULES=128};
private:
class Rules
{
public:
Rules();
void clear();
const RuleEntry * begin() const;
const RuleEntry * end() const;
size_t size() const;
void accumulate_rules(const State &state);
private:
RuleEntry * m_begin,
* m_end,
m_rules[MAX_RULES*2];
};
public:
FiniteStateMachine(SlotMap & map, json * logger);
void reset(Slot * & slot, const short unsigned int max_pre_ctxt);
Rules rules;
SlotMap & slots;
json * const dbgout;
};
inline
FiniteStateMachine::FiniteStateMachine(SlotMap& map, json * logger)
: slots(map),
dbgout(logger)
{
}
inline
void FiniteStateMachine::reset(Slot * & slot, const short unsigned int max_pre_ctxt)
{
rules.clear();
int ctxt = 0;
for (; ctxt != max_pre_ctxt && slot->prev(); ++ctxt, slot = slot->prev());
slots.reset(*slot, ctxt);
}
inline
FiniteStateMachine::Rules::Rules()
: m_begin(m_rules), m_end(m_rules)
{
}
inline
void FiniteStateMachine::Rules::clear()
{
m_end = m_begin;
}
inline
const RuleEntry * FiniteStateMachine::Rules::begin() const
{
return m_begin;
}
inline
const RuleEntry * FiniteStateMachine::Rules::end() const
{
return m_end;
}
inline
size_t FiniteStateMachine::Rules::size() const
{
return m_end - m_begin;
}
inline
void FiniteStateMachine::Rules::accumulate_rules(const State &state)
{
// Only bother if there are rules in the State object.
if (state.empty()) return;
// Merge the new sorted rules list into the current sorted result set.
const RuleEntry * lre = begin(), * rre = state.rules;
RuleEntry * out = m_rules + (m_begin == m_rules)*MAX_RULES;
const RuleEntry * const lrend = out + MAX_RULES,
* const rrend = state.rules_end;
m_begin = out;
while (lre != end() && out != lrend)
{
if (*lre < *rre) *out++ = *lre++;
else if (*rre < *lre) { *out++ = *rre++; }
else { *out++ = *lre++; ++rre; }
if (rre == rrend)
{
while (lre != end() && out != lrend) { *out++ = *lre++; }
m_end = out;
return;
}
}
while (rre != rrend && out != lrend) { *out++ = *rre++; }
m_end = out;
}
inline
SlotMap::SlotMap(Segment & seg, uint8 direction, size_t maxSize)
: segment(seg), m_size(0), m_precontext(0), m_highwater(0),
m_maxSize(int(maxSize)), m_dir(direction), m_highpassed(false)
{
m_slot_map[0] = 0;
}
inline
Slot * * SlotMap::begin()
{
return &m_slot_map[1]; // allow map to go 1 before slot_map when inserting
// at start of segment.
}
inline
Slot * * SlotMap::end()
{
return m_slot_map + m_size + 1;
}
inline
size_t SlotMap::size() const
{
return m_size;
}
inline
short unsigned int SlotMap::context() const
{
return m_precontext;
}
inline
void SlotMap::reset(Slot & slot, short unsigned int ctxt)
{
m_size = 0;
m_precontext = ctxt;
*m_slot_map = slot.prev();
}
inline
void SlotMap::pushSlot(Slot*const slot)
{
m_slot_map[++m_size] = slot;
}
inline
Slot * const & SlotMap::operator[](int n) const
{
return m_slot_map[n + 1];
}
inline
Slot * & SlotMap::operator[](int n)
{
return m_slot_map[n + 1];
}
} // namespace graphite2

236
thirdparty/graphite/src/inc/Segment.h vendored Normal file
View File

@ -0,0 +1,236 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "inc/Main.h"
#include <cassert>
#include "inc/CharInfo.h"
#include "inc/Face.h"
#include "inc/FeatureVal.h"
#include "inc/GlyphCache.h"
#include "inc/GlyphFace.h"
#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/List.h"
#include "inc/Collider.h"
#define MAX_SEG_GROWTH_FACTOR 64
namespace graphite2 {
typedef Vector<Features> FeatureList;
typedef Vector<Slot *> SlotRope;
typedef Vector<int16 *> AttributeRope;
typedef Vector<SlotJustify *> JustifyRope;
class Font;
class Segment;
class Silf;
enum SpliceParam {
/** sub-Segments longer than this are not cached
* (in Unicode code points) */
eMaxSpliceSize = 96
};
enum justFlags {
gr_justStartInline = 1,
gr_justEndInline = 2
};
class SegmentScopeState
{
private:
friend class Segment;
Slot * realFirstSlot;
Slot * slotBeforeScope;
Slot * slotAfterScope;
Slot * realLastSlot;
size_t numGlyphsOutsideScope;
};
class Segment
{
// Prevent copying of any kind.
Segment(const Segment&);
Segment& operator=(const Segment&);
public:
enum {
SEG_INITCOLLISIONS = 1,
SEG_HASCOLLISIONS = 2
};
size_t slotCount() const { return m_numGlyphs; } //one slot per glyph
void extendLength(ptrdiff_t num) { m_numGlyphs += num; }
Position advance() const { return m_advance; }
bool runGraphite() { if (m_silf) return m_face->runGraphite(this, m_silf); else return true;};
void chooseSilf(uint32 script) { m_silf = m_face->chooseSilf(script); }
const Silf *silf() const { return m_silf; }
size_t charInfoCount() const { return m_numCharinfo; }
const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; }
CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; }
Segment(size_t numchars, const Face* face, uint32 script, int dir);
~Segment();
uint8 flags() const { return m_flags; }
void flags(uint8 f) { m_flags = f; }
Slot *first() { return m_first; }
void first(Slot *p) { m_first = p; }
Slot *last() { return m_last; }
void last(Slot *p) { m_last = p; }
void appendSlot(int i, int cid, int gid, int fid, size_t coffset);
Slot *newSlot();
void freeSlot(Slot *);
SlotJustify *newJustify();
void freeJustify(SlotJustify *aJustify);
Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl = false, bool isFinal = true);
void associateChars(int offset, size_t num);
void linkClusters(Slot *first, Slot *last);
uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); }
uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); }
int addFeatures(const Features& feats) { m_feats.push_back(feats); return int(m_feats.size()) - 1; }
uint32 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); }
void setFeature(int index, uint8 findex, uint32 val) {
const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex);
if (pFR)
{
if (val > pFR->maxVal()) val = pFR->maxVal();
pFR->applyValToFeature(val, m_feats[index]);
} }
int8 dir() const { return m_dir; }
void dir(int8 val) { m_dir = val; }
bool currdir() const { return ((m_dir >> 6) ^ m_dir) & 1; }
uint8 passBits() const { return m_passBits; }
void mergePassBits(const uint8 val) { m_passBits &= val; }
int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; }
int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const;
float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; }
const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); } //warning value may become invalid when another glyph is accessed
Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; }
int numAttrs() const { return m_silf->numUser(); }
int defaultOriginal() const { return m_defaultOriginal; }
const Face * getFace() const { return m_face; }
const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; }
void bidiPass(int paradir, uint8 aMirror);
int8 getSlotBidiClass(Slot *s) const;
void doMirror(uint16 aMirror);
Slot *addLineEnd(Slot *nSlot);
void delLineEnd(Slot *s);
bool hasJustification() const { return m_justifies.size() != 0; }
void reverseSlots();
bool isWhitespace(const int cid) const;
bool hasCollisionInfo() const { return (m_flags & SEG_HASCOLLISIONS) && m_collisions; }
SlotCollision *collisionInfo(const Slot *s) const { return m_collisions ? m_collisions + s->index() : 0; }
CLASS_NEW_DELETE
public: //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
void finalise(const Font *font, bool reverse=false);
float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
bool initCollisions();
private:
Position m_advance; // whole segment advance
SlotRope m_slots; // Vector of slot buffers
AttributeRope m_userAttrs; // Vector of userAttrs buffers
JustifyRope m_justifies; // Slot justification info buffers
FeatureList m_feats; // feature settings referenced by charinfos in this segment
Slot * m_freeSlots; // linked list of free slots
SlotJustify * m_freeJustifies; // Slot justification blocks free list
CharInfo * m_charinfo; // character info, one per input character
SlotCollision * m_collisions;
const Face * m_face; // GrFace
const Silf * m_silf;
Slot * m_first; // first slot in segment
Slot * m_last; // last slot in segment
size_t m_bufSize, // how big a buffer to create when need more slots
m_numGlyphs,
m_numCharinfo; // size of the array and number of input characters
int m_defaultOriginal; // number of whitespace chars in the string
int8 m_dir;
uint8 m_flags, // General purpose flags
m_passBits; // if bit set then skip pass
};
inline
int8 Segment::getSlotBidiClass(Slot *s) const
{
int8 res = s->getBidiClass();
if (res != -1) return res;
res = int8(glyphAttr(s->gid(), m_silf->aBidi()));
s->setBidiClass(res);
return res;
}
inline
void Segment::finalise(const Font *font, bool reverse)
{
if (!m_first || !m_last) return;
m_advance = positionSlots(font, m_first, m_last, m_silf->dir(), true);
//associateChars(0, m_numCharinfo);
if (reverse && currdir() != (m_dir & 1))
reverseSlots();
linkClusters(m_first, m_last);
}
inline
int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const {
if (attrLevel > 0)
{
Slot *is = findRoot(iSlot);
return is->clusterMetric(this, metric, attrLevel, rtl);
}
else
return m_face->getGlyphMetric(iSlot->gid(), metric);
}
inline
bool Segment::isWhitespace(const int cid) const
{
return ((cid >= 0x0009) * (cid <= 0x000D)
+ (cid == 0x0020)
+ (cid == 0x0085)
+ (cid == 0x00A0)
+ (cid == 0x1680)
+ (cid == 0x180E)
+ (cid >= 0x2000) * (cid <= 0x200A)
+ (cid == 0x2028)
+ (cid == 0x2029)
+ (cid == 0x202F)
+ (cid == 0x205F)
+ (cid == 0x3000)) != 0;
}
} // namespace graphite2
struct gr_segment : public graphite2::Segment {};

128
thirdparty/graphite/src/inc/Silf.h vendored Normal file
View File

@ -0,0 +1,128 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "graphite2/Font.h"
#include "inc/Main.h"
#include "inc/Pass.h"
namespace graphite2 {
class Face;
class Segment;
class FeatureVal;
class VMScratch;
class Error;
class Pseudo
{
public:
uint32 uid;
uint32 gid;
CLASS_NEW_DELETE;
};
class Justinfo
{
public:
Justinfo(uint8 stretch, uint8 shrink, uint8 step, uint8 weight) :
m_astretch(stretch), m_ashrink(shrink), m_astep(step),
m_aweight(weight) {};
uint8 attrStretch() const { return m_astretch; }
uint8 attrShrink() const { return m_ashrink; }
uint8 attrStep() const { return m_astep; }
uint8 attrWeight() const { return m_aweight; }
private:
uint8 m_astretch;
uint8 m_ashrink;
uint8 m_astep;
uint8 m_aweight;
};
class Silf
{
// Prevent copying
Silf(const Silf&);
Silf& operator=(const Silf&);
public:
Silf() throw();
~Silf() throw();
bool readGraphite(const byte * const pSilf, size_t lSilf, Face &face, uint32 version);
bool runGraphite(Segment *seg, uint8 firstPass=0, uint8 lastPass=0, int dobidi = 0) const;
uint16 findClassIndex(uint16 cid, uint16 gid) const;
uint16 getClassGlyph(uint16 cid, unsigned int index) const;
uint16 findPseudo(uint32 uid) const;
uint8 numUser() const { return m_aUser; }
uint8 aPseudo() const { return m_aPseudo; }
uint8 aBreak() const { return m_aBreak; }
uint8 aMirror() const {return m_aMirror; }
uint8 aPassBits() const { return m_aPassBits; }
uint8 aBidi() const { return m_aBidi; }
uint8 aCollision() const { return m_aCollision; }
uint8 substitutionPass() const { return m_sPass; }
uint8 positionPass() const { return m_pPass; }
uint8 justificationPass() const { return m_jPass; }
uint8 bidiPass() const { return m_bPass; }
uint8 numPasses() const { return m_numPasses; }
uint8 maxCompPerLig() const { return m_iMaxComp; }
uint16 numClasses() const { return m_nClass; }
byte flags() const { return m_flags; }
byte dir() const { return m_dir; }
uint8 numJustLevels() const { return m_numJusts; }
Justinfo *justAttrs() const { return m_justs; }
uint16 endLineGlyphid() const { return m_gEndLine; }
const gr_faceinfo *silfInfo() const { return &m_silfinfo; }
CLASS_NEW_DELETE;
private:
size_t readClassMap(const byte *p, size_t data_len, uint32 version, Error &e);
template<typename T> inline uint32 readClassOffsets(const byte *&p, size_t data_len, Error &e);
Pass * m_passes;
Pseudo * m_pseudos;
uint32 * m_classOffsets;
uint16 * m_classData;
Justinfo * m_justs;
uint8 m_numPasses;
uint8 m_numJusts;
uint8 m_sPass, m_pPass, m_jPass, m_bPass,
m_flags, m_dir;
uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
m_iMaxComp, m_aCollision;
uint16 m_aLig, m_numPseudo, m_nClass, m_nLinear,
m_gEndLine;
gr_faceinfo m_silfinfo;
void releaseBuffers() throw();
};
} // namespace graphite2

170
thirdparty/graphite/src/inc/Slot.h vendored Normal file
View File

@ -0,0 +1,170 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include "graphite2/Types.h"
#include "graphite2/Segment.h"
#include "inc/Main.h"
#include "inc/Font.h"
#include "inc/Position.h"
namespace graphite2 {
typedef gr_attrCode attrCode;
class GlyphFace;
class Segment;
struct SlotJustify
{
static const int NUMJUSTPARAMS = 5;
SlotJustify(const SlotJustify &);
SlotJustify & operator = (const SlotJustify &);
public:
static size_t size_of(size_t levels) { return sizeof(SlotJustify) + ((levels > 1 ? levels : 1)*NUMJUSTPARAMS - 1)*sizeof(int16); }
void LoadSlot(const Slot *s, const Segment *seg);
SlotJustify *next;
int16 values[1];
};
class Slot
{
enum Flag
{
DELETED = 1,
INSERTED = 2,
COPIED = 4,
POSITIONED = 8,
ATTACHED = 16
};
public:
struct iterator;
unsigned short gid() const { return m_glyphid; }
Position origin() const { return m_position; }
float advance() const { return m_advance.x; }
void advance(Position &val) { m_advance = val; }
Position advancePos() const { return m_advance; }
int before() const { return m_before; }
int after() const { return m_after; }
uint32 index() const { return m_index; }
void index(uint32 val) { m_index = val; }
Slot(int16 *m_userAttr = NULL);
void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars);
Slot *next() const { return m_next; }
void next(Slot *s) { m_next = s; }
Slot *prev() const { return m_prev; }
void prev(Slot *s) { m_prev = s; }
uint16 glyph() const { return m_realglyphid ? m_realglyphid : m_glyphid; }
void setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph = NULL);
void setRealGid(uint16 realGid) { m_realglyphid = realGid; }
void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
void origin(const Position &pos) { m_position = pos + m_shift; }
void originate(int ind) { m_original = ind; }
int original() const { return m_original; }
void before(int ind) { m_before = ind; }
void after(int ind) { m_after = ind; }
bool isBase() const { return (!m_parent); }
void update(int numSlots, int numCharInfo, Position &relpos);
Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth = 0);
bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
bool isCopied() const { return (m_flags & COPIED) ? true : false; }
void markCopied(bool state) { if (state) m_flags |= COPIED; else m_flags &= ~COPIED; }
bool isPositioned() const { return (m_flags & POSITIONED) ? true : false; }
void markPositioned(bool state) { if (state) m_flags |= POSITIONED; else m_flags &= ~POSITIONED; }
bool isInsertBefore() const { return !(m_flags & INSERTED); }
uint8 getBidiLevel() const { return m_bidiLevel; }
void setBidiLevel(uint8 level) { m_bidiLevel = level; }
int8 getBidiClass(const Segment *seg);
int8 getBidiClass() const { return m_bidiCls; }
void setBidiClass(int8 cls) { m_bidiCls = cls; }
int16 *userAttrs() const { return m_userAttr; }
void userAttrs(int16 *p) { m_userAttr = p; }
void markInsertBefore(bool state) { if (!state) m_flags |= INSERTED; else m_flags &= ~INSERTED; }
void setAttr(Segment* seg, attrCode ind, uint8 subindex, int16 val, const SlotMap & map);
int getAttr(const Segment *seg, attrCode ind, uint8 subindex) const;
int getJustify(const Segment *seg, uint8 level, uint8 subindex) const;
void setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value);
bool isLocalJustify() const { return m_justs != NULL; };
void attachTo(Slot *ap) { m_parent = ap; }
Slot *attachedTo() const { return m_parent; }
Position attachOffset() const { return m_attach - m_with; }
Slot* firstChild() const { return m_child; }
void firstChild(Slot *ap) { m_child = ap; }
bool child(Slot *ap);
Slot* nextSibling() const { return m_sibling; }
void nextSibling(Slot *ap) { m_sibling = ap; }
bool sibling(Slot *ap);
bool removeChild(Slot *ap);
int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
void positionShift(Position a) { m_position += a; }
void floodShift(Position adj, int depth = 0);
float just() const { return m_just; }
void just(float j) { m_just = j; }
Slot *nextInCluster(const Slot *s) const;
bool isChildOf(const Slot *base) const;
CLASS_NEW_DELETE
private:
Slot *m_next; // linked list of slots
Slot *m_prev;
unsigned short m_glyphid; // glyph id
uint16 m_realglyphid;
uint32 m_original; // charinfo that originated this slot (e.g. for feature values)
uint32 m_before; // charinfo index of before association
uint32 m_after; // charinfo index of after association
uint32 m_index; // slot index given to this slot during finalising
Slot *m_parent; // index to parent we are attached to
Slot *m_child; // index to first child slot that attaches to us
Slot *m_sibling; // index to next child that attaches to our parent
Position m_position; // absolute position of glyph
Position m_shift; // .shift slot attribute
Position m_advance; // .advance slot attribute
Position m_attach; // attachment point on us
Position m_with; // attachment point position on parent
float m_just; // Justification inserted space
uint8 m_flags; // holds bit flags
byte m_attLevel; // attachment level
int8 m_bidiCls; // bidirectional class
byte m_bidiLevel; // bidirectional level
int16 *m_userAttr; // pointer to user attributes
SlotJustify *m_justs; // pointer to justification parameters
friend class Segment;
};
} // namespace graphite2
struct gr_slot : public graphite2::Slot {};

168
thirdparty/graphite/src/inc/Sparse.h vendored Normal file
View File

@ -0,0 +1,168 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <iterator>
#include <utility>
#include "inc/Main.h"
namespace graphite2 {
// A read-only packed fast sparse array of uint16 with uint16 keys.
// Like most container classes this has capacity and size properties and these
// refer to the number of stored entries and the number of addressable entries
// as normal. However due the sparse nature the capacity is always <= than the
// size.
class sparse
{
public:
typedef uint16 key_type;
typedef uint16 mapped_type;
typedef std::pair<const key_type, mapped_type> value_type;
private:
typedef unsigned long mask_t;
static const unsigned char SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;
struct chunk
{
mask_t mask:SIZEOF_CHUNK;
key_type offset;
};
static const chunk empty_chunk;
sparse(const sparse &);
sparse & operator = (const sparse &);
public:
template<typename I>
sparse(I first, const I last);
sparse() throw();
~sparse() throw();
operator bool () const throw();
mapped_type operator [] (const key_type k) const throw();
size_t capacity() const throw();
size_t size() const throw();
size_t _sizeof() const throw();
CLASS_NEW_DELETE;
private:
union {
chunk * map;
mapped_type * values;
} m_array;
key_type m_nchunks;
};
inline
sparse::sparse() throw() : m_nchunks(0)
{
m_array.map = const_cast<graphite2::sparse::chunk *>(&empty_chunk);
}
template <typename I>
sparse::sparse(I attr, const I last)
: m_nchunks(0)
{
m_array.map = 0;
// Find the maximum extent of the key space.
size_t n_values=0;
long lastkey = -1;
for (I i = attr; i != last; ++i, ++n_values)
{
const typename std::iterator_traits<I>::value_type v = *i;
if (v.second == 0) { --n_values; continue; }
if (v.first <= lastkey) { m_nchunks = 0; return; }
lastkey = v.first;
const key_type k = v.first / SIZEOF_CHUNK;
if (k >= m_nchunks) m_nchunks = k+1;
}
if (m_nchunks == 0)
{
m_array.map=const_cast<graphite2::sparse::chunk *>(&empty_chunk);
return;
}
m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)
/ sizeof(mapped_type)
+ n_values);
if (m_array.values == 0)
return;
// coverity[forward_null : FALSE] Since m_array is union and m_array.values is not NULL
chunk * ci = m_array.map;
ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
mapped_type * vi = m_array.values + ci->offset;
for (; attr != last; ++attr, ++vi)
{
const typename std::iterator_traits<I>::value_type v = *attr;
if (v.second == 0) { --vi; continue; }
chunk * const ci_ = m_array.map + v.first/SIZEOF_CHUNK;
if (ci != ci_)
{
ci = ci_;
ci->offset = key_type(vi - m_array.values);
}
ci->mask |= 1UL << (SIZEOF_CHUNK - 1 - (v.first % SIZEOF_CHUNK));
*vi = v.second;
}
}
inline
sparse::operator bool () const throw()
{
return m_array.map != 0;
}
inline
size_t sparse::size() const throw()
{
return m_nchunks*SIZEOF_CHUNK;
}
inline
size_t sparse::_sizeof() const throw()
{
return sizeof(sparse) + capacity()*sizeof(mapped_type) + m_nchunks*sizeof(chunk);
}
} // namespace graphite2

419
thirdparty/graphite/src/inc/TtfTypes.h vendored Normal file
View File

@ -0,0 +1,419 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
/*--------------------------------------------------------------------*//*:Ignore this sentence.
File: TtfTypes.h
Responsibility: Tim Eves
Last reviewed: Not yet.
Description:
Provides types required to represent the TTF basic types.
-------------------------------------------------------------------------------*//*:End Ignore*/
//**********************************************************************************************
// Include files
//**********************************************************************************************
namespace graphite2
{
namespace TtfUtil
{
//**********************************************************************************************
// Forward declarations
//**********************************************************************************************
//**********************************************************************************************
// Type declarations
//**********************************************************************************************
typedef unsigned char uint8;
typedef uint8 byte;
typedef signed char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
typedef int16 short_frac;
typedef int32 fixed;
typedef int16 fword;
typedef uint16 ufword;
typedef int16 f2dot14;
typedef uint32 long_date_time[2];
//**********************************************************************************************
// Constants and enum types
//**********************************************************************************************/
enum
{
OneFix = 1<<16
};
//**********************************************************************************************
// Table declarations
//**********************************************************************************************
namespace Sfnt
{
#pragma pack(push,1) // We need this or the structure members aren't aligned
// correctly. Fortunately this form of pragma is supposed
// to be recognised by VS C++ too (at least according to
// MSDN).
struct OffsetSubTable
{
uint32 scaler_type;
uint16 num_tables,
search_range,
entry_selector,
range_shift;
struct Entry
{
uint32 tag,
checksum,
offset,
length;
} table_directory[1];
enum ScalerType
{
TrueTypeMac = 0x74727565U,
TrueTypeWin = 0x00010000U,
Type1 = 0x74797031U
};
};
struct CharacterCodeMap
{
uint16 version,
num_subtables;
struct
{
uint16 platform_id,
platform_specific_id;
uint32 offset;
} encoding[1];
};
struct CmapSubTable
{
uint16 format,
length,
language;
};
struct CmapSubTableFormat4 : CmapSubTable
{
uint16 seg_count_x2,
search_range,
entry_selector,
range_shift,
end_code[1];
// There are arrarys after this which need their
// start positions calculated since end_code is
// seg_count uint16s long.
};
struct CmapSubTableFormat12
{
fixed format;
uint32 length,
language,
num_groups;
struct
{
uint32 start_char_code,
end_char_code,
start_glyph_id;
} group[1];
};
struct FontHeader
{
fixed version,
font_revision;
uint32 check_sum_adjustment,
magic_number;
uint16 flags,
units_per_em;
long_date_time created,
modified;
fword x_min,
y_min,
x_max,
y_max;
uint16 mac_style,
lowest_rec_ppem;
int16 font_direction_hint,
index_to_loc_format,
glyph_data_format;
enum
{
MagicNumber = 0x5F0F3CF5,
GlypDataFormat = 0
};
enum {ShortIndexLocFormat, LongIndexLocFormat};
};
struct PostScriptGlyphName
{
fixed format,
italic_angle;
fword underline_position,
underline_thickness;
uint32 is_fixed_pitch,
min_mem_type42,
max_mem_type42,
min_mem_type1,
max_mem_type1;
enum
{
Format1 = 0x10000,
Format2 = 0x20000,
Format25 = 0x28000,
Format3 = 0x30000,
Format4 = 0x40000
};
};
struct PostScriptGlyphName2 : PostScriptGlyphName
{
uint16 number_of_glyphs,
glyph_name_index[1];
};
struct PostScriptGlyphName25 : PostScriptGlyphName
{
uint16 number_of_glyphs;
int8 offset[1];
};
struct PostScriptGlyphName3 : PostScriptGlyphName {};
struct PostScriptGlyphName4 : PostScriptGlyphName
{
uint16 glyph_to_char_map[1];
};
struct HorizontalHeader
{
fixed version;
fword ascent,
descent,
line_gap;
ufword advance_width_max;
fword min_left_side_bearing,
max_left_side_bearing,
x_max_element;
int16 caret_slope_rise,
caret_slope_run;
fword caret_offset;
int16 reserved[4],
metric_data_format;
uint16 num_long_hor_metrics;
};
struct MaximumProfile
{
fixed version;
uint16 num_glyphs,
max_points,
max_contours,
max_component_points,
max_component_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;
};
typedef byte Panose[10];
struct Compatibility0
{
uint16 version;
int16 x_avg_char_width;
uint16 weight_class,
width_class;
int16 fs_type,
y_subscript_x_size,
y_subscript_y_size,
y_subscript_x_offset,
y_subscript_y_offset,
y_superscript_x_size,
y_superscript_y_size,
y_superscript_x_offset,
y_superscript_y_offset,
y_strikeout_size,
y_strikeout_position,
family_class;
Panose panose;
uint32 unicode_range[4];
int8 ach_vend_id[4];
uint16 fs_selection,
fs_first_char_index,
fs_last_char_index, // Acording to Apple's spec this is where v0 should end
typo_ascender,
typo_descender,
type_linegap,
win_ascent,
win_descent;
enum
{
Italic =0x01,
Underscore=0x02,
Negative =0x04,
Outlined =0x08,
StrikeOut =0x10,
Bold =0x20
};
};
struct Compatibility1 : Compatibility0
{
uint32 codepage_range[2];
};
struct Compatibility2 : Compatibility1
{
int16 x_height,
cap_height;
uint16 default_char,
break_char,
max_context;
};
struct Compatibility3 : Compatibility2 {};
typedef Compatibility3 Compatibility;
struct NameRecord
{
uint16 platform_id,
platform_specific_id,
language_id,
name_id,
length,
offset;
enum {Unicode, Mactintosh, Reserved, Microsoft};
enum
{
Copyright, Family, Subfamily, UniqueSubfamily,
Fullname, Version, PostScript
};
};
struct LangTagRecord
{
uint16 length,
offset;
};
struct FontNames
{
uint16 format,
count,
string_offset;
NameRecord name_record[1];
};
struct HorizontalMetric
{
uint16 advance_width;
int16 left_side_bearing;
};
struct Glyph
{
int16 number_of_contours;
fword x_min,
y_min,
x_max,
y_max;
};
struct SimpleGlyph : Glyph
{
uint16 end_pts_of_contours[1];
enum
{
OnCurve = 0x01,
XShort = 0x02,
YShort = 0x04,
Repeat = 0x08,
XIsSame = 0x10,
XIsPos = 0x10,
YIsSame = 0x20,
YIsPos = 0x20
};
};
struct CompoundGlyph : Glyph
{
uint16 flags,
glyph_index;
enum
{
Arg1Arg2Words = 0x01,
ArgsAreXYValues = 0x02,
RoundXYToGrid = 0x04,
HaveScale = 0x08,
MoreComponents = 0x20,
HaveXAndYScale = 0x40,
HaveTwoByTwo = 0x80,
HaveInstructions = 0x100,
UseMyMetrics = 0x200,
OverlapCompund = 0x400,
ScaledOffset = 0x800,
UnscaledOffset = 0x1000
};
};
#pragma pack(pop)
} // end of namespace Sfnt
} // end of namespace TtfUtil
} // end of namespace graphite2

208
thirdparty/graphite/src/inc/TtfUtil.h vendored Normal file
View File

@ -0,0 +1,208 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
/*--------------------------------------------------------------------*//*:Ignore this sentence.
File: TtfUtil.h
Responsibility: Alan Ward
Last reviewed: Not yet.
Description:
Utility class for handling TrueType font files.
----------------------------------------------------------------------------------------------*/
#include <cstddef>
namespace graphite2
{
namespace TtfUtil
{
#define OVERFLOW_OFFSET_CHECK(p, o) (o + reinterpret_cast<size_t>(p) < reinterpret_cast<size_t>(p))
typedef long fontTableId32;
typedef unsigned short gid16;
#define TTF_TAG(a,b,c,d) ((a << 24UL) + (b << 16UL) + (c << 8UL) + (d))
// Enumeration used to specify a table in a TTF file
class Tag
{
unsigned int _v;
public:
Tag(const char n[5]) throw() : _v(TTF_TAG(n[0],n[1],n[2],n[3])) {}
Tag(const unsigned int tag) throw() : _v(tag) {}
operator unsigned int () const throw () { return _v; }
enum
{
Feat = TTF_TAG('F','e','a','t'),
Glat = TTF_TAG('G','l','a','t'),
Gloc = TTF_TAG('G','l','o','c'),
Sile = TTF_TAG('S','i','l','e'),
Silf = TTF_TAG('S','i','l','f'),
Sill = TTF_TAG('S','i','l','l'),
cmap = TTF_TAG('c','m','a','p'),
cvt = TTF_TAG('c','v','t',' '),
cryp = TTF_TAG('c','r','y','p'),
head = TTF_TAG('h','e','a','d'),
fpgm = TTF_TAG('f','p','g','m'),
gdir = TTF_TAG('g','d','i','r'),
glyf = TTF_TAG('g','l','y','f'),
hdmx = TTF_TAG('h','d','m','x'),
hhea = TTF_TAG('h','h','e','a'),
hmtx = TTF_TAG('h','m','t','x'),
loca = TTF_TAG('l','o','c','a'),
kern = TTF_TAG('k','e','r','n'),
LTSH = TTF_TAG('L','T','S','H'),
maxp = TTF_TAG('m','a','x','p'),
name = TTF_TAG('n','a','m','e'),
OS_2 = TTF_TAG('O','S','/','2'),
post = TTF_TAG('p','o','s','t'),
prep = TTF_TAG('p','r','e','p')
};
};
/*----------------------------------------------------------------------------------------------
Class providing utility methods to parse a TrueType font file (TTF).
Callling application handles all file input and memory allocation.
Assumes minimal knowledge of TTF file format.
----------------------------------------------------------------------------------------------*/
////////////////////////////////// tools to find & check TTF tables
bool GetHeaderInfo(size_t & lOffset, size_t & lSize);
bool CheckHeader(const void * pHdr);
bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize);
bool GetTableInfo(const Tag TableTag, const void * pHdr, const void * pTableDir,
size_t & lOffset, size_t & lSize);
bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize);
////////////////////////////////// simple font wide info
size_t GlyphCount(const void * pMaxp);
#ifdef ALL_TTFUTILS
size_t MaxCompositeComponentCount(const void * pMaxp);
size_t MaxCompositeLevelCount(const void * pMaxp);
size_t LocaGlyphCount(size_t lLocaSize, const void * pHead); // throw (std::domain_error);
#endif
int DesignUnits(const void * pHead);
#ifdef ALL_TTFUTILS
int HeadTableCheckSum(const void * pHead);
void HeadTableCreateTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
void HeadTableModifyTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
bool IsItalic(const void * pHead);
int FontAscent(const void * pOs2);
int FontDescent(const void * pOs2);
bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic);
bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp,
const char * pPostName);
#endif
////////////////////////////////// utility methods helpful for name table
bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
int nLangId, int nNameId, size_t & lOffset, size_t & lSize);
//size_t NameTableLength(const byte * pTable);
#ifdef ALL_TTFUTILS
int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
int *nameIdList, int cNameIds, short *langIdList);
void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
#endif
////////////////////////////////// cmap lookup tools
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
int nEncodingId = 1, size_t length = 0);
bool CheckCmapSubtable4(const void * pCmap31, const void * pCmapEnd /*, unsigned int maxgid*/);
gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
int * pRangeKey = 0);
bool CheckCmapSubtable12(const void *pCmap310, const void * pCmapEnd /*, unsigned int maxgid*/);
gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
int * pRangeKey = 0);
///////////////////////////////// horizontal metric data for a glyph
bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize,
const void * pHhea, int & nLsb, unsigned int & nAdvWid);
////////////////////////////////// primitives for loca and glyf lookup
size_t LocaLookup(gid16 nGlyphId, const void * pLoca, size_t lLocaSize,
const void * pHead); // throw (std::out_of_range);
void * GlyfLookup(const void * pGlyf, size_t lGlyfOffset, size_t lTableLen);
////////////////////////////////// primitves for simple glyph data
bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin,
int & xMax, int & yMax);
#ifdef ALL_TTFUTILS
int GlyfContourCount(const void * pSimpleGlyf);
bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint,
int cnPointsTotal, size_t & cnPoints);
bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY,
char * prgbFlag, int cnPointsTotal, int & cnPoints);
// primitive to find the glyph ids in a composite glyph
bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId,
size_t cnCompIdTotal, size_t & cnCompId);
// primitive to find the placement data for a component in a composite glyph
bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
bool fOffset, int & a, int & b);
// primitive to find the transform data for a component in a composite glyph
bool GetComponentTransform(const void * pSimpleGlyf, int nCompId,
float & flt11, float & flt12, float & flt21, float & flt22, bool & fTransOffset);
#endif
////////////////////////////////// operate on composite or simple glyph (auto glyf lookup)
void * GlyfLookup(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
size_t lGlyfSize, size_t lLocaSize, const void * pHead); // primitive used by below methods
#ifdef ALL_TTFUTILS
// below are primary user methods for handling glyf data
bool IsSpace(gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead);
bool IsDeepComposite(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
size_t lGlyfSize, size_t lLocaSize, const void * pHead);
bool GlyfBox(gid16 nGlyphId, const void * pGlyf, const void * pLoca, size_t lGlyfSize, size_t lLocaSize,
const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax);
bool GlyfContourCount(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
size_t lGlyfSize, size_t lLocaSize, const void *pHead, size_t & cnContours);
bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
size_t lGlyfSize, size_t lLocaSize, const void * pHead, int * prgnContourEndPoint, size_t cnPoints);
bool GlyfPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
size_t lGlyfSize, size_t lLocaSize, const void * pHead, const int * prgnContourEndPoint, size_t cnEndPoints,
int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints);
// utitily method used by high-level GlyfPoints
bool SimplifyFlags(char * prgbFlags, int cnPoints);
bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints);
#endif
} // end of namespace TtfUtil
} // end of namespace graphite2

251
thirdparty/graphite/src/inc/UtfCodec.h vendored Normal file
View File

@ -0,0 +1,251 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstdlib>
#include "inc/Main.h"
namespace graphite2 {
typedef uint32 uchar_t;
template <int N>
struct _utf_codec
{
typedef uchar_t codeunit_t;
static void put(codeunit_t * cp, const uchar_t , int8 & len) throw();
static uchar_t get(const codeunit_t * cp, int8 & len) throw();
static bool validate(const codeunit_t * s, const codeunit_t * const e) throw();
};
template <>
struct _utf_codec<32>
{
private:
static const uchar_t limit = 0x110000;
public:
typedef uint32 codeunit_t;
inline
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
{
*cp = usv; l = 1;
}
inline
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
{
if (cp[0] < limit) { l = 1; return cp[0]; }
else { l = -1; return 0xFFFD; }
}
inline
static bool validate(const codeunit_t * s, const codeunit_t * const e) throw()
{
return s <= e;
}
};
template <>
struct _utf_codec<16>
{
private:
static const int32 lead_offset = 0xD800 - (0x10000 >> 10);
static const int32 surrogate_offset = 0x10000 - (0xD800 << 10) - 0xDC00;
public:
typedef uint16 codeunit_t;
inline
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
{
if (usv < 0x10000) { l = 1; cp[0] = codeunit_t(usv); }
else
{
cp[0] = codeunit_t(lead_offset + (usv >> 10));
cp[1] = codeunit_t(0xDC00 + (usv & 0x3FF));
l = 2;
}
}
inline
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
{
const uint32 uh = cp[0];
l = 1;
if (uh < 0xD800|| uh > 0xDFFF) { return uh; }
if (uh > 0xDBFF) { l = -1; return 0xFFFD; }
const uint32 ul = cp[1];
if (ul < 0xDC00 || ul > 0xDFFF) { l = -1; return 0xFFFD; }
++l;
return (uh<<10) + ul + surrogate_offset;
}
inline
static bool validate(const codeunit_t * s, const codeunit_t * const e) throw()
{
const ptrdiff_t n = e-s;
if (n <= 0) return n == 0;
const uint32 u = *(e-1); // Get the last codepoint
return (u < 0xD800 || u > 0xDBFF);
}
};
template <>
struct _utf_codec<8>
{
private:
static const int8 sz_lut[16];
static const byte mask_lut[5];
static const uchar_t limit = 0x110000;
public:
typedef uint8 codeunit_t;
inline
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
{
if (usv < 0x80) {l = 1; cp[0] = usv; return; }
if (usv < 0x0800) {l = 2; cp[0] = 0xC0 + (usv >> 6); cp[1] = 0x80 + (usv & 0x3F); return; }
if (usv < 0x10000) {l = 3; cp[0] = 0xE0 + (usv >> 12); cp[1] = 0x80 + ((usv >> 6) & 0x3F); cp[2] = 0x80 + (usv & 0x3F); return; }
else {l = 4; cp[0] = 0xF0 + (usv >> 18); cp[1] = 0x80 + ((usv >> 12) & 0x3F); cp[2] = 0x80 + ((usv >> 6) & 0x3F); cp[3] = 0x80 + (usv & 0x3F); return; }
}
inline
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
{
const int8 seq_sz = sz_lut[*cp >> 4];
uchar_t u = *cp & mask_lut[seq_sz];
l = 1;
bool toolong = false;
switch(seq_sz) {
case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10); GR_FALLTHROUGH;
// no break
case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); GR_FALLTHROUGH;
// no break
case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); GR_FALLTHROUGH;
// no break
case 1: break;
case 0: l = -1; return 0xFFFD;
}
if (l != seq_sz || toolong || u >= limit)
{
l = -l;
return 0xFFFD;
}
return u;
}
inline
static bool validate(const codeunit_t * s, const codeunit_t * const e) throw()
{
const ptrdiff_t n = e-s;
if (n <= 0) return n == 0;
s += (n-1);
if (*s < 0x80) return true;
if (*s >= 0xC0) return false;
if (n == 1) return true;
if (*--s < 0x80) return true;
if (*s >= 0xE0) return false;
if (n == 2 || *s >= 0xC0) return true;
if (*--s < 0x80) return true;
if (*s >= 0xF0) return false;
return true;
}
};
template <typename C>
class _utf_iterator
{
typedef _utf_codec<sizeof(C)*8> codec;
C * cp;
mutable int8 sl;
public:
typedef C codeunit_type;
typedef uchar_t value_type;
typedef uchar_t * pointer;
class reference
{
const _utf_iterator & _i;
reference(const _utf_iterator & i): _i(i) {}
public:
operator value_type () const throw () { return codec::get(_i.cp, _i.sl); }
reference & operator = (const value_type usv) throw() { codec::put(_i.cp, usv, _i.sl); return *this; }
friend class _utf_iterator;
};
_utf_iterator(const void * us=0) : cp(reinterpret_cast<C *>(const_cast<void *>(us))), sl(1) { }
_utf_iterator & operator ++ () { cp += abs(sl); return *this; }
_utf_iterator operator ++ (int) { _utf_iterator tmp(*this); operator++(); return tmp; }
bool operator == (const _utf_iterator & rhs) const throw() { return cp >= rhs.cp; }
bool operator != (const _utf_iterator & rhs) const throw() { return !operator==(rhs); }
reference operator * () const throw() { return *this; }
pointer operator ->() const throw() { return &operator *(); }
operator codeunit_type * () const throw() { return cp; }
bool error() const throw() { return sl < 1; }
bool validate(const _utf_iterator & e) { return codec::validate(cp, e.cp); }
};
template <typename C>
struct utf
{
typedef typename _utf_codec<sizeof(C)*8>::codeunit_t codeunit_t;
typedef _utf_iterator<C> iterator;
typedef _utf_iterator<const C> const_iterator;
inline
static bool validate(codeunit_t * s, codeunit_t * e) throw() {
return _utf_codec<sizeof(C)*8>::validate(s,e);
}
};
typedef utf<uint32> utf32;
typedef utf<uint16> utf16;
typedef utf<uint8> utf8;
} // namespace graphite2

150
thirdparty/graphite/src/inc/bits.h vendored Normal file
View File

@ -0,0 +1,150 @@
/* GRAPHITE2 LICENSING
Copyright 2012, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
namespace graphite2
{
#if defined GRAPHITE2_BUILTINS && (defined __GNUC__ || defined __clang__)
template<typename T>
inline unsigned int bit_set_count(T v)
{
return __builtin_popcount(v);
}
template<>
inline unsigned int bit_set_count(int16 v)
{
return __builtin_popcount(static_cast<uint16>(v));
}
template<>
inline unsigned int bit_set_count(int8 v)
{
return __builtin_popcount(static_cast<uint8>(v));
}
template<>
inline unsigned int bit_set_count(unsigned long v)
{
return __builtin_popcountl(v);
}
template<>
inline unsigned int bit_set_count(signed long v)
{
return __builtin_popcountl(v);
}
template<>
inline unsigned int bit_set_count(unsigned long long v)
{
return __builtin_popcountll(v);
}
template<>
inline unsigned int bit_set_count(signed long long v)
{
return __builtin_popcountll(v);
}
#else
template<typename T>
inline unsigned int bit_set_count(T v)
{
static size_t const ONES = ~0;
v = v - ((v >> 1) & T(ONES/3)); // temp
v = (v & T(ONES/15*3)) + ((v >> 2) & T(ONES/15*3)); // temp
v = (v + (v >> 4)) & T(ONES/255*15); // temp
return (T)(v * T(ONES/255)) >> (sizeof(T)-1)*8; // count
}
#endif
//TODO: Changed these to uintmax_t when we go to C++11
template<int S>
inline size_t _mask_over_val(size_t v)
{
v = _mask_over_val<S/2>(v);
v |= v >> S*4;
return v;
}
//TODO: Changed these to uintmax_t when we go to C++11
template<>
inline size_t _mask_over_val<1>(size_t v)
{
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
return v;
}
template<typename T>
inline T mask_over_val(T v)
{
return T(_mask_over_val<sizeof(T)>(v));
}
template<typename T>
inline unsigned long next_highest_power2(T v)
{
return _mask_over_val<sizeof(T)>(v-1)+1;
}
template<typename T>
inline unsigned int log_binary(T v)
{
return bit_set_count(mask_over_val(v))-1;
}
template<typename T>
inline T has_zero(const T x)
{
return (x - T(~T(0)/255)) & ~x & T(~T(0)/255*128);
}
template<typename T>
inline T zero_bytes(const T x, unsigned char n)
{
const T t = T(~T(0)/255*n);
return T((has_zero(x^t) >> 7)*n);
}
#if 0
inline float float_round(float x, uint32 m)
{
*reinterpret_cast<unsigned int *>(&x) &= m;
return *reinterpret_cast<float *>(&x);
}
#endif
}

89
thirdparty/graphite/src/inc/debug.h vendored Normal file
View File

@ -0,0 +1,89 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// debug.h
//
// Created on: 22 Dec 2011
// Author: tim
#pragma once
#if !defined GRAPHITE2_NTRACING
#include <utility>
#include "inc/json.h"
#include "inc/Position.h"
namespace graphite2
{
class CharInfo;
class Segment;
class Slot;
typedef std::pair<const Segment * const, const Slot * const> dslot;
struct objectid
{
char name[16];
objectid(const dslot &) throw();
objectid(const Segment * const p) throw();
};
json & operator << (json & j, const Position &) throw();
json & operator << (json & j, const Rect &) throw();
json & operator << (json & j, const CharInfo &) throw();
json & operator << (json & j, const dslot &) throw();
json & operator << (json & j, const objectid &) throw();
json & operator << (json & j, const telemetry &) throw();
inline
json & operator << (json & j, const Position & p) throw()
{
return j << json::flat << json::array << p.x << p.y << json::close;
}
inline
json & operator << (json & j, const Rect & p) throw()
{
return j << json::flat << json::array << p.bl.x << p.bl.y << p.tr.x << p.tr.y << json::close;
}
inline
json & operator << (json & j, const objectid & sid) throw()
{
return j << sid.name;
}
} // namespace graphite2
#endif //!defined GRAPHITE2_NTRACING

178
thirdparty/graphite/src/inc/json.h vendored Normal file
View File

@ -0,0 +1,178 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// JSON pretty printer for graphite font debug output logging.
// Created on: 15 Dec 2011
// Author: Tim Eves
#pragma once
#include "inc/Main.h"
#include <cassert>
#include <cstdio>
#include <cstdint>
#include "inc/List.h"
namespace graphite2 {
class json
{
// Prevent copying
json(const json &);
json & operator = (const json &);
typedef void (*_context_t)(json &);
FILE * const _stream;
char _contexts[128], // context stack
* _context, // current context (top of stack)
* _flatten; // if !0 points to context above which
// pretty printed output should occur.
Vector<void *> _env;
void context(const char current) throw();
void indent(const int d=0) throw();
void push_context(const char, const char) throw();
void pop_context() throw();
public:
class closer;
using string = const char *;
using number = double;
enum class integer : std::intmax_t {};
enum class integer_u : std::uintmax_t {};
using boolean = bool;
static const std::nullptr_t null;
void setenv(unsigned int index, void *val) { _env.reserve(index + 1); if (index >= _env.size()) _env.insert(_env.end(), _env.size() - index + 1, 0); _env[index] = val; }
void *getenv(unsigned int index) const { return _env[index]; }
const Vector<void *> &getenvs() const { return _env; }
static void flat(json &) throw();
static void close(json &) throw();
static void object(json &) throw();
static void array(json &) throw();
static void item(json &) throw();
json(FILE * stream) throw();
~json() throw ();
FILE * stream() const throw();
json & operator << (string) throw();
json & operator << (number) throw();
json & operator << (integer) throw();
json & operator << (integer_u) throw();
json & operator << (boolean) throw();
json & operator << (std::nullptr_t) throw();
json & operator << (_context_t) throw();
operator bool() const throw();
bool good() const throw();
bool eof() const throw();
CLASS_NEW_DELETE;
};
class json::closer
{
// Prevent copying.
closer(const closer &);
closer & operator = (const closer &);
json * const _j;
public:
closer(json * const j) : _j(j) {}
~closer() throw() { if (_j) *_j << close; }
};
inline
json::json(FILE * s) throw()
: _stream(s), _context(_contexts), _flatten(0)
{
if (good())
fflush(s);
}
inline
json::~json() throw ()
{
while (_context > _contexts) pop_context();
}
inline
FILE * json::stream() const throw() { return _stream; }
inline
json & json::operator << (json::_context_t ctxt) throw()
{
ctxt(*this);
return *this;
}
inline
json & operator << (json & j, signed char d) throw() { return j << json::integer(d); }
inline
json & operator << (json & j, unsigned char d) throw() { return j << json::integer_u(d); }
inline
json & operator << (json & j, short int d) throw() { return j << json::integer(d); }
inline
json & operator << (json & j, unsigned short int d) throw() { return j << json::integer_u(d); }
inline
json & operator << (json & j, int d) throw() { return j << json::integer(d); }
inline
json & operator << (json & j, unsigned int d) throw() { return j << json::integer_u(d); }
inline
json & operator << (json & j, long int d) throw() { return j << json::integer(d); }
inline
json & operator << (json & j, unsigned long int d) throw() { return j << json::integer_u(d); }
inline
json & operator << (json & j, long long int d) throw() { return j << json::integer(d); }
inline
json & operator << (json & j, unsigned long long int d) throw() { return j << json::integer_u(d); }
inline
json::operator bool() const throw() { return good(); }
inline
bool json::good() const throw() { return _stream && ferror(_stream) == 0; }
inline
bool json::eof() const throw() { return feof(_stream) != 0; }
} // namespace graphite2

View File

@ -0,0 +1,450 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstring>
#include <cassert>
#include "inc/Main.h"
namespace graphite2 {
struct IsoLangEntry
{
unsigned short mnLang;
char maLangStr[4];
char maCountry[3];
};
// Windows Language ID, Locale ISO-639 language, country code as used in
// naming table of OpenType fonts
const IsoLangEntry LANG_ENTRIES[] = {
{ 0x0401, "ar","SA" }, // Arabic Saudi Arabia
{ 0x0402, "bg","BG" }, // Bulgarian Bulgaria
{ 0x0403, "ca","ES" }, // Catalan Catalan
{ 0x0404, "zh","TW" }, // Chinese Taiwan
{ 0x0405, "cs","CZ" }, // Czech Czech Republic
{ 0x0406, "da","DK" }, // Danish Denmark
{ 0x0407, "de","DE" }, // German Germany
{ 0x0408, "el","GR" }, // Greek Greece
{ 0x0409, "en","US" }, // English United States
{ 0x040A, "es","ES" }, // Spanish (Traditional Sort) Spain
{ 0x040B, "fi","FI" }, // Finnish Finland
{ 0x040C, "fr","FR" }, // French France
{ 0x040D, "he","IL" }, // Hebrew Israel
{ 0x040E, "hu","HU" }, // Hungarian Hungary
{ 0x040F, "is","IS" }, // Icelandic Iceland
{ 0x0410, "it","IT" }, // Italian Italy
{ 0x0411, "jp","JP" }, // Japanese Japan
{ 0x0412, "ko","KR" }, // Korean Korea
{ 0x0413, "nl","NL" }, // Dutch Netherlands
{ 0x0414, "no","NO" }, // Norwegian (Bokmal) Norway
{ 0x0415, "pl","PL" }, // Polish Poland
{ 0x0416, "pt","BR" }, // Portuguese Brazil
{ 0x0417, "rm","CH" }, // Romansh Switzerland
{ 0x0418, "ro","RO" }, // Romanian Romania
{ 0x0419, "ru","RU" }, // Russian Russia
{ 0x041A, "hr","HR" }, // Croatian Croatia
{ 0x041B, "sk","SK" }, // Slovak Slovakia
{ 0x041C, "sq","AL" }, // Albanian Albania
{ 0x041D, "sv","SE" }, // Swedish Sweden
{ 0x041E, "th","TH" }, // Thai Thailand
{ 0x041F, "tr","TR" }, // Turkish Turkey
{ 0x0420, "ur","PK" }, // Urdu Islamic Republic of Pakistan
{ 0x0421, "id","ID" }, // Indonesian Indonesia
{ 0x0422, "uk","UA" }, // Ukrainian Ukraine
{ 0x0423, "be","BY" }, // Belarusian Belarus
{ 0x0424, "sl","SI" }, // Slovenian Slovenia
{ 0x0425, "et","EE" }, // Estonian Estonia
{ 0x0426, "lv","LV" }, // Latvian Latvia
{ 0x0427, "lt","LT" }, // Lithuanian Lithuania
{ 0x0428, "tg","TJ" }, // Tajik (Cyrillic) Tajikistan
{ 0x042A, "vi","VN" }, // Vietnamese Vietnam
{ 0x042B, "hy","AM" }, // Armenian Armenia
{ 0x042C, "az","AZ" }, // Azeri (Latin) Azerbaijan
{ 0x042D, "eu","" }, // Basque Basque
{ 0x042E, "hsb","DE" }, // Upper Sorbian Germany
{ 0x042F, "mk","MK" }, // Macedonian (FYROM) Former Yugoslav Republic of Macedonia
{ 0x0432, "tn","ZA" }, // Setswana South Africa
{ 0x0434, "xh","ZA" }, // isiXhosa South Africa
{ 0x0435, "zu","ZA" }, // isiZulu South Africa
{ 0x0436, "af","ZA" }, // Afrikaans South Africa
{ 0x0437, "ka","GE" }, // Georgian Georgia
{ 0x0438, "fo","FO" }, // Faroese Faroe Islands
{ 0x0439, "hi","IN" }, // Hindi India
{ 0x043A, "mt","MT" }, // Maltese Malta
{ 0x043B, "se","NO" }, // Sami (Northern) Norway
{ 0x043E, "ms","MY" }, // Malay Malaysia
{ 0x043F, "kk","KZ" }, // Kazakh Kazakhstan
{ 0x0440, "ky","KG" }, // Kyrgyz Kyrgyzstan
{ 0x0441, "sw","KE" }, // Kiswahili Kenya
{ 0x0442, "tk","TM" }, // Turkmen Turkmenistan
{ 0x0443, "uz","UZ" }, // Uzbek (Latin) Uzbekistan
{ 0x0444, "tt","RU" }, // Tatar Russia
{ 0x0445, "bn","IN" }, // Bengali India
{ 0x0446, "pa","IN" }, // Punjabi India
{ 0x0447, "gu","IN" }, // Gujarati India
{ 0x0448, "or","IN" }, // Oriya India
{ 0x0448, "wo","SN" }, // Wolof Senegal
{ 0x0449, "ta","IN" }, // Tamil India
{ 0x044A, "te","IN" }, // Telugu India
{ 0x044B, "kn","IN" }, // Kannada India
{ 0x044C, "ml","IN" }, // Malayalam India
{ 0x044D, "as","IN" }, // Assamese India
{ 0x044E, "mr","IN" }, // Marathi India
{ 0x044F, "sa","IN" }, // Sanskrit India
{ 0x0450, "mn","MN" }, // Mongolian (Cyrillic) Mongolia
{ 0x0451, "bo","CN" }, // Tibetan PRC
{ 0x0452, "cy","GB" }, // Welsh United Kingdom
{ 0x0453, "km","KH" }, // Khmer Cambodia
{ 0x0454, "lo","LA" }, // Lao Lao P.D.R.
{ 0x0455, "my","MM" }, // Burmese Myanmar - not listed in Microsoft docs anymore
{ 0x0456, "gl","ES" }, // Galician Galician
{ 0x0457, "kok","IN" }, // Konkani India
{ 0x045A, "syr","TR" }, // Syriac Syria
{ 0x045B, "si","LK" }, // Sinhala Sri Lanka
{ 0x045D, "iu","CA" }, // Inuktitut Canada
{ 0x045E, "am","ET" }, // Amharic Ethiopia
{ 0x0461, "ne","NP" }, // Nepali Nepal
{ 0x0462, "fy","NL" }, // Frisian Netherlands
{ 0x0463, "ps","AF" }, // Pashto Afghanistan
{ 0x0464, "fil","PH" }, // Filipino Philippines
{ 0x0465, "dv","MV" }, // Divehi Maldives
{ 0x0468, "ha","NG" }, // Hausa (Latin) Nigeria
{ 0x046A, "yo","NG" }, // Yoruba Nigeria
{ 0x046B, "qu","BO" }, // Quechua Bolivia
{ 0x046C, "st","ZA" }, // Sesotho sa Leboa South Africa
{ 0x046D, "ba","RU" }, // Bashkir Russia
{ 0x046E, "lb","LU" }, // Luxembourgish Luxembourg
{ 0x046F, "kl","GL" }, // Greenlandic Greenland
{ 0x0470, "ig","NG" }, // Igbo Nigeria
{ 0x0478, "ii","CN" }, // Yi PRC
{ 0x047A, "arn","CL" }, // Mapudungun Chile
{ 0x047C, "moh","CA" }, // Mohawk Mohawk
{ 0x047E, "br","FR" }, // Breton France
{ 0x0480, "ug","CN" }, // Uighur PRC
{ 0x0481, "mi","NZ" }, // Maori New Zealand
{ 0x0482, "oc","FR" }, // Occitan France
{ 0x0483, "co","FR" }, // Corsican France
{ 0x0484, "gsw","FR" }, // Alsatian France
{ 0x0485, "sah","RU" }, // Yakut Russia
{ 0x0486, "qut","GT" }, // K'iche Guatemala
{ 0x0487, "rw","RW" }, // Kinyarwanda Rwanda
{ 0x048C, "gbz","AF" }, // Dari Afghanistan
{ 0x0801, "ar","IQ" }, // Arabic Iraq
{ 0x0804, "zn","CH" }, // Chinese People's Republic of China
{ 0x0807, "de","CH" }, // German Switzerland
{ 0x0809, "en","GB" }, // English United Kingdom
{ 0x080A, "es","MX" }, // Spanish Mexico
{ 0x080C, "fr","BE" }, // French Belgium
{ 0x0810, "it","CH" }, // Italian Switzerland
{ 0x0813, "nl","BE" }, // Dutch Belgium
{ 0x0814, "nn","NO" }, // Norwegian (Nynorsk) Norway
{ 0x0816, "pt","PT" }, // Portuguese Portugal
{ 0x081A, "sh","RS" }, // Serbian (Latin) Serbia
{ 0x081D, "sv","FI" }, // Sweden Finland
{ 0x082C, "az","AZ" }, // Azeri (Cyrillic) Azerbaijan
{ 0x082E, "dsb","DE" }, // Lower Sorbian Germany
{ 0x083B, "se","SE" }, // Sami (Northern) Sweden
{ 0x083C, "ga","IE" }, // Irish Ireland
{ 0x083E, "ms","BN" }, // Malay Brunei Darussalam
{ 0x0843, "uz","UZ" }, // Uzbek (Cyrillic) Uzbekistan
{ 0x0845, "bn","BD" }, // Bengali Bangladesh
{ 0x0850, "mn","MN" }, // Mongolian (Traditional) People's Republic of China
{ 0x085D, "iu","CA" }, // Inuktitut (Latin) Canada
{ 0x085F, "ber","DZ" }, // Tamazight (Latin) Algeria
{ 0x086B, "es","EC" }, // Quechua Ecuador
{ 0x0C01, "ar","EG" }, // Arabic Egypt
{ 0x0C04, "zh","HK" }, // Chinese Hong Kong S.A.R.
{ 0x0C07, "de","AT" }, // German Austria
{ 0x0C09, "en","AU" }, // English Australia
{ 0x0C0A, "es","ES" }, // Spanish (Modern Sort) Spain
{ 0x0C0C, "fr","CA" }, // French Canada
{ 0x0C1A, "sr","CS" }, // Serbian (Cyrillic) Serbia
{ 0x0C3B, "se","FI" }, // Sami (Northern) Finland
{ 0x0C6B, "qu","PE" }, // Quechua Peru
{ 0x1001, "ar","LY" }, // Arabic Libya
{ 0x1004, "zh","SG" }, // Chinese Singapore
{ 0x1007, "de","LU" }, // German Luxembourg
{ 0x1009, "en","CA" }, // English Canada
{ 0x100A, "es","GT" }, // Spanish Guatemala
{ 0x100C, "fr","CH" }, // French Switzerland
{ 0x101A, "hr","BA" }, // Croatian (Latin) Bosnia and Herzegovina
{ 0x103B, "smj","NO" }, // Sami (Lule) Norway
{ 0x1401, "ar","DZ" }, // Arabic Algeria
{ 0x1404, "zh","MO" }, // Chinese Macao S.A.R.
{ 0x1407, "de","LI" }, // German Liechtenstein
{ 0x1409, "en","NZ" }, // English New Zealand
{ 0x140A, "es","CR" }, // Spanish Costa Rica
{ 0x140C, "fr","LU" }, // French Luxembourg
{ 0x141A, "bs","BA" }, // Bosnian (Latin) Bosnia and Herzegovina
{ 0x143B, "smj","SE" }, // Sami (Lule) Sweden
{ 0x1801, "ar","MA" }, // Arabic Morocco
{ 0x1809, "en","IE" }, // English Ireland
{ 0x180A, "es","PA" }, // Spanish Panama
{ 0x180C, "fr","MC" }, // French Principality of Monoco
{ 0x181A, "sh","BA" }, // Serbian (Latin) Bosnia and Herzegovina
{ 0x183B, "sma","NO" }, // Sami (Southern) Norway
{ 0x1C01, "ar","TN" }, // Arabic Tunisia
{ 0x1C09, "en","ZA" }, // English South Africa
{ 0x1C0A, "es","DO" }, // Spanish Dominican Republic
{ 0x1C1A, "sr","BA" }, // Serbian (Cyrillic) Bosnia and Herzegovina
{ 0x1C3B, "sma","SE" }, // Sami (Southern) Sweden
{ 0x2001, "ar","OM" }, // Arabic Oman
{ 0x2009, "en","JM" }, // English Jamaica
{ 0x200A, "es","VE" }, // Spanish Venezuela
{ 0x201A, "bs","BA" }, // Bosnian (Cyrillic) Bosnia and Herzegovina
{ 0x203B, "sms","FI" }, // Sami (Skolt) Finland
{ 0x2401, "ar","YE" }, // Arabic Yemen
{ 0x2409, "en","BS" }, // English Caribbean
{ 0x240A, "es","CO" }, // Spanish Colombia
{ 0x243B, "smn","FI" }, // Sami (Inari) Finland
{ 0x2801, "ar","SY" }, // Arabic Syria
{ 0x2809, "en","BZ" }, // English Belize
{ 0x280A, "es","PE" }, // Spanish Peru
{ 0x2C01, "ar","JO" }, // Arabic Jordan
{ 0x2C09, "en","TT" }, // English Trinidad and Tobago
{ 0x2C0A, "es","AR" }, // Spanish Argentina
{ 0x3001, "ar","LB" }, // Arabic Lebanon
{ 0x3009, "en","ZW" }, // English Zimbabwe
{ 0x300A, "es","EC" }, // Spanish Ecuador
{ 0x3401, "ar","KW" }, // Arabic Kuwait
{ 0x3409, "en","PH" }, // English Republic of the Philippines
{ 0x340A, "es","CL" }, // Spanish Chile
{ 0x3801, "ar","AE" }, // Arabic U.A.E.
{ 0x380A, "es","UY" }, // Spanish Uruguay
{ 0x3C01, "ar","BH" }, // Arabic Bahrain
{ 0x3C0A, "es","PY" }, // Spanish Paraguay
{ 0x4001, "ar","QA" }, // Arabic Qatar
{ 0x4009, "en","IN" }, // English India
{ 0x400A, "es","BO" }, // Spanish Bolivia
{ 0x4409, "en","MY" }, // English Malaysia
{ 0x440A, "es","SV" }, // Spanish El Salvador
{ 0x4809, "en","SG" }, // English Singapore
{ 0x480A, "es","HN" }, // Spanish Honduras
{ 0x4C0A, "es","NI" }, // Spanish Nicaragua
{ 0x500A, "es","PR" }, // Spanish Puerto Rico
{ 0x540A, "es","US" } // Spanish United States
};
class Locale2Lang
{
Locale2Lang(const Locale2Lang &);
Locale2Lang & operator = (const Locale2Lang &);
public:
Locale2Lang() : mSeedPosition(128)
{
memset((void*)mLangLookup, 0, sizeof(mLangLookup));
// create a tri lookup on first 2 letters of language code
static const int maxIndex = sizeof(LANG_ENTRIES)/sizeof(IsoLangEntry);
for (int i = 0; i < maxIndex; i++)
{
size_t a = LANG_ENTRIES[i].maLangStr[0] - 'a';
size_t b = LANG_ENTRIES[i].maLangStr[1] - 'a';
if (mLangLookup[a][b])
{
const IsoLangEntry ** old = mLangLookup[a][b];
int len = 1;
while (old[len]) len++;
len += 2;
mLangLookup[a][b] = gralloc<const IsoLangEntry *>(len);
if (!mLangLookup[a][b])
{
mLangLookup[a][b] = old;
continue;
}
mLangLookup[a][b][--len] = NULL;
mLangLookup[a][b][--len] = &LANG_ENTRIES[i];
while (--len >= 0)
{
assert(len >= 0);
mLangLookup[a][b][len] = old[len];
}
free(old);
}
else
{
mLangLookup[a][b] = gralloc<const IsoLangEntry *>(2);
if (!mLangLookup[a][b]) continue;
mLangLookup[a][b][1] = NULL;
mLangLookup[a][b][0] = &LANG_ENTRIES[i];
}
}
while (2 * mSeedPosition < maxIndex)
mSeedPosition *= 2;
};
~Locale2Lang()
{
for (int i = 0; i != 26; ++i)
for (int j = 0; j != 26; ++j)
free(mLangLookup[i][j]);
}
unsigned short getMsId(const char * locale) const
{
size_t length = strlen(locale);
size_t langLength = length;
const char * language = locale;
const char * script = NULL;
const char * region = NULL;
size_t regionLength = 0;
const char * dash = strchr(locale, '-');
if (dash && (dash != locale))
{
langLength = (dash - locale);
size_t nextPartLength = length - langLength - 1;
if (nextPartLength >= 2)
{
script = ++dash;
dash = strchr(dash, '-');
if (dash)
{
nextPartLength = (dash - script);
region = ++dash;
}
if (nextPartLength == 2 &&
(locale[langLength+1] > 0x40) && (locale[langLength+1] < 0x5B) &&
(locale[langLength+2] > 0x40) && (locale[langLength+2] < 0x5B))
{
region = script;
regionLength = nextPartLength;
script = NULL;
}
else if (nextPartLength == 4)
{
if (dash)
{
dash = strchr(dash, '-');
if (dash)
{
nextPartLength = (dash - region);
}
else
{
nextPartLength = langLength - (region - locale);
}
regionLength = nextPartLength;
}
}
}
}
size_t a = 'e' - 'a';
size_t b = 'n' - 'a';
unsigned short langId = 0;
int i = 0;
switch (langLength)
{
case 2:
{
a = language[0] - 'a';
b = language[1] - 'a';
if ((a < 26) && (b < 26) && mLangLookup[a][b])
{
while (mLangLookup[a][b][i])
{
if (mLangLookup[a][b][i]->maLangStr[2] != '\0')
{
++i;
continue;
}
if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0))
{
langId = mLangLookup[a][b][i]->mnLang;
break;
}
else if (langId == 0)
{
// possible fallback code
langId = mLangLookup[a][b][i]->mnLang;
}
++i;
}
}
}
break;
case 3:
{
a = language[0] - 'a';
b = language[1] - 'a';
if (mLangLookup[a][b])
{
while (mLangLookup[a][b][i])
{
if (mLangLookup[a][b][i]->maLangStr[2] != language[2])
{
++i;
continue;
}
if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0))
{
langId = mLangLookup[a][b][i]->mnLang;
break;
}
else if (langId == 0)
{
// possible fallback code
langId = mLangLookup[a][b][i]->mnLang;
}
++i;
}
}
}
break;
default:
break;
}
if (langId == 0) langId = 0x409;
return langId;
}
const IsoLangEntry * findEntryById(unsigned short langId) const
{
static const int maxIndex = sizeof(LANG_ENTRIES)/sizeof(IsoLangEntry);
int window = mSeedPosition;
int guess = mSeedPosition - 1;
while (LANG_ENTRIES[guess].mnLang != langId)
{
window /= 2;
if (window == 0) return NULL;
guess += (LANG_ENTRIES[guess].mnLang > langId)? -window : window;
while (guess >= maxIndex)
{
window /= 2;
guess -= window;
assert(window);
}
}
return &LANG_ENTRIES[guess];
}
CLASS_NEW_DELETE;
private:
const IsoLangEntry ** mLangLookup[26][26];
int mSeedPosition;
};
} // namespace graphite2

View File

@ -0,0 +1,124 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// This file will be pulled into and integrated into a machine implmentation
// DO NOT build directly
#pragma once
#define do2(n) do_(n) ,do_(n)
#define NILOP 0U
// types or parameters are: (.. is inclusive)
// number - any byte
// output_class - 0 .. silf.m_nClass
// input_class - 0 .. silf.m_nClass
// sattrnum - 0 .. 29 (gr_slatJWidth) , 55 (gr_slatUserDefn)
// attrid - 0 .. silf.numUser() where sattrnum == 55; 0..silf.m_iMaxComp where sattrnum == 15 otherwise 0
// gattrnum - 0 .. face->getGlyphFaceCache->numAttrs()
// gmetric - 0 .. 11 (kgmetDescent)
// featidx - 0 .. face.numFeatures()
// level - any byte
static const opcode_t opcode_table[] =
{
{{do2(nop)}, 0, "NOP"},
{{do2(push_byte)}, 1, "PUSH_BYTE"}, // number
{{do2(push_byte_u)}, 1, "PUSH_BYTE_U"}, // number
{{do2(push_short)}, 2, "PUSH_SHORT"}, // number number
{{do2(push_short_u)}, 2, "PUSH_SHORT_U"}, // number number
{{do2(push_long)}, 4, "PUSH_LONG"}, // number number number number
{{do2(add)}, 0, "ADD"},
{{do2(sub)}, 0, "SUB"},
{{do2(mul)}, 0, "MUL"},
{{do2(div_)}, 0, "DIV"},
{{do2(min_)}, 0, "MIN"},
{{do2(max_)}, 0, "MAX"},
{{do2(neg)}, 0, "NEG"},
{{do2(trunc8)}, 0, "TRUNC8"},
{{do2(trunc16)}, 0, "TRUNC16"},
{{do2(cond)}, 0, "COND"},
{{do2(and_)}, 0, "AND"}, // 0x10
{{do2(or_)}, 0, "OR"},
{{do2(not_)}, 0, "NOT"},
{{do2(equal)}, 0, "EQUAL"},
{{do2(not_eq_)}, 0, "NOT_EQ"},
{{do2(less)}, 0, "LESS"},
{{do2(gtr)}, 0, "GTR"},
{{do2(less_eq)}, 0, "LESS_EQ"},
{{do2(gtr_eq)}, 0, "GTR_EQ"}, // 0x18
{{do_(next), NILOP}, 0, "NEXT"},
{{NILOP, NILOP}, 1, "NEXT_N"}, // number <= smap.end - map
{{do_(next), NILOP}, 0, "COPY_NEXT"},
{{do_(put_glyph_8bit_obs), NILOP}, 1, "PUT_GLYPH_8BIT_OBS"}, // output_class
{{do_(put_subs_8bit_obs), NILOP}, 3, "PUT_SUBS_8BIT_OBS"}, // slot input_class output_class
{{do_(put_copy), NILOP}, 1, "PUT_COPY"}, // slot
{{do_(insert), NILOP}, 0, "INSERT"},
{{do_(delete_), NILOP}, 0, "DELETE"}, // 0x20
{{do_(assoc), NILOP}, VARARGS, "ASSOC"},
{{NILOP ,do_(cntxt_item)}, 2, "CNTXT_ITEM"}, // slot offset
{{do_(attr_set), NILOP}, 1, "ATTR_SET"}, // sattrnum
{{do_(attr_add), NILOP}, 1, "ATTR_ADD"}, // sattrnum
{{do_(attr_sub), NILOP}, 1, "ATTR_SUB"}, // sattrnum
{{do_(attr_set_slot), NILOP}, 1, "ATTR_SET_SLOT"}, // sattrnum
{{do_(iattr_set_slot), NILOP}, 2, "IATTR_SET_SLOT"}, // sattrnum attrid
{{do2(push_slot_attr)}, 2, "PUSH_SLOT_ATTR"}, // sattrnum slot
{{do2(push_glyph_attr_obs)}, 2, "PUSH_GLYPH_ATTR_OBS"}, // gattrnum slot
{{do2(push_glyph_metric)}, 3, "PUSH_GLYPH_METRIC"}, // gmetric slot level
{{do2(push_feat)}, 2, "PUSH_FEAT"}, // featidx slot
{{do2(push_att_to_gattr_obs)}, 2, "PUSH_ATT_TO_GATTR_OBS"}, // gattrnum slot
{{do2(push_att_to_glyph_metric)}, 3, "PUSH_ATT_TO_GLYPH_METRIC"}, // gmetric slot level
{{do2(push_islot_attr)}, 3, "PUSH_ISLOT_ATTR"}, // sattrnum slot attrid
{{NILOP,NILOP}, 3, "PUSH_IGLYPH_ATTR"},
{{do2(pop_ret)}, 0, "POP_RET"}, // 0x30
{{do2(ret_zero)}, 0, "RET_ZERO"},
{{do2(ret_true)}, 0, "RET_TRUE"},
{{do_(iattr_set), NILOP}, 2, "IATTR_SET"}, // sattrnum attrid
{{do_(iattr_add), NILOP}, 2, "IATTR_ADD"}, // sattrnum attrid
{{do_(iattr_sub), NILOP}, 2, "IATTR_SUB"}, // sattrnum attrid
{{do2(push_proc_state)}, 1, "PUSH_PROC_STATE"}, // dummy
{{do2(push_version)}, 0, "PUSH_VERSION"},
{{do_(put_subs), NILOP}, 5, "PUT_SUBS"}, // slot input_class input_class output_class output_class
{{NILOP,NILOP}, 0, "PUT_SUBS2"},
{{NILOP,NILOP}, 0, "PUT_SUBS3"},
{{do_(put_glyph), NILOP}, 2, "PUT_GLYPH"}, // output_class output_class
{{do2(push_glyph_attr)}, 3, "PUSH_GLYPH_ATTR"}, // gattrnum gattrnum slot
{{do2(push_att_to_glyph_attr)}, 3, "PUSH_ATT_TO_GLYPH_ATTR"}, // gattrnum gattrnum slot
{{do2(bor)}, 0, "BITOR"},
{{do2(band)}, 0, "BITAND"},
{{do2(bnot)}, 0, "BITNOT"}, // 0x40
{{do2(setbits)}, 4, "BITSET"},
{{do_(set_feat), NILOP}, 2, "SET_FEAT"}, // featidx slot
// private opcodes for internal use only, comes after all other on disk opcodes.
{{do_(temp_copy), NILOP}, 0, "TEMP_COPY"}
};

691
thirdparty/graphite/src/inc/opcodes.h vendored Normal file
View File

@ -0,0 +1,691 @@
/* GRAPHITE2 LICENSING
Copyright 2010, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
// This file will be pulled into and integrated into a machine implmentation
// DO NOT build directly and under no circumstances ever #include headers in
// here or you will break the direct_machine.
//
// Implementers' notes
// ==================
// You have access to a few primitives and the full C++ code:
// declare_params(n) Tells the interpreter how many bytes of parameter
// space to claim for this instruction uses and
// initialises the param pointer. You *must* before the
// first use of param.
// use_params(n) Claim n extra bytes of param space beyond what was
// claimed using delcare_param.
// param A const byte pointer for the parameter space claimed by
// this instruction.
// binop(op) Implement a binary operation on the stack using the
// specified C++ operator.
// NOT_IMPLEMENTED Any instruction body containing this will exit the
// program with an assertion error. Instructions that are
// not implemented should also be marked NILOP in the
// opcodes tables this will cause the code class to spot
// them in a live code stream and throw a runtime_error
// instead.
// push(n) Push the value n onto the stack.
// pop() Pop the top most value and return it.
//
// You have access to the following named fast 'registers':
// sp = The pointer to the current top of stack, the last value
// pushed.
// seg = A reference to the Segment this code is running over.
// is = The current slot index
// isb = The original base slot index at the start of this rule
// isf = The first positioned slot
// isl = The last positioned slot
// ip = The current instruction pointer
// endPos = Position of advance of last cluster
// dir = writing system directionality of the font
// #define NOT_IMPLEMENTED assert(false)
// #define NOT_IMPLEMENTED
#define binop(op) const uint32 a = pop(); *sp = uint32(*sp) op a
#define sbinop(op) const int32 a = pop(); *sp = int32(*sp) op a
#define use_params(n) dp += n
#define declare_params(n) const byte * param = dp; \
use_params(n);
#define push(n) { *++sp = n; }
#define pop() (*sp--)
#define slotat(x) (map[(x)])
#define DIE { is=seg.last(); status = Machine::died_early; EXIT(1); }
#define POSITIONED 1
STARTOP(nop)
do {} while (0);
ENDOP
STARTOP(push_byte)
declare_params(1);
push(int8(*param));
ENDOP
STARTOP(push_byte_u)
declare_params(1);
push(uint8(*param));
ENDOP
STARTOP(push_short)
declare_params(2);
const int16 r = int16(param[0]) << 8
| uint8(param[1]);
push(r);
ENDOP
STARTOP(push_short_u)
declare_params(2);
const uint16 r = uint16(param[0]) << 8
| uint8(param[1]);
push(r);
ENDOP
STARTOP(push_long)
declare_params(4);
const int32 r = int32(param[0]) << 24
| uint32(param[1]) << 16
| uint32(param[2]) << 8
| uint8(param[3]);
push(r);
ENDOP
STARTOP(add)
binop(+);
ENDOP
STARTOP(sub)
binop(-);
ENDOP
STARTOP(mul)
binop(*);
ENDOP
STARTOP(div_)
const int32 b = pop();
const int32 a = int32(*sp);
if (b == 0 || (a == std::numeric_limits<int32>::min() && b == -1)) DIE;
*sp = int32(*sp) / b;
ENDOP
STARTOP(min_)
const int32 a = pop(), b = *sp;
if (a < b) *sp = a;
ENDOP
STARTOP(max_)
const int32 a = pop(), b = *sp;
if (a > b) *sp = a;
ENDOP
STARTOP(neg)
*sp = uint32(-int32(*sp));
ENDOP
STARTOP(trunc8)
*sp = uint8(*sp);
ENDOP
STARTOP(trunc16)
*sp = uint16(*sp);
ENDOP
STARTOP(cond)
const uint32 f = pop(), t = pop(), c = pop();
push(c ? t : f);
ENDOP
STARTOP(and_)
binop(&&);
ENDOP
STARTOP(or_)
binop(||);
ENDOP
STARTOP(not_)
*sp = !*sp;
ENDOP
STARTOP(equal)
binop(==);
ENDOP
STARTOP(not_eq_)
binop(!=);
ENDOP
STARTOP(less)
sbinop(<);
ENDOP
STARTOP(gtr)
sbinop(>);
ENDOP
STARTOP(less_eq)
sbinop(<=);
ENDOP
STARTOP(gtr_eq)
sbinop(>=);
ENDOP
STARTOP(next)
if (map - &smap[0] >= int(smap.size())) DIE
if (is)
{
if (is == smap.highwater())
smap.highpassed(true);
is = is->next();
}
++map;
ENDOP
//STARTOP(next_n)
// use_params(1);
// NOT_IMPLEMENTED;
//declare_params(1);
//const size_t num = uint8(*param);
//ENDOP
//STARTOP(copy_next)
// if (is) is = is->next();
// ++map;
// ENDOP
STARTOP(put_glyph_8bit_obs)
declare_params(1);
const unsigned int output_class = uint8(*param);
is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
ENDOP
STARTOP(put_subs_8bit_obs)
declare_params(3);
const int slot_ref = int8(param[0]);
const unsigned int input_class = uint8(param[1]),
output_class = uint8(param[2]);
uint16 index;
slotref slot = slotat(slot_ref);
if (slot)
{
index = seg.findClassIndex(input_class, slot->gid());
is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
}
ENDOP
STARTOP(put_copy)
declare_params(1);
const int slot_ref = int8(*param);
if (is && !is->isDeleted())
{
slotref ref = slotat(slot_ref);
if (ref && ref != is)
{
int16 *tempUserAttrs = is->userAttrs();
if (is->attachedTo() || is->firstChild()) DIE
Slot *prev = is->prev();
Slot *next = is->next();
memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
memcpy(is, ref, sizeof(Slot));
is->firstChild(NULL);
is->nextSibling(NULL);
is->userAttrs(tempUserAttrs);
is->next(next);
is->prev(prev);
if (is->attachedTo())
is->attachedTo()->child(is);
}
is->markCopied(false);
is->markDeleted(false);
}
ENDOP
STARTOP(insert)
if (smap.decMax() <= 0) DIE;
Slot *newSlot = seg.newSlot();
if (!newSlot) DIE;
Slot *iss = is;
while (iss && iss->isDeleted()) iss = iss->next();
if (!iss)
{
if (seg.last())
{
seg.last()->next(newSlot);
newSlot->prev(seg.last());
newSlot->before(seg.last()->before());
seg.last(newSlot);
}
else
{
seg.first(newSlot);
seg.last(newSlot);
}
}
else if (iss->prev())
{
iss->prev()->next(newSlot);
newSlot->prev(iss->prev());
newSlot->before(iss->prev()->after());
}
else
{
newSlot->prev(NULL);
newSlot->before(iss->before());
seg.first(newSlot);
}
newSlot->next(iss);
if (iss)
{
iss->prev(newSlot);
newSlot->originate(iss->original());
newSlot->after(iss->before());
}
else if (newSlot->prev())
{
newSlot->originate(newSlot->prev()->original());
newSlot->after(newSlot->prev()->after());
}
else
{
newSlot->originate(seg.defaultOriginal());
}
if (is == smap.highwater())
smap.highpassed(false);
is = newSlot;
seg.extendLength(1);
if (map != &smap[-1])
--map;
ENDOP
STARTOP(delete_)
if (!is || is->isDeleted()) DIE
is->markDeleted(true);
if (is->prev())
is->prev()->next(is->next());
else
seg.first(is->next());
if (is->next())
is->next()->prev(is->prev());
else
seg.last(is->prev());
if (is == smap.highwater())
smap.highwater(is->next());
if (is->prev())
is = is->prev();
seg.extendLength(-1);
ENDOP
STARTOP(assoc)
declare_params(1);
unsigned int num = uint8(*param);
const int8 * assocs = reinterpret_cast<const int8 *>(param+1);
use_params(num);
int max = -1;
int min = -1;
while (num-- > 0)
{
int sr = *assocs++;
slotref ts = slotat(sr);
if (ts && (min == -1 || ts->before() < min)) min = ts->before();
if (ts && ts->after() > max) max = ts->after();
}
if (min > -1) // implies max > -1
{
is->before(min);
is->after(max);
}
ENDOP
STARTOP(cntxt_item)
// It turns out this is a cunningly disguised condition forward jump.
declare_params(3);
const int is_arg = int8(param[0]);
const size_t iskip = uint8(param[1]),
dskip = uint8(param[2]);
if (mapb + is_arg != map)
{
ip += iskip;
dp += dskip;
push(true);
}
ENDOP
STARTOP(attr_set)
declare_params(1);
const attrCode slat = attrCode(uint8(*param));
const int val = pop();
is->setAttr(&seg, slat, 0, val, smap);
ENDOP
STARTOP(attr_add)
declare_params(1);
const attrCode slat = attrCode(uint8(*param));
const uint32_t val = pop();
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
uint32_t res = uint32_t(is->getAttr(&seg, slat, 0));
is->setAttr(&seg, slat, 0, int32_t(val + res), smap);
ENDOP
STARTOP(attr_sub)
declare_params(1);
const attrCode slat = attrCode(uint8(*param));
const uint32_t val = pop();
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
uint32_t res = uint32_t(is->getAttr(&seg, slat, 0));
is->setAttr(&seg, slat, 0, int32_t(res - val), smap);
ENDOP
STARTOP(attr_set_slot)
declare_params(1);
const attrCode slat = attrCode(uint8(*param));
const int offset = int(map - smap.begin())*int(slat == gr_slatAttTo);
const int val = pop() + offset;
is->setAttr(&seg, slat, offset, val, smap);
ENDOP
STARTOP(iattr_set_slot)
declare_params(2);
const attrCode slat = attrCode(uint8(param[0]));
const uint8 idx = uint8(param[1]);
const int val = int(pop() + (map - smap.begin())*int(slat == gr_slatAttTo));
is->setAttr(&seg, slat, idx, val, smap);
ENDOP
STARTOP(push_slot_attr)
declare_params(2);
const attrCode slat = attrCode(uint8(param[0]));
const int slot_ref = int8(param[1]);
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
if (slot)
{
int res = slot->getAttr(&seg, slat, 0);
push(res);
}
ENDOP
STARTOP(push_glyph_attr_obs)
declare_params(2);
const unsigned int glyph_attr = uint8(param[0]);
const int slot_ref = int8(param[1]);
slotref slot = slotat(slot_ref);
if (slot)
push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
ENDOP
STARTOP(push_glyph_metric)
declare_params(3);
const unsigned int glyph_attr = uint8(param[0]);
const int slot_ref = int8(param[1]);
const signed int attr_level = uint8(param[2]);
slotref slot = slotat(slot_ref);
if (slot)
push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir));
ENDOP
STARTOP(push_feat)
declare_params(2);
const unsigned int feat = uint8(param[0]);
const int slot_ref = int8(param[1]);
slotref slot = slotat(slot_ref);
if (slot)
{
uint8 fid = seg.charinfo(slot->original())->fid();
push(seg.getFeature(fid, feat));
}
ENDOP
STARTOP(push_att_to_gattr_obs)
declare_params(2);
const unsigned int glyph_attr = uint8(param[0]);
const int slot_ref = int8(param[1]);
slotref slot = slotat(slot_ref);
if (slot)
{
slotref att = slot->attachedTo();
if (att) slot = att;
push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
}
ENDOP
STARTOP(push_att_to_glyph_metric)
declare_params(3);
const unsigned int glyph_attr = uint8(param[0]);
const int slot_ref = int8(param[1]);
const signed int attr_level = uint8(param[2]);
slotref slot = slotat(slot_ref);
if (slot)
{
slotref att = slot->attachedTo();
if (att) slot = att;
push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)));
}
ENDOP
STARTOP(push_islot_attr)
declare_params(3);
const attrCode slat = attrCode(uint8(param[0]));
const int slot_ref = int8(param[1]),
idx = uint8(param[2]);
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
if (slot)
{
int res = slot->getAttr(&seg, slat, idx);
push(res);
}
ENDOP
#if 0
STARTOP(push_iglyph_attr) // not implemented
NOT_IMPLEMENTED;
ENDOP
#endif
STARTOP(pop_ret)
const uint32 ret = pop();
EXIT(ret);
ENDOP
STARTOP(ret_zero)
EXIT(0);
ENDOP
STARTOP(ret_true)
EXIT(1);
ENDOP
STARTOP(iattr_set)
declare_params(2);
const attrCode slat = attrCode(uint8(param[0]));
const uint8 idx = uint8(param[1]);
const int val = pop();
is->setAttr(&seg, slat, idx, val, smap);
ENDOP
STARTOP(iattr_add)
declare_params(2);
const attrCode slat = attrCode(uint8(param[0]));
const uint8 idx = uint8(param[1]);
const uint32_t val = pop();
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
uint32_t res = uint32_t(is->getAttr(&seg, slat, idx));
is->setAttr(&seg, slat, idx, int32_t(val + res), smap);
ENDOP
STARTOP(iattr_sub)
declare_params(2);
const attrCode slat = attrCode(uint8(param[0]));
const uint8 idx = uint8(param[1]);
const uint32_t val = pop();
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
flags |= POSITIONED;
}
uint32_t res = uint32_t(is->getAttr(&seg, slat, idx));
is->setAttr(&seg, slat, idx, int32_t(res - val), smap);
ENDOP
STARTOP(push_proc_state)
use_params(1);
push(1);
ENDOP
STARTOP(push_version)
push(0x00030000);
ENDOP
STARTOP(put_subs)
declare_params(5);
const int slot_ref = int8(param[0]);
const unsigned int input_class = uint8(param[1]) << 8
| uint8(param[2]);
const unsigned int output_class = uint8(param[3]) << 8
| uint8(param[4]);
slotref slot = slotat(slot_ref);
if (slot)
{
int index = seg.findClassIndex(input_class, slot->gid());
is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
}
ENDOP
#if 0
STARTOP(put_subs2) // not implemented
NOT_IMPLEMENTED;
ENDOP
STARTOP(put_subs3) // not implemented
NOT_IMPLEMENTED;
ENDOP
#endif
STARTOP(put_glyph)
declare_params(2);
const unsigned int output_class = uint8(param[0]) << 8
| uint8(param[1]);
is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
ENDOP
STARTOP(push_glyph_attr)
declare_params(3);
const unsigned int glyph_attr = uint8(param[0]) << 8
| uint8(param[1]);
const int slot_ref = int8(param[2]);
slotref slot = slotat(slot_ref);
if (slot)
push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
ENDOP
STARTOP(push_att_to_glyph_attr)
declare_params(3);
const unsigned int glyph_attr = uint8(param[0]) << 8
| uint8(param[1]);
const int slot_ref = int8(param[2]);
slotref slot = slotat(slot_ref);
if (slot)
{
slotref att = slot->attachedTo();
if (att) slot = att;
push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
}
ENDOP
STARTOP(temp_copy)
slotref newSlot = seg.newSlot();
if (!newSlot || !is) DIE;
int16 *tempUserAttrs = newSlot->userAttrs();
memcpy(newSlot, is, sizeof(Slot));
memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
newSlot->userAttrs(tempUserAttrs);
newSlot->markCopied(true);
*map = newSlot;
ENDOP
STARTOP(band)
binop(&);
ENDOP
STARTOP(bor)
binop(|);
ENDOP
STARTOP(bnot)
*sp = ~*sp;
ENDOP
STARTOP(setbits)
declare_params(4);
const uint16 m = uint16(param[0]) << 8
| uint8(param[1]);
const uint16 v = uint16(param[2]) << 8
| uint8(param[3]);
*sp = ((*sp) & ~m) | v;
ENDOP
STARTOP(set_feat)
declare_params(2);
const unsigned int feat = uint8(param[0]);
const int slot_ref = int8(param[1]);
slotref slot = slotat(slot_ref);
if (slot)
{
uint8 fid = seg.charinfo(slot->original())->fid();
seg.setFeature(fid, feat, pop());
}
ENDOP

147
thirdparty/graphite/src/json.cpp vendored Normal file
View File

@ -0,0 +1,147 @@
/* GRAPHITE2 LICENSING
Copyright 2011, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
// JSON debug logging
// Author: Tim Eves
#if !defined GRAPHITE2_NTRACING
#include <cstdio>
#include <limits>
#include "inc/json.h"
#if defined(_MSC_VER)
#define FORMAT_INTMAX "%lli"
#define FORMAT_UINTMAX "%llu"
#else
#define FORMAT_INTMAX "%ji"
#define FORMAT_UINTMAX "%ju"
#endif
using namespace graphite2;
namespace
{
enum
{
seq = ',',
obj='}', member=':', empty_obj='{',
arr=']', empty_arr='['
};
}
const std::nullptr_t json::null = nullptr;
inline
void json::context(const char current) throw()
{
fprintf(_stream, "%c", *_context);
indent();
*_context = current;
}
void json::indent(const int d) throw()
{
if (*_context == member || (_flatten && _flatten < _context))
fputc(' ', _stream);
else
fprintf(_stream, "\n%*s", 4*int(_context - _contexts + d), "");
}
inline
void json::push_context(const char prefix, const char suffix) throw()
{
assert(_context - _contexts < ptrdiff_t(sizeof _contexts));
if (_context == _contexts)
*_context = suffix;
else
context(suffix);
*++_context = prefix;
}
void json::pop_context() throw()
{
assert(_context > _contexts);
if (*_context == seq) indent(-1);
else fputc(*_context, _stream);
fputc(*--_context, _stream);
if (_context == _contexts) fputc('\n', _stream);
fflush(_stream);
if (_flatten >= _context) _flatten = 0;
*_context = seq;
}
// These four functions cannot be inlined as pointers to these
// functions are needed for operator << (_context_t) to work.
void json::flat(json & j) throw() { if (!j._flatten) j._flatten = j._context; }
void json::close(json & j) throw() { j.pop_context(); }
void json::object(json & j) throw() { j.push_context('{', '}'); }
void json::array(json & j) throw() { j.push_context('[', ']'); }
void json::item(json & j) throw()
{
while (j._context > j._contexts+1 && j._context[-1] != arr)
j.pop_context();
}
json & json::operator << (json::string s) throw()
{
const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq;
context(ctxt);
fprintf(_stream, "\"%s\"", s);
if (ctxt == member) fputc(' ', _stream);
return *this;
}
json & json::operator << (json::number f) throw()
{
context(seq);
if (std::numeric_limits<json::number>::infinity() == f)
fputs("Infinity", _stream);
else if (-std::numeric_limits<json::number>::infinity() == f)
fputs("-Infinity", _stream);
else if (std::numeric_limits<json::number>::quiet_NaN() == f ||
std::numeric_limits<json::number>::signaling_NaN() == f)
fputs("NaN", _stream);
else
fprintf(_stream, "%g", f);
return *this;
}
json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, FORMAT_INTMAX, intmax_t(d)); return *this; }
json & json::operator << (json::integer_u d) throw() { context(seq); fprintf(_stream, FORMAT_UINTMAX, uintmax_t(d)); return *this; }
json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
json & json::operator << (std::nullptr_t) throw() { context(seq); fputs("null",_stream); return *this; }
#endif

14
thirdparty/harfbuzz/AUTHORS vendored Normal file
View File

@ -0,0 +1,14 @@
Behdad Esfahbod
David Corbett
David Turner
Ebrahim Byagowi
Garret Rieger
Jonathan Kew
Khaled Hosny
Lars Knoll
Martin Hosken
Owen Taylor
Roderick Sheeter
Roozbeh Pournader
Simon Hausmann
Werner Lemberg

38
thirdparty/harfbuzz/COPYING vendored Normal file
View File

@ -0,0 +1,38 @@
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
For parts of HarfBuzz that are licensed under different licenses see individual
files names COPYING in subdirectories where applicable.
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
Copyright © 2018,2019,2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2006 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg
For full copyright notices consult the individual files in the package.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the
above copyright notice and the following two paragraphs appear in
all copies of this software.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

2412
thirdparty/harfbuzz/NEWS vendored Normal file

File diff suppressed because it is too large Load Diff

7
thirdparty/harfbuzz/THANKS vendored Normal file
View File

@ -0,0 +1,7 @@
Bradley Grainger
Kenichi Ishibashi
Ivan Kuckir <https://photopea.com/>
Ryan Lortie
Jeff Muizelaar
suzuki toshiya
Philip Withnall

View File

@ -0,0 +1,98 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
#define HB_AAT_LAYOUT_ANKR_TABLE_HH
#include "hb-aat-layout-common.hh"
/*
* ankr -- Anchor Point
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html
*/
#define HB_AAT_TAG_ankr HB_TAG('a','n','k','r')
namespace AAT {
using namespace OT;
struct Anchor
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
FWORD xCoordinate;
FWORD yCoordinate;
public:
DEFINE_SIZE_STATIC (4);
};
typedef LArrayOf<Anchor> GlyphAnchors;
struct ankr
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
const Anchor &get_anchor (hb_codepoint_t glyph_id,
unsigned int i,
unsigned int num_glyphs) const
{
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
if (!offset)
return Null (Anchor);
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
return anchors[i];
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version == 0 &&
c->check_range (this, anchorData) &&
lookupTable.sanitize (c, this, &(this+anchorData))));
}
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
lookupTable; /* Offset to the table's lookup table */
LNNOffsetTo<HBUINT8>
anchorData; /* Offset to the glyph data table */
public:
DEFINE_SIZE_STATIC (12);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_ANKR_TABLE_HH */

View File

@ -0,0 +1,158 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH
#define HB_AAT_LAYOUT_BSLN_TABLE_HH
#include "hb-aat-layout-common.hh"
/*
* bsln -- Baseline
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html
*/
#define HB_AAT_TAG_bsln HB_TAG('b','s','l','n')
namespace AAT {
struct BaselineTableFormat0Part
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
// Roman, Ideographic centered, Ideographic low, Hanging and Math
// are the default defined ones, but any other maybe accessed also.
HBINT16 deltas[32]; /* These are the FUnit distance deltas from
* the font's natural baseline to the other
* baselines used in the font. */
public:
DEFINE_SIZE_STATIC (64);
};
struct BaselineTableFormat1Part
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
lookupTable.sanitize (c)));
}
protected:
HBINT16 deltas[32]; /* ditto */
Lookup<HBUINT16>
lookupTable; /* Lookup table that maps glyphs to their
* baseline values. */
public:
DEFINE_SIZE_MIN (66);
};
struct BaselineTableFormat2Part
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBGlyphID stdGlyph; /* The specific glyph index number in this
* font that is used to set the baseline values.
* This is the standard glyph.
* This glyph must contain a set of control points
* (whose numbers are contained in the ctlPoints field)
* that are used to determine baseline distances. */
HBUINT16 ctlPoints[32]; /* Set of control point numbers,
* associated with the standard glyph.
* A value of 0xFFFF means there is no corresponding
* control point in the standard glyph. */
public:
DEFINE_SIZE_STATIC (66);
};
struct BaselineTableFormat3Part
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c)));
}
protected:
HBGlyphID stdGlyph; /* ditto */
HBUINT16 ctlPoints[32]; /* ditto */
Lookup<HBUINT16>
lookupTable; /* Lookup table that maps glyphs to their
* baseline values. */
public:
DEFINE_SIZE_MIN (68);
};
struct bsln
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
return_trace (false);
switch (format)
{
case 0: return_trace (parts.format0.sanitize (c));
case 1: return_trace (parts.format1.sanitize (c));
case 2: return_trace (parts.format2.sanitize (c));
case 3: return_trace (parts.format3.sanitize (c));
default:return_trace (true);
}
}
protected:
FixedVersion<>version; /* Version number of the Baseline table. */
HBUINT16 format; /* Format of the baseline table. Only one baseline
* format may be selected for the font. */
HBUINT16 defaultBaseline;/* Default baseline value for all glyphs.
* This value can be from 0 through 31. */
union {
// Distance-Based Formats
BaselineTableFormat0Part format0;
BaselineTableFormat1Part format1;
// Control Point-based Formats
BaselineTableFormat2Part format2;
BaselineTableFormat3Part format3;
} parts;
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_BSLN_TABLE_HH */

View File

@ -0,0 +1,840 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_COMMON_HH
#define HB_AAT_LAYOUT_COMMON_HH
#include "hb-aat-layout.hh"
#include "hb-open-type.hh"
namespace AAT {
using namespace OT;
/*
* Lookup Table
*/
template <typename T> struct Lookup;
template <typename T>
struct LookupFormat0
{
friend struct Lookup<T>;
private:
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
if (unlikely (glyph_id >= num_glyphs)) return nullptr;
return &arrayZ[glyph_id];
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
}
protected:
HBUINT16 format; /* Format identifier--format = 0 */
UnsizedArrayOf<T>
arrayZ; /* Array of lookup values, indexed by glyph index. */
public:
DEFINE_SIZE_UNBOUNDED (2);
};
template <typename T>
struct LookupSegmentSingle
{
static constexpr unsigned TerminationWordCount = 2u;
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1 ; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c, base));
}
HBGlyphID last; /* Last GlyphID in this segment */
HBGlyphID first; /* First GlyphID in this segment */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
};
template <typename T>
struct LookupFormat2
{
friend struct Lookup<T>;
private:
const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
return v ? &v->value : nullptr;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
public:
DEFINE_SIZE_ARRAY (8, segments);
};
template <typename T>
struct LookupSegmentArray
{
static constexpr unsigned TerminationWordCount = 2u;
const T* get_value (hb_codepoint_t glyph_id, const void *base) const
{
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
}
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1));
}
template <typename ...Ts>
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
}
HBGlyphID last; /* Last GlyphID in this segment */
HBGlyphID first; /* First GlyphID in this segment */
NNOffsetTo<UnsizedArrayOf<T>>
valuesZ; /* A 16-bit offset from the start of
* the table to the data. */
public:
DEFINE_SIZE_STATIC (6);
};
template <typename T>
struct LookupFormat4
{
friend struct Lookup<T>;
private:
const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
return v ? v->get_value (glyph_id, this) : nullptr;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, this));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, this, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 4 */
VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
public:
DEFINE_SIZE_ARRAY (8, segments);
};
template <typename T>
struct LookupSingle
{
static constexpr unsigned TerminationWordCount = 1u;
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c, base));
}
HBGlyphID glyph; /* Last GlyphID */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC (2 + T::static_size);
};
template <typename T>
struct LookupFormat6
{
friend struct Lookup<T>;
private:
const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSingle<T> *v = entries.bsearch (glyph_id);
return v ? &v->value : nullptr;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (entries.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (entries.sanitize (c, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 6 */
VarSizedBinSearchArrayOf<LookupSingle<T>>
entries; /* The actual entries, sorted by glyph index. */
public:
DEFINE_SIZE_ARRAY (8, entries);
};
template <typename T>
struct LookupFormat8
{
friend struct Lookup<T>;
private:
const T* get_value (hb_codepoint_t glyph_id) const
{
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
&valueArrayZ[glyph_id - firstGlyph] : nullptr;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 8 */
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<T>
valueArrayZ; /* The lookup values (indexed by the glyph index
* minus the value of firstGlyph). */
public:
DEFINE_SIZE_ARRAY (6, valueArrayZ);
};
template <typename T>
struct LookupFormat10
{
friend struct Lookup<T>;
private:
const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
{
if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
return Null (T);
const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
unsigned int v = 0;
unsigned int count = valueSize;
for (unsigned int i = 0; i < count; i++)
v = (v << 8) | *p++;
return v;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
valueSize <= 4 &&
valueArrayZ.sanitize (c, glyphCount * valueSize));
}
protected:
HBUINT16 format; /* Format identifier--format = 8 */
HBUINT16 valueSize; /* Byte size of each value. */
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<HBUINT8>
valueArrayZ; /* The lookup values (indexed by the glyph index
* minus the value of firstGlyph). */
public:
DEFINE_SIZE_ARRAY (8, valueArrayZ);
};
template <typename T>
struct Lookup
{
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
case 0: return u.format0.get_value (glyph_id, num_glyphs);
case 2: return u.format2.get_value (glyph_id);
case 4: return u.format4.get_value (glyph_id);
case 6: return u.format6.get_value (glyph_id);
case 8: return u.format8.get_value (glyph_id);
default:return nullptr;
}
}
const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
/* Format 10 cannot return a pointer. */
case 10: return u.format10.get_value_or_null (glyph_id);
default:
const T *v = get_value (glyph_id, num_glyphs);
return v ? *v : Null (T);
}
}
typename T::type get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
unsigned int outOfRange) const
{
const T *v = get_value (glyph_id, num_glyphs);
return v ? *v : outOfRange;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
case 6: return_trace (u.format6.sanitize (c));
case 8: return_trace (u.format8.sanitize (c));
case 10: return_trace (u.format10.sanitize (c));
default:return_trace (true);
}
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c, base));
case 2: return_trace (u.format2.sanitize (c, base));
case 4: return_trace (u.format4.sanitize (c, base));
case 6: return_trace (u.format6.sanitize (c, base));
case 8: return_trace (u.format8.sanitize (c, base));
case 10: return_trace (false); /* We don't support format10 here currently. */
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
LookupFormat0<T> format0;
LookupFormat2<T> format2;
LookupFormat4<T> format4;
LookupFormat6<T> format6;
LookupFormat8<T> format8;
LookupFormat10<T> format10;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
* special NULL objects for Lookup<> objects, but since it's template our macros
* don't work. So we have to hand-code them here. UGLY. */
} /* Close namespace. */
/* Ugly hand-coded null objects for template Lookup<> :(. */
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
template <typename T>
struct Null<AAT::Lookup<T>> {
static AAT::Lookup<T> const & get_null ()
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
};
namespace AAT {
enum { DELETED_GLYPH = 0xFFFF };
/*
* (Extended) State Table
*/
template <typename T>
struct Entry
{
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
/* Note, we don't recurse-sanitize data because we don't access it.
* That said, in our DEFINE_SIZE_STATIC we access T::static_size,
* which ensures that data has a simple sanitize(). To be determined
* if I need to remove that as well.
*
* HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
* assertion wouldn't be checked, hence the line below. */
static_assert (T::static_size, "");
return_trace (c->check_struct (this));
}
public:
HBUINT16 newState; /* Byte offset from beginning of state table
* to the new state. Really?!?! Or just state
* number? The latter in morx for sure. */
HBUINT16 flags; /* Table specific. */
T data; /* Optional offsets to per-glyph tables. */
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
};
template <>
struct Entry<void>
{
bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */
HBUINT16 flags; /* Table specific. */
public:
DEFINE_SIZE_STATIC (4);
};
template <typename Types, typename Extra>
struct StateTable
{
typedef typename Types::HBUINT HBUINT;
typedef typename Types::HBUSHORT HBUSHORT;
typedef typename Types::ClassTypeNarrow ClassType;
enum State
{
STATE_START_OF_TEXT = 0,
STATE_START_OF_LINE = 1,
};
enum Class
{
CLASS_END_OF_TEXT = 0,
CLASS_OUT_OF_BOUNDS = 1,
CLASS_DELETED_GLYPH = 2,
CLASS_END_OF_LINE = 3,
};
int new_state (unsigned int newState) const
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
return (this+classTable).get_class (glyph_id, num_glyphs, 1);
}
const Entry<Extra> *get_entries () const
{ return (this+entryTable).arrayZ; }
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses))
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int entry = states[state * nClasses + klass];
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
return entries[entry];
}
bool sanitize (hb_sanitize_context_t *c,
unsigned int *num_entries_out = nullptr) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) &&
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
classTable.sanitize (c, this)))) return_trace (false);
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int num_classes = nClasses;
if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
return_trace (false);
unsigned int row_stride = num_classes * states[0].static_size;
/* Apple 'kern' table has this peculiarity:
*
* "Because the stateTableOffset in the state table header is (strictly
* speaking) redundant, some 'kern' tables use it to record an initial
* state where that should not be StartOfText. To determine if this is
* done, calculate what the stateTableOffset should be. If it's different
* from the actual stateTableOffset, use it as the initial state."
*
* We implement this by calling the initial state zero, but allow *negative*
* states if the start state indeed was not the first state. Since the code
* is shared, this will also apply to 'mort' table. The 'kerx' / 'morx'
* tables are not affected since those address states by index, not offset.
*/
int min_state = 0;
int max_state = 0;
unsigned int num_entries = 0;
int state_pos = 0;
int state_neg = 0;
unsigned int entry = 0;
while (min_state < state_neg || state_pos <= max_state)
{
if (min_state < state_neg)
{
/* Negative states. */
if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
return_trace (false);
if (unlikely (!c->check_range (&states[min_state * num_classes],
-min_state,
row_stride)))
return_trace (false);
if ((c->max_ops -= state_neg - min_state) <= 0)
return_trace (false);
{ /* Sweep new states. */
const HBUSHORT *stop = &states[min_state * num_classes];
if (unlikely (stop > states))
return_trace (false);
for (const HBUSHORT *p = states; stop < p; p--)
num_entries = hb_max (num_entries, *(p - 1) + 1);
state_neg = min_state;
}
}
if (state_pos <= max_state)
{
/* Positive states. */
if (unlikely (!c->check_range (states,
max_state + 1,
row_stride)))
return_trace (false);
if ((c->max_ops -= max_state - state_pos + 1) <= 0)
return_trace (false);
{ /* Sweep new states. */
if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
return_trace (false);
const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
if (unlikely (stop < states))
return_trace (false);
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
num_entries = hb_max (num_entries, *p + 1);
state_pos = max_state + 1;
}
}
if (unlikely (!c->check_array (entries, num_entries)))
return_trace (false);
if ((c->max_ops -= num_entries - entry) <= 0)
return_trace (false);
{ /* Sweep new entries. */
const Entry<Extra> *stop = &entries[num_entries];
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
{
int newState = new_state (p->newState);
min_state = hb_min (min_state, newState);
max_state = hb_max (max_state, newState);
}
entry = num_entries;
}
}
if (num_entries_out)
*num_entries_out = num_entries;
return_trace (true);
}
protected:
HBUINT nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
NNOffsetTo<ClassType, HBUINT>
classTable; /* Offset to the class table. */
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
stateArrayTable;/* Offset to the state array. */
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
entryTable; /* Offset to the entry array. */
public:
DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
};
template <typename HBUCHAR>
struct ClassTable
{
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
{
unsigned int i = glyph_id - firstGlyph;
return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
}
unsigned int get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs HB_UNUSED,
unsigned int outOfRange) const
{
return get_class (glyph_id, outOfRange);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && classArray.sanitize (c));
}
protected:
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
* firstGlyph). */
public:
DEFINE_SIZE_ARRAY (4, classArray);
};
struct ObsoleteTypes
{
static constexpr bool extended = false;
typedef HBUINT16 HBUINT;
typedef HBUINT8 HBUSHORT;
typedef ClassTable<HBUINT8> ClassTypeNarrow;
typedef ClassTable<HBUINT16> ClassTypeWide;
template <typename T>
static unsigned int offsetToIndex (unsigned int offset,
const void *base,
const T *array)
{
return (offset - ((const char *) array - (const char *) base)) / T::static_size;
}
template <typename T>
static unsigned int byteOffsetToIndex (unsigned int offset,
const void *base,
const T *array)
{
return offsetToIndex (offset, base, array);
}
template <typename T>
static unsigned int wordOffsetToIndex (unsigned int offset,
const void *base,
const T *array)
{
return offsetToIndex (2 * offset, base, array);
}
};
struct ExtendedTypes
{
static constexpr bool extended = true;
typedef HBUINT32 HBUINT;
typedef HBUINT16 HBUSHORT;
typedef Lookup<HBUINT16> ClassTypeNarrow;
typedef Lookup<HBUINT16> ClassTypeWide;
template <typename T>
static unsigned int offsetToIndex (unsigned int offset,
const void *base HB_UNUSED,
const T *array HB_UNUSED)
{
return offset;
}
template <typename T>
static unsigned int byteOffsetToIndex (unsigned int offset,
const void *base HB_UNUSED,
const T *array HB_UNUSED)
{
return offset / 2;
}
template <typename T>
static unsigned int wordOffsetToIndex (unsigned int offset,
const void *base HB_UNUSED,
const T *array HB_UNUSED)
{
return offset;
}
};
template <typename Types, typename EntryData>
struct StateTableDriver
{
StateTableDriver (const StateTable<Types, EntryData> &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
buffer (buffer_),
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t>
void drive (context_t *c)
{
if (!c->in_place)
buffer->clear_output ();
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
for (buffer->idx = 0; buffer->successful;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const Entry<EntryData> &entry = machine.get_entry (state, klass);
/* Unsafe-to-break before this if not in state 0, as things might
* go differently if we start from state 0 here.
*
* Ugh. The indexing here is ugly... */
if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
{
/* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */
if (c->is_actionable (this, entry) ||
!(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
entry.flags == context_t::DontAdvance))
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
}
/* Unsafe-to-break if end-of-text would kick in here. */
if (buffer->idx + 2 <= buffer->len)
{
const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
if (c->is_actionable (this, end_entry))
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
}
c->transition (this, entry);
state = machine.new_state (entry.newState);
DEBUG_MSG (APPLY, nullptr, "s%d", state);
if (buffer->idx == buffer->len)
break;
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
buffer->next_glyph ();
}
if (!c->in_place)
{
for (; buffer->successful && buffer->idx < buffer->len;)
buffer->next_glyph ();
buffer->swap_buffers ();
}
}
public:
const StateTable<Types, EntryData> &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};
struct ankr;
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
const char *get_name () { return "APPLY"; }
template <typename T>
return_t dispatch (const T &obj) { return obj.apply (this); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
const hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
HB_INTERNAL ~hb_aat_apply_context_t ();
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_COMMON_HH */

View File

@ -0,0 +1,222 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH
#define HB_AAT_LAYOUT_FEAT_TABLE_HH
#include "hb-aat-layout-common.hh"
/*
* feat -- Feature Name
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html
*/
#define HB_AAT_TAG_feat HB_TAG('f','e','a','t')
namespace AAT {
struct SettingName
{
friend struct FeatureName;
int cmp (hb_aat_layout_feature_selector_t key) const
{ return (int) key - (int) setting; }
hb_aat_layout_feature_selector_t get_selector () const
{ return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
hb_aat_layout_feature_selector_info_t get_info (hb_aat_layout_feature_selector_t default_selector) const
{
return {
nameIndex,
(hb_aat_layout_feature_selector_t) (unsigned int) setting,
default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
? (hb_aat_layout_feature_selector_t) (setting + 1)
: default_selector,
0
};
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT16 setting; /* The setting. */
NameID nameIndex; /* The name table index for the setting's name. */
public:
DEFINE_SIZE_STATIC (4);
};
DECLARE_NULL_NAMESPACE_BYTES (AAT, SettingName);
struct feat;
struct FeatureName
{
int cmp (hb_aat_layout_feature_type_t key) const
{ return (int) key - (int) feature; }
enum {
Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */
NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in
* the setting name array for this feature should
* be taken as the default for the feature
* (if one is required). If set, then bits 0-15 of this
* featureFlags field contain the index of the setting
* which is to be taken as the default. */
IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits
* indicate the index of the setting in the setting name
* array for this feature which should be taken
* as the default. */
};
unsigned int get_selector_infos (unsigned int start_offset,
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *pdefault_index, /* OUT. May be NULL. */
const void *base) const
{
hb_array_t< const SettingName> settings_table = (base+settingTableZ).as_array (nSettings);
static_assert (Index::NOT_FOUND_INDEX == HB_AAT_LAYOUT_NO_SELECTOR_INDEX, "");
hb_aat_layout_feature_selector_t default_selector = HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID;
unsigned int default_index = Index::NOT_FOUND_INDEX;
if (featureFlags & Exclusive)
{
default_index = (featureFlags & NotDefault) ? featureFlags & IndexMask : 0;
default_selector = settings_table[default_index].get_selector ();
}
if (pdefault_index)
*pdefault_index = default_index;
if (selectors_count)
{
+ settings_table.sub_array (start_offset, selectors_count)
| hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
| hb_sink (hb_array (selectors, *selectors_count))
;
}
return settings_table.length;
}
hb_aat_layout_feature_type_t get_feature_type () const
{ return (hb_aat_layout_feature_type_t) (unsigned int) feature; }
hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
bool is_exclusive () const { return featureFlags & Exclusive; }
/* A FeatureName with no settings is meaningless */
bool has_data () const { return nSettings; }
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(base+settingTableZ).sanitize (c, nSettings)));
}
protected:
HBUINT16 feature; /* Feature type. */
HBUINT16 nSettings; /* The number of records in the setting name array. */
LNNOffsetTo<UnsizedArrayOf<SettingName>>
settingTableZ; /* Offset in bytes from the beginning of this table to
* this feature's setting name array. The actual type of
* record this offset refers to will depend on the
* exclusivity value, as described below. */
HBUINT16 featureFlags; /* Single-bit flags associated with the feature type. */
HBINT16 nameIndex; /* The name table index for the feature's name.
* This index has values greater than 255 and
* less than 32768. */
public:
DEFINE_SIZE_STATIC (12);
};
struct feat
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
bool has_data () const { return version.to_int (); }
unsigned int get_feature_types (unsigned int start_offset,
unsigned int *count,
hb_aat_layout_feature_type_t *features) const
{
if (count)
{
+ namesZ.as_array (featureNameCount).sub_array (start_offset, count)
| hb_map (&FeatureName::get_feature_type)
| hb_sink (hb_array (features, *count))
;
}
return featureNameCount;
}
bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const
{ return get_feature (feature_type).has_data (); }
const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
{ return namesZ.bsearch (featureNameCount, feature_type); }
hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
{ return get_feature (feature).get_feature_name_id (); }
unsigned int get_selector_infos (hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */) const
{
return get_feature (feature_type).get_selector_infos (start_offset, selectors_count, selectors,
default_index, this);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
namesZ.sanitize (c, featureNameCount, this)));
}
protected:
FixedVersion<>version; /* Version number of the feature name table
* (0x00010000 for the current version). */
HBUINT16 featureNameCount;
/* The number of entries in the feature name array. */
HBUINT16 reserved1; /* Reserved (set to zero). */
HBUINT32 reserved2; /* Reserved (set to zero). */
SortedUnsizedArrayOf<FeatureName>
namesZ; /* The feature name array. */
public:
DEFINE_SIZE_ARRAY (12, namesZ);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_FEAT_TABLE_HH */

View File

@ -0,0 +1,417 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_JUST_TABLE_HH
#define HB_AAT_LAYOUT_JUST_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
#include "hb-aat-layout-morx-table.hh"
/*
* just -- Justification
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html
*/
#define HB_AAT_TAG_just HB_TAG('j','u','s','t')
namespace AAT {
using namespace OT;
struct ActionSubrecordHeader
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
HBUINT16 actionClass; /* The JustClass value associated with this
* ActionSubrecord. */
HBUINT16 actionType; /* The type of postcompensation action. */
HBUINT16 actionLength; /* Length of this ActionSubrecord record, which
* must be a multiple of 4. */
public:
DEFINE_SIZE_STATIC (6);
};
struct DecompositionAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
ActionSubrecordHeader
header;
HBFixed lowerLimit; /* If the distance factor is less than this value,
* then the ligature is decomposed. */
HBFixed upperLimit; /* If the distance factor is greater than this value,
* then the ligature is decomposed. */
HBUINT16 order; /* Numerical order in which this ligature will
* be decomposed; you may want infrequent ligatures
* to decompose before more frequent ones. The ligatures
* on the line of text will decompose in increasing
* value of this field. */
ArrayOf<HBUINT16>
decomposedglyphs;
/* Number of 16-bit glyph indexes that follow;
* the ligature will be decomposed into these glyphs.
*
* Array of decomposed glyphs. */
public:
DEFINE_SIZE_ARRAY (18, decomposedglyphs);
};
struct UnconditionalAddGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
ActionSubrecordHeader
header;
HBGlyphID addGlyph; /* Glyph that should be added if the distance factor
* is growing. */
public:
DEFINE_SIZE_STATIC (8);
};
struct ConditionalAddGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
ActionSubrecordHeader
header;
HBFixed substThreshold; /* Distance growth factor (in ems) at which
* this glyph is replaced and the growth factor
* recalculated. */
HBGlyphID addGlyph; /* Glyph to be added as kashida. If this value is
* 0xFFFF, no extra glyph will be added. Note that
* generally when a glyph is added, justification
* will need to be redone. */
HBGlyphID substGlyph; /* Glyph to be substituted for this glyph if the
* growth factor equals or exceeds the value of
* substThreshold. */
public:
DEFINE_SIZE_STATIC (14);
};
struct DuctileGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
ActionSubrecordHeader
header;
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
* This would normally be 0x64756374 ('duct'),
* but you may use any axis the font contains. */
HBFixed minimumLimit; /* The lowest value for the ductility axis tha
* still yields an acceptable appearance. Normally
* this will be 1.0. */
HBFixed noStretchValue; /* This is the default value that corresponds to
* no change in appearance. Normally, this will
* be 1.0. */
HBFixed maximumLimit; /* The highest value for the ductility axis that
* still yields an acceptable appearance. */
public:
DEFINE_SIZE_STATIC (22);
};
struct RepeatedAddGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
ActionSubrecordHeader
header;
HBUINT16 flags; /* Currently unused; set to 0. */
HBGlyphID glyph; /* Glyph that should be added if the distance factor
* is growing. */
public:
DEFINE_SIZE_STATIC (10);
};
struct ActionSubrecord
{
unsigned int get_length () const { return u.header.actionLength; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
switch (u.header.actionType)
{
case 0: return_trace (u.decompositionAction.sanitize (c));
case 1: return_trace (u.unconditionalAddGlyphAction.sanitize (c));
case 2: return_trace (u.conditionalAddGlyphAction.sanitize (c));
// case 3: return_trace (u.stretchGlyphAction.sanitize (c));
case 4: return_trace (u.decompositionAction.sanitize (c));
case 5: return_trace (u.decompositionAction.sanitize (c));
default: return_trace (true);
}
}
protected:
union {
ActionSubrecordHeader header;
DecompositionAction decompositionAction;
UnconditionalAddGlyphAction unconditionalAddGlyphAction;
ConditionalAddGlyphAction conditionalAddGlyphAction;
/* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */
DuctileGlyphAction ductileGlyphAction;
RepeatedAddGlyphAction repeatedAddGlyphAction;
} u; /* Data. The format of this data depends on
* the value of the actionType field. */
public:
DEFINE_SIZE_UNION (6, header);
};
struct PostcompensationActionChain
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
unsigned int offset = min_size;
for (unsigned int i = 0; i < count; i++)
{
const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset);
if (unlikely (!subrecord.sanitize (c))) return_trace (false);
offset += subrecord.get_length ();
}
return_trace (true);
}
protected:
HBUINT32 count;
public:
DEFINE_SIZE_STATIC (4);
};
struct JustWidthDeltaEntry
{
enum Flags
{
Reserved1 =0xE000,/* Reserved. You should set these bits to zero. */
UnlimiteGap =0x1000,/* The glyph can take unlimited gap. When this
* glyph participates in the justification process,
* it and any other glyphs on the line having this
* bit set absorb all the remaining gap. */
Reserved2 =0x0FF0,/* Reserved. You should set these bits to zero. */
Priority =0x000F /* The justification priority of the glyph. */
};
enum Priority
{
Kashida = 0, /* Kashida priority. This is the highest priority
* during justification. */
Whitespace = 1, /* Whitespace priority. Any whitespace glyphs (as
* identified in the glyph properties table) will
* get this priority. */
InterCharacter = 2, /* Inter-character priority. Give this to any
* remaining glyphs. */
NullPriority = 3 /* Null priority. You should set this priority for
* glyphs that only participate in justification
* after the above priorities. Normally all glyphs
* have one of the previous three values. If you
* don't want a glyph to participate in justification,
* and you don't want to set its factors to zero,
* you may instead assign it to the null priority. */
};
protected:
HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
* glyph is permitted to grow on the left or top side. */
HBFixed beforeShrinkLimit;
/* The ratio by which the advance width of the
* glyph is permitted to shrink on the left or top side. */
HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
* is permitted to shrink on the left or top side. */
HBFixed afterShrinkLimit;
/* The ratio by which the advance width of the glyph
* is at most permitted to shrink on the right or
* bottom side. */
HBUINT16 growFlags; /* Flags controlling the grow case. */
HBUINT16 shrinkFlags; /* Flags controlling the shrink case. */
public:
DEFINE_SIZE_STATIC (20);
};
struct WidthDeltaPair
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT32 justClass; /* The justification category associated
* with the wdRecord field. Only 7 bits of
* this field are used. (The other bits are
* used as padding to guarantee longword
* alignment of the following record). */
JustWidthDeltaEntry
wdRecord; /* The actual width delta record. */
public:
DEFINE_SIZE_STATIC (24);
};
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
struct JustificationCategory
{
typedef void EntryData;
enum Flags
{
SetMark =0x8000,/* If set, make the current glyph the marked
* glyph. */
DontAdvance =0x4000,/* If set, don't advance to the next glyph before
* going to the new state. */
MarkCategory =0x3F80,/* The justification category for the marked
* glyph if nonzero. */
CurrentCategory =0x007F /* The justification category for the current
* glyph if nonzero. */
};
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
morphHeader.sanitize (c) &&
stHeader.sanitize (c)));
}
protected:
ChainSubtable<ObsoleteTypes>
morphHeader; /* Metamorphosis-style subtable header. */
StateTable<ObsoleteTypes, EntryData>
stHeader; /* The justification insertion state table header */
public:
DEFINE_SIZE_STATIC (30);
};
struct JustificationHeader
{
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
justClassTable.sanitize (c, base, base) &&
wdcTable.sanitize (c, base) &&
pcTable.sanitize (c, base) &&
lookupTable.sanitize (c, base)));
}
protected:
OffsetTo<JustificationCategory>
justClassTable; /* Offset to the justification category state table. */
OffsetTo<WidthDeltaCluster>
wdcTable; /* Offset from start of justification table to start
* of the subtable containing the width delta factors
* for the glyphs in your font.
*
* The width delta clusters table. */
OffsetTo<PostcompensationActionChain>
pcTable; /* Offset from start of justification table to start
* of postcompensation subtable (set to zero if none).
*
* The postcompensation subtable, if present in the font. */
Lookup<OffsetTo<WidthDeltaCluster>>
lookupTable; /* Lookup table associating glyphs with width delta
* clusters. See the description of Width Delta Clusters
* table for details on how to interpret the lookup values. */
public:
DEFINE_SIZE_MIN (8);
};
struct just
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
}
protected:
FixedVersion<>version; /* Version of the justification table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the justification table (set to 0). */
OffsetTo<JustificationHeader>
horizData; /* Byte offset from the start of the justification table
* to the header for tables that contain justification
* information for horizontal text.
* If you are not including this information,
* store 0. */
OffsetTo<JustificationHeader>
vertData; /* ditto, vertical */
public:
DEFINE_SIZE_STATIC (10);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */

View File

@ -0,0 +1,999 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
#define HB_AAT_LAYOUT_KERX_TABLE_HH
#include "hb-kern.hh"
#include "hb-aat-layout-ankr-table.hh"
/*
* kerx -- Extended Kerning
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
*/
#define HB_AAT_TAG_kerx HB_TAG('k','e','r','x')
namespace AAT {
using namespace OT;
static inline int
kerxTupleKern (int value,
unsigned int tupleCount,
const void *base,
hb_aat_apply_context_t *c)
{
if (likely (!tupleCount || !c)) return value;
unsigned int offset = value;
const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
return *pv;
}
struct hb_glyph_pair_t
{
hb_codepoint_t left;
hb_codepoint_t right;
};
struct KernPair
{
int get_kerning () const { return value; }
int cmp (const hb_glyph_pair_t &o) const
{
int ret = left.cmp (o.left);
if (ret) return ret;
return right.cmp (o.right);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBGlyphID left;
HBGlyphID right;
FWORD value;
public:
DEFINE_SIZE_STATIC (6);
};
template <typename KernSubTableHeader>
struct KerxSubTableFormat0
{
int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
hb_aat_apply_context_t *c = nullptr) const
{
hb_glyph_pair_t pair = {left, right};
int v = pairs.bsearch (pair).get_kerning ();
return kerxTupleKern (v, header.tuple_count (), this, c);
}
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
return_trace (true);
}
struct accelerator_t
{
const KerxSubTableFormat0 &table;
hb_aat_apply_context_t *c;
accelerator_t (const KerxSubTableFormat0 &table_,
hb_aat_apply_context_t *c_) :
table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table.get_kerning (left, right, c); }
};
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (pairs.sanitize (c)));
}
protected:
KernSubTableHeader header;
BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT>
pairs; /* Sorted kern records. */
public:
DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 16, pairs);
};
template <bool extended>
struct Format1Entry;
template <>
struct Format1Entry<true>
{
enum Flags
{
Push = 0x8000, /* If set, push this glyph on the kerning stack. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. */
Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */
Reserved = 0x1FFF, /* Not used; set to 0. */
};
struct EntryData
{
HBUINT16 kernActionIndex;/* Index into the kerning value array. If
* this index is 0xFFFF, then no kerning
* is to be performed. */
public:
DEFINE_SIZE_STATIC (2);
};
static bool performAction (const Entry<EntryData> &entry)
{ return entry.data.kernActionIndex != 0xFFFF; }
static unsigned int kernActionIndex (const Entry<EntryData> &entry)
{ return entry.data.kernActionIndex; }
};
template <>
struct Format1Entry<false>
{
enum Flags
{
Push = 0x8000, /* If set, push this glyph on the kerning stack. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. */
Offset = 0x3FFF, /* Byte offset from beginning of subtable to the
* value table for the glyphs on the kerning stack. */
Reset = 0x0000, /* Not supported? */
};
typedef void EntryData;
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
static unsigned int kernActionIndex (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
};
template <typename KernSubTableHeader>
struct KerxSubTableFormat1
{
typedef typename KernSubTableHeader::Types Types;
typedef typename Types::HBUINT HBUINT;
typedef Format1Entry<Types::extended> Format1EntryT;
typedef typename Format1EntryT::EntryData EntryData;
struct driver_context_t
{
static constexpr bool in_place = true;
enum
{
DontAdvance = Format1EntryT::DontAdvance,
};
driver_context_t (const KerxSubTableFormat1 *table_,
hb_aat_apply_context_t *c_) :
c (c_),
table (table_),
/* Apparently the offset kernAction is from the beginning of the state-machine,
* similar to offsets in morx table, NOT from beginning of this table, like
* other subtables in kerx. Discovered via testing. */
kernAction (&table->machine + table->kernAction),
depth (0),
crossStream (table->header.coverage & table->header.CrossStream) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return Format1EntryT::performAction (entry); }
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags;
if (flags & Format1EntryT::Reset)
depth = 0;
if (flags & Format1EntryT::Push)
{
if (likely (depth < ARRAY_LENGTH (stack)))
stack[depth++] = buffer->idx;
else
depth = 0; /* Probably not what CoreText does, but better? */
}
if (Format1EntryT::performAction (entry) && depth)
{
unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
const FWORD *actions = &kernAction[kern_idx];
if (!c->sanitizer.check_array (actions, depth, tuple_count))
{
depth = 0;
return;
}
hb_mask_t kern_mask = c->plan->kern_mask;
/* From Apple 'kern' spec:
* "Each pops one glyph from the kerning stack and applies the kerning value to it.
* The end of the list is marked by an odd value... */
bool last = false;
while (!last && depth)
{
unsigned int idx = stack[--depth];
int v = *actions;
actions += tuple_count;
if (idx >= buffer->len) continue;
/* "The end of the list is marked by an odd value..." */
last = v & 1;
v &= ~1;
hb_glyph_position_t &o = buffer->pos[idx];
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
if (crossStream)
{
/* The following flag is undocumented in the spec, but described
* in the 'kern' table example. */
if (v == -0x8000)
{
o.attach_type() = ATTACH_TYPE_NONE;
o.attach_chain() = 0;
o.y_offset = 0;
}
else if (o.attach_type())
{
o.y_offset += c->font->em_scale_y (v);
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
}
else if (buffer->info[idx].mask & kern_mask)
{
o.x_advance += c->font->em_scale_x (v);
o.x_offset += c->font->em_scale_x (v);
}
}
else
{
if (crossStream)
{
/* CoreText doesn't do crossStream kerning in vertical. We do. */
if (v == -0x8000)
{
o.attach_type() = ATTACH_TYPE_NONE;
o.attach_chain() = 0;
o.x_offset = 0;
}
else if (o.attach_type())
{
o.x_offset += c->font->em_scale_x (v);
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
}
else if (buffer->info[idx].mask & kern_mask)
{
o.y_advance += c->font->em_scale_y (v);
o.y_offset += c->font->em_scale_y (v);
}
}
}
}
}
private:
hb_aat_apply_context_t *c;
const KerxSubTableFormat1 *table;
const UnsizedArrayOf<FWORD> &kernAction;
unsigned int stack[8];
unsigned int depth;
bool crossStream;
};
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
if (!c->plan->requested_kerning &&
!(header.coverage & header.CrossStream))
return false;
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
driver.drive (&dc);
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */
return_trace (likely (c->check_struct (this) &&
machine.sanitize (c)));
}
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT));
};
template <typename KernSubTableHeader>
struct KerxSubTableFormat2
{
typedef typename KernSubTableHeader::Types Types;
typedef typename Types::HBUINT HBUINT;
int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
hb_aat_apply_context_t *c) const
{
unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
unsigned int l = (this+leftClassTable).get_class (left, num_glyphs, 0);
unsigned int r = (this+rightClassTable).get_class (right, num_glyphs, 0);
const UnsizedArrayOf<FWORD> &arrayZ = this+array;
unsigned int kern_idx = l + r;
kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
const FWORD *v = &arrayZ[kern_idx];
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
return kerxTupleKern (*v, header.tuple_count (), this, c);
}
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
return_trace (true);
}
struct accelerator_t
{
const KerxSubTableFormat2 &table;
hb_aat_apply_context_t *c;
accelerator_t (const KerxSubTableFormat2 &table_,
hb_aat_apply_context_t *c_) :
table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table.get_kerning (left, right, c); }
};
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) &&
c->check_range (this, array)));
}
protected:
KernSubTableHeader header;
HBUINT rowWidth; /* The width, in bytes, of a row in the table. */
NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
leftClassTable; /* Offset from beginning of this subtable to
* left-hand class table. */
NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
rightClassTable;/* Offset from beginning of this subtable to
* right-hand class table. */
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>
array; /* Offset from beginning of this subtable to
* the start of the kerning array. */
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 4 * sizeof (HBUINT));
};
template <typename KernSubTableHeader>
struct KerxSubTableFormat4
{
typedef ExtendedTypes Types;
struct EntryData
{
HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of
* the action to perform. */
public:
DEFINE_SIZE_STATIC (2);
};
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags
{
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* Not used; set to 0. */
};
enum SubTableFlags
{
ActionType = 0xC0000000, /* A two-bit field containing the action type. */
Unused = 0x3F000000, /* Unused - must be zero. */
Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning
* of the subtable to the beginning of the control
* point table. */
};
driver_context_t (const KerxSubTableFormat4 *table,
hb_aat_apply_context_t *c_) :
c (c_),
action_type ((table->flags & ActionType) >> 30),
ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
mark_set (false),
mark (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return entry.data.ankrActionIndex != 0xFFFF; }
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
{
hb_glyph_position_t &o = buffer->cur_pos();
switch (action_type)
{
case 0: /* Control Point Actions.*/
{
/* Indexed into glyph outline. */
/* Each action (record in ankrData) contains two 16-bit fields, so we must
double the ankrActionIndex to get the correct offset here. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
if (!c->sanitizer.check_array (data, 2)) return;
unsigned int markControlPoint = *data++;
unsigned int currControlPoint = *data++;
hb_position_t markX = 0;
hb_position_t markY = 0;
hb_position_t currX = 0;
hb_position_t currY = 0;
if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint,
markControlPoint,
HB_DIRECTION_LTR /*XXX*/,
&markX, &markY) ||
!c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint,
currControlPoint,
HB_DIRECTION_LTR /*XXX*/,
&currX, &currY))
return;
o.x_offset = markX - currX;
o.y_offset = markY - currY;
}
break;
case 1: /* Anchor Point Actions. */
{
/* Indexed into 'ankr' table. */
/* Each action (record in ankrData) contains two 16-bit fields, so we must
double the ankrActionIndex to get the correct offset here. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
if (!c->sanitizer.check_array (data, 2)) return;
unsigned int markAnchorPoint = *data++;
unsigned int currAnchorPoint = *data++;
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
markAnchorPoint,
c->sanitizer.get_num_glyphs ());
const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
currAnchorPoint,
c->sanitizer.get_num_glyphs ());
o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
}
break;
case 2: /* Control Point Coordinate Actions. */
{
/* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
by 4 to get the correct offset for the given action. */
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
if (!c->sanitizer.check_array (data, 4)) return;
int markX = *data++;
int markY = *data++;
int currX = *data++;
int currY = *data++;
o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX);
o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY);
}
break;
}
o.attach_type() = ATTACH_TYPE_MARK;
o.attach_chain() = (int) mark - (int) buffer->idx;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
if (entry.flags & Mark)
{
mark_set = true;
mark = buffer->idx;
}
}
private:
hb_aat_apply_context_t *c;
unsigned int action_type;
const HBUINT16 *ankrData;
bool mark_set;
unsigned int mark;
};
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
driver.drive (&dc);
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */
return_trace (likely (c->check_struct (this) &&
machine.sanitize (c)));
}
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
HBUINT32 flags;
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20);
};
template <typename KernSubTableHeader>
struct KerxSubTableFormat6
{
enum Flags
{
ValuesAreLong = 0x00000001,
};
bool is_long () const { return flags & ValuesAreLong; }
int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
hb_aat_apply_context_t *c) const
{
unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
if (is_long ())
{
const typename U::Long &t = u.l;
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
unsigned int offset = l + r;
if (unlikely (offset < l)) return 0; /* Addition overflow. */
if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
}
else
{
const typename U::Short &t = u.s;
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
unsigned int offset = l + r;
const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
}
}
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
if (!c->plan->requested_kerning)
return false;
if (header.coverage & header.Backwards)
return false;
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(is_long () ?
(
u.l.rowIndexTable.sanitize (c, this) &&
u.l.columnIndexTable.sanitize (c, this) &&
c->check_range (this, u.l.array)
) : (
u.s.rowIndexTable.sanitize (c, this) &&
u.s.columnIndexTable.sanitize (c, this) &&
c->check_range (this, u.s.array)
)) &&
(header.tuple_count () == 0 ||
c->check_range (this, vector))));
}
struct accelerator_t
{
const KerxSubTableFormat6 &table;
hb_aat_apply_context_t *c;
accelerator_t (const KerxSubTableFormat6 &table_,
hb_aat_apply_context_t *c_) :
table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table.get_kerning (left, right, c); }
};
protected:
KernSubTableHeader header;
HBUINT32 flags;
HBUINT16 rowCount;
HBUINT16 columnCount;
union U
{
struct Long
{
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
} l;
struct Short
{
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
} s;
} u;
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
};
struct KerxSubTableHeader
{
typedef ExtendedTypes Types;
unsigned tuple_count () const { return tupleCount; }
bool is_horizontal () const { return !(coverage & Vertical); }
enum Coverage
{
Vertical = 0x80000000u, /* Set if table has vertical kerning values. */
CrossStream = 0x40000000u, /* Set if table has cross-stream kerning values. */
Variation = 0x20000000u, /* Set if table has variation kerning values. */
Backwards = 0x10000000u, /* If clear, process the glyphs forwards, that
* is, from first to last in the glyph stream.
* If we, process them from last to first.
* This flag only applies to state-table based
* 'kerx' subtables (types 1 and 4). */
Reserved = 0x0FFFFF00u, /* Reserved, set to zero. */
SubtableType= 0x000000FFu, /* Subtable type. */
};
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
public:
HBUINT32 length;
HBUINT32 coverage;
HBUINT32 tupleCount;
public:
DEFINE_SIZE_STATIC (12);
};
struct KerxSubTable
{
friend struct kerx;
unsigned int get_size () const { return u.header.length; }
unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
unsigned int subtable_type = get_type ();
TRACE_DISPATCH (this, subtable_type);
switch (subtable_type) {
case 0: return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
case 6: return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
default: return_trace (c->default_return_value ());
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.header.sanitize (c) ||
u.header.length <= u.header.static_size ||
!c->check_range (this, u.header.length))
return_trace (false);
return_trace (dispatch (c));
}
public:
union {
KerxSubTableHeader header;
KerxSubTableFormat0<KerxSubTableHeader> format0;
KerxSubTableFormat1<KerxSubTableHeader> format1;
KerxSubTableFormat2<KerxSubTableHeader> format2;
KerxSubTableFormat4<KerxSubTableHeader> format4;
KerxSubTableFormat6<KerxSubTableHeader> format6;
} u;
public:
DEFINE_SIZE_MIN (12);
};
/*
* The 'kerx' Table
*/
template <typename T>
struct KerxTable
{
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
const T* thiz () const { return static_cast<const T *> (this); }
bool has_state_machine () const
{
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
if (st->get_type () == 1)
return true;
st = &StructAfter<SubTable> (*st);
}
return false;
}
bool has_cross_stream () const
{
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
if (st->u.header.coverage & st->u.header.CrossStream)
return true;
st = &StructAfter<SubTable> (*st);
}
return false;
}
int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
typedef typename T::SubTable SubTable;
int v = 0;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
!st->u.header.is_horizontal ())
continue;
v += st->get_kerning (left, right);
st = &StructAfter<SubTable> (*st);
}
return v;
}
bool apply (AAT::hb_aat_apply_context_t *c) const
{
typedef typename T::SubTable SubTable;
bool ret = false;
bool seenCrossStream = false;
c->set_lookup_index (0);
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
bool reverse;
if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
goto skip;
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
goto skip;
reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index))
goto skip;
if (!seenCrossStream &&
(st->u.header.coverage & st->u.header.CrossStream))
{
/* Attach all glyphs into a chain. */
seenCrossStream = true;
hb_glyph_position_t *pos = c->buffer->pos;
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++)
{
pos[i].attach_type() = ATTACH_TYPE_CURSIVE;
pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1;
/* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT,
* since there needs to be a non-zero attachment for post-positioning to
* be needed. */
}
}
if (reverse)
c->buffer->reverse ();
{
/* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
ret |= st->dispatch (c);
}
if (reverse)
c->buffer->reverse ();
(void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
skip:
st = &StructAfter<SubTable> (*st);
c->set_lookup_index (c->lookup_index + 1);
}
return ret;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!thiz()->version.sanitize (c) ||
(unsigned) thiz()->version < (unsigned) T::minVersion ||
!thiz()->tableCount.sanitize (c)))
return_trace (false);
typedef typename T::SubTable SubTable;
const SubTable *st = &thiz()->firstSubTable;
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
if (unlikely (!st->u.header.sanitize (c)))
return_trace (false);
/* OpenType kern table has 2-byte subtable lengths. That's limiting.
* MS implementation also only supports one subtable, of format 0,
* anyway. Certain versions of some fonts, like Calibry, contain
* kern subtable that exceeds 64kb. Looks like, the subtable length
* is simply ignored. Which makes sense. It's only needed if you
* have multiple subtables. To handle such fonts, we just ignore
* the length for the last subtable. */
hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr);
if (unlikely (!st->sanitize (c)))
return_trace (false);
st = &StructAfter<SubTable> (*st);
}
return_trace (true);
}
};
struct kerx : KerxTable<kerx>
{
friend struct KerxTable<kerx>;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
static constexpr unsigned minVersion = 2u;
typedef KerxSubTableHeader SubTableHeader;
typedef SubTableHeader::Types Types;
typedef KerxSubTable SubTable;
bool has_data () const { return version; }
protected:
HBUINT16 version; /* The version number of the extended kerning table
* (currently 2, 3, or 4). */
HBUINT16 unused; /* Set to 0. */
HBUINT32 tableCount; /* The number of subtables included in the extended kerning
* table. */
SubTable firstSubTable; /* Subtables. */
/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
/*
* Copyright © 2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
#define HB_AAT_LAYOUT_OPBD_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-open-type.hh"
/*
* opbd -- Optical Bounds
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
*/
#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
namespace AAT {
struct OpticalBounds
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
FWORD leftSide;
FWORD topSide;
FWORD rightSide;
FWORD bottomSide;
public:
DEFINE_SIZE_STATIC (8);
};
struct opbdFormat0
{
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
hb_glyph_extents_t *extents, const void *base) const
{
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
if (!bounds_offset) return false;
const OpticalBounds &bounds = base+*bounds_offset;
if (extents)
*extents = {
font->em_scale_x (bounds.leftSide),
font->em_scale_y (bounds.topSide),
font->em_scale_x (bounds.rightSide),
font->em_scale_y (bounds.bottomSide)
};
return true;
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
}
protected:
Lookup<OffsetTo<OpticalBounds>>
lookupTable; /* Lookup table associating glyphs with the four
* int16 values for the left-side, top-side,
* right-side, and bottom-side optical bounds. */
public:
DEFINE_SIZE_MIN (2);
};
struct opbdFormat1
{
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
hb_glyph_extents_t *extents, const void *base) const
{
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
if (!bounds_offset) return false;
const OpticalBounds &bounds = base+*bounds_offset;
hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
{
if (extents)
*extents = {left, top, right, bottom};
return true;
}
return false;
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
}
protected:
Lookup<OffsetTo<OpticalBounds>>
lookupTable; /* Lookup table associating glyphs with the four
* int16 values for the left-side, top-side,
* right-side, and bottom-side optical bounds. */
public:
DEFINE_SIZE_MIN (2);
};
struct opbd
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
hb_glyph_extents_t *extents) const
{
switch (format)
{
case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
default:return false;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this) || version.major != 1))
return_trace (false);
switch (format)
{
case 0: return_trace (u.format0.sanitize (c, this));
case 1: return_trace (u.format1.sanitize (c, this));
default:return_trace (true);
}
}
protected:
FixedVersion<>version; /* Version number of the optical bounds
* table (0x00010000 for the current version). */
HBUINT16 format; /* Format of the optical bounds table.
* Format 0 indicates distance and Format 1 indicates
* control point. */
union {
opbdFormat0 format0;
opbdFormat1 format1;
} u;
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */

View File

@ -0,0 +1,230 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
#define HB_AAT_LAYOUT_TRAK_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
/*
* trak -- Tracking
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
*/
#define HB_AAT_TAG_trak HB_TAG('t','r','a','k')
namespace AAT {
struct TrackTableEntry
{
friend struct TrackData;
float get_track_value () const { return track.to_float (); }
int get_value (const void *base, unsigned int index,
unsigned int table_size) const
{ return (base+valuesZ).as_array (table_size)[index]; }
public:
bool sanitize (hb_sanitize_context_t *c, const void *base,
unsigned int table_size) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(valuesZ.sanitize (c, base, table_size))));
}
protected:
HBFixed track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
NNOffsetTo<UnsizedArrayOf<FWORD>>
valuesZ; /* Offset from start of tracking table to
* per-size tracking values for this track. */
public:
DEFINE_SIZE_STATIC (8);
};
struct TrackData
{
float interpolate_at (unsigned int idx,
float target_size,
const TrackTableEntry &trackTableEntry,
const void *base) const
{
unsigned int sizes = nSizes;
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
return t * trackTableEntry.get_value (base, idx + 1, sizes) +
(1.f - t) * trackTableEntry.get_value (base, idx, sizes);
}
int get_tracking (const void *base, float ptem) const
{
/*
* Choose track.
*/
const TrackTableEntry *trackTableEntry = nullptr;
unsigned int count = nTracks;
for (unsigned int i = 0; i < count; i++)
{
/* Note: Seems like the track entries are sorted by values. But the
* spec doesn't explicitly say that. It just mentions it in the example. */
/* For now we only seek for track entries with zero tracking value */
if (trackTable[i].get_track_value () == 0.f)
{
trackTableEntry = &trackTable[i];
break;
}
}
if (!trackTableEntry) return 0.;
/*
* Choose size.
*/
unsigned int sizes = nSizes;
if (!sizes) return 0.;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= ptem)
break;
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
*trackTableEntry, base));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
sizeTable.sanitize (c, base, nSizes) &&
trackTable.sanitize (c, nTracks, base, nSizes)));
}
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
LNNOffsetTo<UnsizedArrayOf<HBFixed>>
sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry>
trackTable; /* Array[nTracks] of TrackTableEntry records. */
public:
DEFINE_SIZE_ARRAY (8, trackTable);
};
struct trak
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
bool has_data () const { return version.to_int (); }
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_mask_t trak_mask = c->plan->trak_mask;
const float ptem = c->font->ptem;
if (unlikely (ptem <= 0.f))
return_trace (false);
hb_buffer_t *buffer = c->buffer;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
const TrackData &trackData = this+horizData;
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
foreach_grapheme (buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[start].x_offset += offset_to_add;
}
}
else
{
const TrackData &trackData = this+vertData;
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
foreach_grapheme (buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[start].y_offset += offset_to_add;
}
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
}
protected:
FixedVersion<>version; /* Version of the tracking table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the tracking table (set to 0). */
OffsetTo<TrackData>
horizData; /* Offset from start of tracking table to TrackData
* for horizontal text (or 0 if none). */
OffsetTo<TrackData>
vertData; /* Offset from start of tracking table to TrackData
* for vertical text (or 0 if none). */
HBUINT16 reserved; /* Reserved. Set to 0. */
public:
DEFINE_SIZE_STATIC (12);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_TRAK_TABLE_HH */

382
thirdparty/harfbuzz/src/hb-aat-layout.cc vendored Normal file
View File

@ -0,0 +1,382 @@
/*
* Copyright © 2017 Google, Inc.
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-aat-layout.hh"
#include "hb-aat-layout-ankr-table.hh"
#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-feat-table.hh"
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-ltag-table.hh"
/*
* hb_aat_apply_context_t
*/
/* Note: This context is used for kerning, even without AAT, hence the condition. */
#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob) :
plan (plan_),
font (font_),
face (font->face),
buffer (buffer_),
sanitizer (),
ankr_table (&Null (AAT::ankr)),
lookup_index (0)
{
sanitizer.init (blob);
sanitizer.set_num_glyphs (face->get_num_glyphs ());
sanitizer.start_processing ();
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
}
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
{ sanitizer.end_processing (); }
void
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
{ ankr_table = ankr_table_; }
#endif
/**
* SECTION:hb-aat-layout
* @title: hb-aat-layout
* @short_description: Apple Advanced Typography Layout
* @include: hb-aat.h
*
* Functions for querying OpenType Layout features in the font face.
**/
#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
/* Table data courtesy of Apple. Converted from mnemonics to integers
* when moving to this file. */
static const hb_aat_feature_mapping_t feature_mappings[] =
{
{HB_TAG ('a','f','r','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG ('c','2','p','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
{HB_TAG ('c','2','s','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
{HB_TAG ('c','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF},
{HB_TAG ('c','a','s','e'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF},
{HB_TAG ('c','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF},
{HB_TAG ('c','p','s','p'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF},
{HB_TAG ('c','s','w','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF},
{HB_TAG ('d','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF},
{HB_TAG ('e','x','p','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('f','r','a','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG ('f','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('h','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('h','i','s','t'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG ('h','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF},
{HB_TAG ('h','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG ('h','n','g','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION},
{HB_TAG ('h','o','j','o'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('h','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('i','t','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF},
{HB_TAG ('j','p','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('j','p','7','8'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('j','p','8','3'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('j','p','9','0'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('l','i','g','a'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF},
{HB_TAG ('l','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2},
{HB_TAG ('m','g','r','k'), HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF},
{HB_TAG ('n','l','c','k'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('o','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2},
{HB_TAG ('o','r','d','n'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('p','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('p','c','a','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
{HB_TAG ('p','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
{HB_TAG ('s','m','p','l'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('s','s','0','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF},
{HB_TAG ('s','s','0','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF},
{HB_TAG ('s','s','0','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF},
{HB_TAG ('s','s','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF},
{HB_TAG ('s','s','0','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF},
{HB_TAG ('s','s','0','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF},
{HB_TAG ('s','s','0','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF},
{HB_TAG ('s','s','0','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF},
{HB_TAG ('s','s','0','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF},
{HB_TAG ('s','s','1','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF},
{HB_TAG ('s','s','1','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF},
{HB_TAG ('s','s','1','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF},
{HB_TAG ('s','s','1','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF},
{HB_TAG ('s','s','1','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF},
{HB_TAG ('s','s','1','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF},
{HB_TAG ('s','s','1','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF},
{HB_TAG ('s','s','1','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF},
{HB_TAG ('s','s','1','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF},
{HB_TAG ('s','s','1','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF},
{HB_TAG ('s','s','2','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF},
{HB_TAG ('s','u','b','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','u','p','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','w','s','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF},
{HB_TAG ('t','i','t','l'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS},
{HB_TAG ('t','n','a','m'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('t','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('t','r','a','d'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('t','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('u','n','i','c'), HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE, (hb_aat_layout_feature_selector_t) 14, (hb_aat_layout_feature_selector_t) 15},
{HB_TAG ('v','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','e','r','t'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
{HB_TAG ('v','h','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF},
{HB_TAG ('v','p','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','r','t','2'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
{HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
};
const hb_aat_feature_mapping_t *
hb_aat_layout_find_feature_mapping (hb_tag_t tag)
{
return hb_sorted_array (feature_mappings).bsearch (tag);
}
#endif
#ifndef HB_NO_AAT
/*
* mort/morx/kerx/trak
*/
void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map)
{
const AAT::morx& morx = *mapper->face->table.morx;
if (morx.has_data ())
{
morx.compile_flags (mapper, map);
return;
}
const AAT::mort& mort = *mapper->face->table.mort;
if (mort.has_data ())
{
mort.compile_flags (mapper, map);
return;
}
}
/*
* hb_aat_layout_has_substitution:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t
hb_aat_layout_has_substitution (hb_face_t *face)
{
return face->table.morx->has_data () ||
face->table.mort->has_data ();
}
void
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
if (morx.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
morx.apply (&c);
return;
}
hb_blob_t *mort_blob = font->face->table.mort.get_blob ();
const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
if (mort.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
mort.apply (&c);
return;
}
}
void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++)
if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
static bool
is_deleted_glyph (const hb_glyph_info_t *info)
{
return info->codepoint == AAT::DELETED_GLYPH;
}
void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
{
hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
}
/*
* hb_aat_layout_has_positioning:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t
hb_aat_layout_has_positioning (hb_face_t *face)
{
return face->table.kerx->has_data ();
}
void
hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
c.set_ankr_table (font->face->table.ankr.get ());
kerx.apply (&c);
}
/*
* hb_aat_layout_has_tracking:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t
hb_aat_layout_has_tracking (hb_face_t *face)
{
return face->table.trak->has_data ();
}
void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const AAT::trak& trak = *font->face->table.trak;
AAT::hb_aat_apply_context_t c (plan, font, buffer);
trak.apply (&c);
}
/**
* hb_aat_layout_get_feature_types:
* @face: a face object
* @start_offset: iteration's start offset
* @feature_count:(inout) (allow-none): buffer size as input, filled size as output
* @features: (out caller-allocates) (array length=feature_count): features buffer
*
* Return value: Number of all available feature types.
*
* Since: 2.2.0
*/
unsigned int
hb_aat_layout_get_feature_types (hb_face_t *face,
unsigned int start_offset,
unsigned int *feature_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */)
{
return face->table.feat->get_feature_types (start_offset, feature_count, features);
}
/**
* hb_aat_layout_feature_type_get_name_id:
* @face: a face object
* @feature_type: feature id
*
* Return value: Name ID index
*
* Since: 2.2.0
*/
hb_ot_name_id_t
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type)
{
return face->table.feat->get_feature_name_id (feature_type);
}
/**
* hb_aat_layout_feature_type_get_selectors:
* @face: a face object
* @feature_type: feature id
* @start_offset: iteration's start offset
* @selector_count: (inout) (allow-none): buffer size as input, filled size as output
* @selectors: (out caller-allocates) (array length=selector_count): settings buffer
* @default_index: (out) (allow-none): index of default selector if any
*
* If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then
* the feature type is non-exclusive. Otherwise, @default_index is the index of
* the selector that is selected by default.
*
* Return value: Number of all available feature selectors.
*
* Since: 2.2.0
*/
unsigned int
hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selector_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */)
{
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
}
#endif

486
thirdparty/harfbuzz/src/hb-aat-layout.h vendored Normal file
View File

@ -0,0 +1,486 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_H_IN
#error "Include <hb-aat.h> instead."
#endif
#ifndef HB_AAT_LAYOUT_H
#define HB_AAT_LAYOUT_H
#include "hb.h"
#include "hb-ot.h"
HB_BEGIN_DECLS
/**
* hb_aat_layout_feature_type_t:
*
*
* Since: 2.2.0
*/
typedef enum
{
HB_AAT_LAYOUT_FEATURE_TYPE_INVALID = 0xFFFF,
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2,
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING = 6,
HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE = 8,
HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE = 9,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION = 10,
HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS = 11,
HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE = 13,
HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS = 14,
HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS = 15,
HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE = 16,
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES = 17,
HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE = 18,
HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS = 19,
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE = 20,
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE = 21,
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING = 22,
HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION = 23,
HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE = 24,
HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE = 25,
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE = 26,
HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE = 27,
HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA = 28,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE = 29,
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE = 30,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE = 31,
HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN = 32,
HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT = 33,
HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA = 34,
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES = 35,
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES = 36,
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE = 37,
HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE = 38,
HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103,
_HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_aat_layout_feature_type_t;
/**
* hb_aat_layout_feature_selector_t:
*
*
* Since: 2.2.0
*/
typedef enum
{
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID = 0xFFFF,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON = 14,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF = 15,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON = 16,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF = 17,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON = 18,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF = 19,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON = 20,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF = 21,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE = 0, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS = 1, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE = 2, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS = 3, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS = 4, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS = 5, /* deprecated */
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT */
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING */
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF = 9,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS = 4,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF = 11,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF = 11,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS = 6,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES = 0,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1 = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2 = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3 = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4 = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5 = 4,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS = 14,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING */
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT = 6,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE = 9,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION= 10,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON = 14,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF = 15,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON = 16,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF = 17,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON = 18,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF = 19,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON = 20,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF = 21,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON = 22,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF = 23,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON = 24,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF = 25,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON = 26,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF = 27,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON = 28,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF = 29,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON = 30,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF = 31,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON = 32,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF = 33,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON = 34,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF = 35,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON = 36,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF = 37,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON = 38,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF = 39,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON = 40,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF = 41,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF= 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3,
_HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_aat_layout_feature_selector_t;
HB_EXTERN unsigned int
hb_aat_layout_get_feature_types (hb_face_t *face,
unsigned int start_offset,
unsigned int *feature_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */);
HB_EXTERN hb_ot_name_id_t
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type);
typedef struct hb_aat_layout_feature_selector_info_t
{
hb_ot_name_id_t name_id;
hb_aat_layout_feature_selector_t enable;
hb_aat_layout_feature_selector_t disable;
/*< private >*/
unsigned int reserved;
} hb_aat_layout_feature_selector_info_t;
#define HB_AAT_LAYOUT_NO_SELECTOR_INDEX 0xFFFFu
HB_EXTERN unsigned int
hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selector_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */);
/*
* morx/mort
*/
HB_EXTERN hb_bool_t
hb_aat_layout_has_substitution (hb_face_t *face);
/*
* kerx
*/
HB_EXTERN hb_bool_t
hb_aat_layout_has_positioning (hb_face_t *face);
/*
* trak
*/
HB_EXTERN hb_bool_t
hb_aat_layout_has_tracking (hb_face_t *face);
HB_END_DECLS
#endif /* HB_AAT_LAYOUT_H */

View File

@ -0,0 +1,75 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_HH
#define HB_AAT_LAYOUT_HH
#include "hb.hh"
#include "hb-ot-shape.hh"
#include "hb-aat-ltag-table.hh"
struct hb_aat_feature_mapping_t
{
hb_tag_t otFeatureTag;
hb_aat_layout_feature_type_t aatFeatureType;
hb_aat_layout_feature_selector_t selectorToEnable;
hb_aat_layout_feature_selector_t selectorToDisable;
int cmp (hb_tag_t key) const
{ return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; }
};
HB_INTERNAL const hb_aat_feature_mapping_t *
hb_aat_layout_find_feature_mapping (hb_tag_t tag);
HB_INTERNAL void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map);
HB_INTERNAL void
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_HH */

View File

@ -0,0 +1,92 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LTAG_TABLE_HH
#define HB_AAT_LTAG_TABLE_HH
#include "hb-open-type.hh"
/*
* ltag -- Language Tag
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ltag.html
*/
#define HB_AAT_TAG_ltag HB_TAG('l','t','a','g')
namespace AAT {
using namespace OT;
struct FTStringRange
{
friend struct ltag;
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && (base+tag).sanitize (c, length));
}
protected:
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
tag; /* Offset from the start of the table to
* the beginning of the string */
HBUINT16 length; /* String length (in bytes) */
public:
DEFINE_SIZE_STATIC (4);
};
struct ltag
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
hb_language_t get_language (unsigned int i) const
{
const FTStringRange &range = tagRanges[i];
return hb_language_from_string ((const char *) (this+range.tag).arrayZ,
range.length);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version >= 1 &&
tagRanges.sanitize (c, this)));
}
protected:
HBUINT32 version; /* Table version; currently 1 */
HBUINT32 flags; /* Table flags; currently none defined */
LArrayOf<FTStringRange>
tagRanges; /* Range for each tag's string */
public:
DEFINE_SIZE_ARRAY (12, tagRanges);
};
} /* namespace AAT */
#endif /* HB_AAT_LTAG_TABLE_HH */

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