Merge branch 'master' into cff-subset
This commit is contained in:
commit
22b88632d5
157
m4/pkg.m4
157
m4/pkg.m4
|
@ -1,157 +0,0 @@
|
|||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of 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 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
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
|
||||
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
|
||||
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||||
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
_pkg_min_version=m4_default([$1], [0.9.0])
|
||||
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
#
|
||||
# Similar to PKG_CHECK_MODULES, make sure that the first instance of
|
||||
# this or PKG_CHECK_MODULES is called, or make sure to call
|
||||
# PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
|
||||
m4_ifval([$2], [$2], [:])
|
||||
m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$PKG_CONFIG"; then
|
||||
if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
else
|
||||
PKG_CHECK_EXISTS([$3],
|
||||
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
|
||||
[pkg_failed=yes])
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||
|
||||
pkg_failed=no
|
||||
AC_MSG_CHECKING([for $1])
|
||||
|
||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||
|
||||
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
|
||||
and $1[]_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.])
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
_PKG_SHORT_ERRORS_SUPPORTED
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
|
||||
else
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
|
||||
|
||||
ifelse([$4], , [AC_MSG_ERROR(dnl
|
||||
[Package requirements ($2) were not met:
|
||||
|
||||
$$1_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
_PKG_TEXT
|
||||
])],
|
||||
[AC_MSG_RESULT([no])
|
||||
$4])
|
||||
elif test $pkg_failed = untried; then
|
||||
ifelse([$4], , [AC_MSG_FAILURE(dnl
|
||||
[The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
_PKG_TEXT
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
|
||||
[$4])
|
||||
else
|
||||
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
|
||||
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
|
||||
AC_MSG_RESULT([yes])
|
||||
ifelse([$3], , :, [$3])
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
|
@ -226,6 +226,7 @@ HB_SUBSET_sources = \
|
|||
hb-subset-cff-common.cc \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-subset-input.cc \
|
||||
hb-subset-input.hh \
|
||||
hb-subset-plan.cc \
|
||||
hb-subset-plan.hh \
|
||||
$(NULL)
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "hb-blob.hh"
|
||||
|
||||
#include "hb-iter.hh"
|
||||
#include "hb-vector.hh"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -111,9 +112,13 @@ static inline Type& StructAfter(TObject &X)
|
|||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY(size, array) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \
|
||||
DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
|
||||
static const unsigned int min_size = (size)
|
||||
static const unsigned int min_size = (size); \
|
||||
|
||||
#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
|
||||
DEFINE_SIZE_ARRAY(size, array); \
|
||||
inline unsigned int get_size (void) const { return (size - array[0].min_size + array.get_size ()); }
|
||||
|
||||
#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
|
||||
|
@ -437,12 +442,19 @@ struct hb_serialize_context_t
|
|||
{
|
||||
this->start = (char *) start_;
|
||||
this->end = this->start + size;
|
||||
reset ();
|
||||
}
|
||||
|
||||
inline void reset (void)
|
||||
{
|
||||
this->ran_out_of_room = false;
|
||||
this->head = this->start;
|
||||
this->debug_depth = 0;
|
||||
}
|
||||
|
||||
inline bool err (bool e) { return this->ran_out_of_room = this->ran_out_of_room || e; }
|
||||
|
||||
/* To be called around main operation. */
|
||||
template <typename Type>
|
||||
inline Type *start_serialize (void)
|
||||
{
|
||||
|
@ -453,7 +465,6 @@ struct hb_serialize_context_t
|
|||
|
||||
return start_embed<Type> ();
|
||||
}
|
||||
|
||||
inline void end_serialize (void)
|
||||
{
|
||||
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
|
||||
|
@ -463,6 +474,70 @@ struct hb_serialize_context_t
|
|||
this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
|
||||
}
|
||||
|
||||
inline unsigned int length (void) const { return this->head - this->start; }
|
||||
|
||||
inline void align (unsigned int alignment)
|
||||
{
|
||||
unsigned int l = length () % alignment;
|
||||
if (l)
|
||||
allocate_size<void> (alignment - l);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *start_embed (void) const
|
||||
{
|
||||
Type *ret = reinterpret_cast<Type *> (this->head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_size (unsigned int size)
|
||||
{
|
||||
if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
|
||||
this->ran_out_of_room = true;
|
||||
return nullptr;
|
||||
}
|
||||
memset (this->head, 0, size);
|
||||
char *ret = this->head;
|
||||
this->head += size;
|
||||
return reinterpret_cast<Type *> (ret);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_min (void)
|
||||
{
|
||||
return this->allocate_size<Type> (Type::min_size);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *embed (const Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
Type *ret = this->allocate_size<Type> (size);
|
||||
if (unlikely (!ret)) return nullptr;
|
||||
memcpy (ret, &obj, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *extend_min (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.min_size;
|
||||
assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *extend (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
/* Output routines. */
|
||||
template <typename Type>
|
||||
inline Type *copy (void) const
|
||||
{
|
||||
|
@ -493,60 +568,7 @@ struct hb_serialize_context_t
|
|||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_size (unsigned int size)
|
||||
{
|
||||
if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
|
||||
this->ran_out_of_room = true;
|
||||
return nullptr;
|
||||
}
|
||||
memset (this->head, 0, size);
|
||||
char *ret = this->head;
|
||||
this->head += size;
|
||||
return reinterpret_cast<Type *> (ret);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_min (void)
|
||||
{
|
||||
return this->allocate_size<Type> (Type::min_size);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *start_embed (void)
|
||||
{
|
||||
Type *ret = reinterpret_cast<Type *> (this->head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *embed (const Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
Type *ret = this->allocate_size<Type> (size);
|
||||
if (unlikely (!ret)) return nullptr;
|
||||
memcpy (ret, obj, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *extend_min (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.min_size;
|
||||
assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *extend (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int debug_depth;
|
||||
char *start, *end, *head;
|
||||
bool ran_out_of_room;
|
||||
|
@ -566,6 +588,13 @@ struct Supplier
|
|||
len = len_;
|
||||
stride = stride_;
|
||||
}
|
||||
inline Supplier (const hb_vector_t<Type> *v)
|
||||
{
|
||||
head = v->arrayZ;
|
||||
len = v->len;
|
||||
stride = sizeof (Type);
|
||||
}
|
||||
|
||||
inline const Type operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len)) return Type ();
|
||||
|
|
|
@ -73,6 +73,19 @@ static_assert (true, "Just so we take semicolon after.")
|
|||
#define DEFINE_NULL_INSTANCE(Type) \
|
||||
const Type _hb_Null_##Type
|
||||
|
||||
/* Specializaiton to disallow Null objects. */
|
||||
#define DECLARE_NULL_DISALLOW(Type) \
|
||||
template <> inline const Type& Null<Type> (void)
|
||||
#define DECLARE_NULL_NAMSPACE_DISALLOW(Namespace, Type) \
|
||||
} /* Close namespace. */ \
|
||||
template <> \
|
||||
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
|
||||
extern void *_hb_undefined; \
|
||||
return *reinterpret_cast<const Namespace::Type *> (_hb_undefined); \
|
||||
} \
|
||||
namespace Namespace { \
|
||||
static_assert (true, "Just so we take semicolon after.")
|
||||
|
||||
/* Global writable pool. Enlarge as necessary. */
|
||||
|
||||
/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
|
||||
|
|
|
@ -161,8 +161,7 @@ typedef struct OffsetTable
|
|||
memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
|
||||
|
||||
/* 4-byte allignment. */
|
||||
if (rec.length % 4)
|
||||
c->allocate_size<void> (4 - rec.length % 4);
|
||||
c->align (4);
|
||||
const char *end = (const char *) c->head;
|
||||
|
||||
if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size)
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "hb-blob.hh"
|
||||
#include "hb-face.hh"
|
||||
#include "hb-machinery.hh"
|
||||
#include "hb-subset.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
@ -246,6 +247,19 @@ struct OffsetTo : Offset<OffsetType>
|
|||
return * (Type *) Offset<OffsetType>::serialize (c, base);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
|
||||
{
|
||||
if (&src == &Null(T))
|
||||
{
|
||||
this->set (0);
|
||||
return;
|
||||
}
|
||||
serialize (c->serializer, base);
|
||||
if (!src.subset (c))
|
||||
this->set (0);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -404,7 +418,6 @@ struct ArrayOf
|
|||
if (unlikely (!c->extend (*this))) return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
Supplier<Type> &items,
|
||||
unsigned int items_len)
|
||||
|
@ -505,6 +518,17 @@ struct OffsetListOf : OffsetArrayOf<Type>
|
|||
return this+this->arrayZ[i];
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct OffsetListOf<Type> *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->arrayZ[i].serialize_subset (c, (*this)[i], out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-set.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
/*
|
||||
* cmap -- Character to Glyph Index Mapping
|
||||
|
@ -48,7 +47,7 @@ struct CmapSubtableFormat0
|
|||
if (!gid)
|
||||
return false;
|
||||
*glyph = gid;
|
||||
return *glyph != 0;
|
||||
return true;
|
||||
}
|
||||
inline void collect_unicodes (hb_set_t *out) const
|
||||
{
|
||||
|
@ -279,9 +278,11 @@ struct CmapSubtableFormat4
|
|||
return false;
|
||||
gid += this->idDelta[i];
|
||||
}
|
||||
|
||||
*glyph = gid & 0xFFFFu;
|
||||
return *glyph != 0;
|
||||
gid &= 0xFFFFu;
|
||||
if (!gid)
|
||||
return false;
|
||||
*glyph = gid;
|
||||
return true;
|
||||
}
|
||||
static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
|
||||
{
|
||||
|
@ -423,7 +424,7 @@ struct CmapSubtableTrimmed
|
|||
if (!gid)
|
||||
return false;
|
||||
*glyph = gid;
|
||||
return *glyph != 0;
|
||||
return true;
|
||||
}
|
||||
inline void collect_unicodes (hb_set_t *out) const
|
||||
{
|
||||
|
@ -465,8 +466,11 @@ struct CmapSubtableLongSegmented
|
|||
int i = groups.bsearch (codepoint);
|
||||
if (i == -1)
|
||||
return false;
|
||||
*glyph = T::group_get_glyph (groups[i], codepoint);
|
||||
return *glyph != 0;
|
||||
hb_codepoint_t gid = T::group_get_glyph (groups[i], codepoint);
|
||||
if (!gid)
|
||||
return false;
|
||||
*glyph = gid;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void collect_unicodes (hb_set_t *out) const
|
||||
|
@ -674,7 +678,7 @@ struct VariationSelectorRecord
|
|||
return GLYPH_VARIANT_USE_DEFAULT;
|
||||
const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
|
||||
i = nonDefaults.bsearch (codepoint);
|
||||
if (i != -1)
|
||||
if (i != -1 && nonDefaults[i].glyphID)
|
||||
{
|
||||
*glyph = nonDefaults[i].glyphID;
|
||||
return GLYPH_VARIANT_FOUND;
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-subset-glyf.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
#include "hb-subset.hh"
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_OT_HDMX_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
/*
|
||||
* hdmx -- Horizontal Device Metrics
|
||||
|
@ -89,8 +88,13 @@ struct DeviceRecord
|
|||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (unlikely (!c->allocate_size<DeviceRecord> (get_size (subset_view.len()))))
|
||||
unsigned int size = get_size (subset_view.len());
|
||||
if (unlikely (!c->allocate_size<DeviceRecord> (size)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
|
||||
size);
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
this->pixel_size.set (subset_view.source_device_record->pixel_size);
|
||||
this->max_width.set (subset_view.source_device_record->max_width);
|
||||
|
@ -161,14 +165,14 @@ struct hdmx
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
static inline size_t get_subsetted_size (hb_subset_plan_t *plan)
|
||||
static inline size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
||||
{
|
||||
return min_size + DeviceRecord::get_size (plan->glyphs.len);
|
||||
return min_size + source_hdmx->num_records * DeviceRecord::get_size (plan->glyphs.len);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
size_t dest_size = get_subsetted_size (plan);
|
||||
size_t dest_size = get_subsetted_size (this, plan);
|
||||
hdmx *dest = (hdmx *) malloc (dest_size);
|
||||
if (unlikely (!dest))
|
||||
{
|
||||
|
@ -178,8 +182,10 @@ struct hdmx
|
|||
|
||||
hb_serialize_context_t c (dest, dest_size);
|
||||
hdmx *hdmx_prime = c.start_serialize<hdmx> ();
|
||||
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) {
|
||||
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
|
||||
{
|
||||
free (dest);
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
|
||||
return false;
|
||||
}
|
||||
c.end_serialize ();
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "hb-ot-hhea-table.hh"
|
||||
#include "hb-ot-os2-table.hh"
|
||||
#include "hb-ot-var-hvar-table.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
/*
|
||||
* hmtx -- Horizontal Metrics
|
||||
|
|
|
@ -97,15 +97,14 @@ struct Record
|
|||
};
|
||||
|
||||
template <typename Type>
|
||||
struct RecordArrayOf : SortedArrayOf<Record<Type> > {
|
||||
inline const Tag& get_tag (unsigned int i) const
|
||||
struct RecordArrayOf : SortedArrayOf<Record<Type> >
|
||||
{
|
||||
/* We cheat slightly and don't define separate Null objects
|
||||
* for Record types. Instead, we return the correct Null(Tag)
|
||||
* here. */
|
||||
if (unlikely (i >= this->len)) return Null(Tag);
|
||||
return (*this)[i].tag;
|
||||
}
|
||||
inline const OffsetTo<Type>& get_offset (unsigned int i) const
|
||||
{ return (*this)[i].offset; }
|
||||
inline OffsetTo<Type>& get_offset (unsigned int i)
|
||||
{ return (*this)[i].offset; }
|
||||
inline const Tag& get_tag (unsigned int i) const
|
||||
{ return (*this)[i].tag; }
|
||||
inline unsigned int get_tags (unsigned int start_offset,
|
||||
unsigned int *record_count /* IN/OUT */,
|
||||
hb_tag_t *record_tags /* OUT */) const
|
||||
|
@ -136,7 +135,18 @@ template <typename Type>
|
|||
struct RecordListOf : RecordArrayOf<Type>
|
||||
{
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{ return this+RecordArrayOf<Type>::operator [](i).offset; }
|
||||
{ return this+this->get_offset (i); }
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct RecordListOf<Type> *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->get_offset (i).serialize_subset (c, (*this)[i], out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
|
@ -158,9 +168,8 @@ struct RangeRecord
|
|||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
inline bool intersects (const hb_set_t *glyphs) const {
|
||||
return glyphs->intersects (start, end);
|
||||
}
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return glyphs->intersects (start, end); }
|
||||
|
||||
template <typename set_t>
|
||||
inline bool add_coverage (set_t *glyphs) const {
|
||||
|
@ -224,6 +233,12 @@ struct LangSys
|
|||
return reqFeatureIndex;;
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (c->serializer->embed (*this));
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c,
|
||||
const Record<LangSys>::sanitize_closure_t * = nullptr) const
|
||||
{
|
||||
|
@ -238,7 +253,7 @@ struct LangSys
|
|||
* = 0xFFFFu */
|
||||
IndexArray featureIndex; /* Array of indices into the FeatureList */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (6, featureIndex);
|
||||
DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
|
||||
};
|
||||
DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
|
||||
|
||||
|
@ -263,6 +278,18 @@ struct Script
|
|||
inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
|
||||
inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct Script *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
|
||||
unsigned int count = langSys.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c,
|
||||
const Record<Script>::sanitize_closure_t * = nullptr) const
|
||||
{
|
||||
|
@ -278,7 +305,7 @@ struct Script
|
|||
langSys; /* Array of LangSysRecords--listed
|
||||
* alphabetically by LangSysTag */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, langSys);
|
||||
DEFINE_SIZE_ARRAY_SIZED (4, langSys);
|
||||
};
|
||||
|
||||
typedef RecordListOf<Script> ScriptList;
|
||||
|
@ -516,6 +543,15 @@ struct Feature
|
|||
inline const FeatureParams &get_feature_params (void) const
|
||||
{ return this+featureParams; }
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct Feature *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
out->featureParams.set (0); /* TODO(subset) FeatureParams. */
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c,
|
||||
const Record<Feature>::sanitize_closure_t *closure = nullptr) const
|
||||
{
|
||||
|
@ -567,7 +603,7 @@ struct Feature
|
|||
* if not required */
|
||||
IndexArray lookupIndex; /* Array of LookupList indices */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, lookupIndex);
|
||||
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
|
||||
};
|
||||
|
||||
typedef RecordListOf<Feature> FeatureList;
|
||||
|
@ -598,16 +634,16 @@ struct Lookup
|
|||
{
|
||||
inline unsigned int get_subtable_count (void) const { return subTable.len; }
|
||||
|
||||
template <typename SubTableType>
|
||||
inline const SubTableType& get_subtable (unsigned int i) const
|
||||
{ return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
|
||||
template <typename TSubTable>
|
||||
inline const TSubTable& get_subtable (unsigned int i) const
|
||||
{ return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
|
||||
|
||||
template <typename SubTableType>
|
||||
inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
|
||||
{ return CastR<OffsetArrayOf<SubTableType> > (subTable); }
|
||||
template <typename SubTableType>
|
||||
inline OffsetArrayOf<SubTableType>& get_subtables (void)
|
||||
{ return CastR<OffsetArrayOf<SubTableType> > (subTable); }
|
||||
template <typename TSubTable>
|
||||
inline const OffsetArrayOf<TSubTable>& get_subtables (void) const
|
||||
{ return CastR<OffsetArrayOf<TSubTable> > (subTable); }
|
||||
template <typename TSubTable>
|
||||
inline OffsetArrayOf<TSubTable>& get_subtables (void)
|
||||
{ return CastR<OffsetArrayOf<TSubTable> > (subTable); }
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{
|
||||
|
@ -633,14 +669,14 @@ struct Lookup
|
|||
return flag;
|
||||
}
|
||||
|
||||
template <typename SubTableType, typename context_t>
|
||||
template <typename TSubTable, typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{
|
||||
unsigned int lookup_type = get_type ();
|
||||
TRACE_DISPATCH (this, lookup_type);
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
|
||||
typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
|
||||
if (c->stop_sublookup_iteration (r))
|
||||
return_trace (r);
|
||||
}
|
||||
|
@ -666,16 +702,68 @@ struct Lookup
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename TSubTable>
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct Lookup *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
/* Subset the actual subtables. */
|
||||
/* TODO Drop empty ones, either by calling intersects() beforehand,
|
||||
* or just dropping null offsets after. */
|
||||
const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
|
||||
OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
|
||||
unsigned int count = subTable.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
struct Wrapper
|
||||
{
|
||||
inline Wrapper (const TSubTable &subtable_,
|
||||
unsigned int lookup_type_) :
|
||||
subtable (subtable_),
|
||||
lookup_type (lookup_type_) {}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{ return subtable.dispatch (c, lookup_type); }
|
||||
|
||||
private:
|
||||
const TSubTable &subtable;
|
||||
unsigned int lookup_type;
|
||||
} wrapper (this+subtables[i], get_type ());
|
||||
|
||||
out_subtables[i].serialize_subset (c, wrapper, out);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
template <typename TSubTable>
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
/* Real sanitize of the subtables is done by GSUB/GPOS/... */
|
||||
if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
|
||||
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
|
||||
{
|
||||
const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
|
||||
if (!markFilteringSet.sanitize (c)) return_trace (false);
|
||||
}
|
||||
|
||||
if (unlikely (!dispatch<TSubTable> (c))) return_trace (false);
|
||||
|
||||
if (unlikely (get_type () == TSubTable::Extension))
|
||||
{
|
||||
/* The spec says all subtables of an Extension lookup should
|
||||
* have the same type, which shall not be the Extension type
|
||||
* itself (but we already checked for that).
|
||||
* This is specially important if one has a reverse type! */
|
||||
unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
|
@ -730,9 +818,17 @@ struct CoverageFormat1
|
|||
return_trace (glyphArray.sanitize (c));
|
||||
}
|
||||
|
||||
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
|
||||
return glyphs->has (glyphArray[index]);
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
/* TODO Speed up, using hb_set_next() and bsearch()? */
|
||||
unsigned int count = glyphArray.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (glyphs->has (glyphArray[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
|
||||
{ return glyphs->has (glyphArray[index]); }
|
||||
|
||||
template <typename set_t>
|
||||
inline bool add_coverage (set_t *glyphs) const {
|
||||
|
@ -820,7 +916,17 @@ struct CoverageFormat2
|
|||
return_trace (rangeRecord.sanitize (c));
|
||||
}
|
||||
|
||||
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
/* TODO Speed up, using hb_set_next() and bsearch()? */
|
||||
unsigned int count = rangeRecord.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (rangeRecord[i].intersects (glyphs))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int count = rangeRecord.len;
|
||||
for (i = 0; i < count; i++) {
|
||||
|
@ -948,13 +1054,13 @@ struct Coverage
|
|||
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
/* TODO speed this up */
|
||||
for (hb_auto_t<Coverage::Iter> iter (*this); iter.more (); iter.next ())
|
||||
if (glyphs->has (iter.get_glyph ()))
|
||||
return true;
|
||||
return false;
|
||||
switch (u.format)
|
||||
{
|
||||
case 1: return u.format1.intersects (glyphs);
|
||||
case 2: return u.format2.intersects (glyphs);
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
|
||||
{
|
||||
switch (u.format)
|
||||
|
@ -1104,6 +1210,17 @@ struct ClassDefFormat1
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
/* TODO Speed up, using hb_set_next()? */
|
||||
hb_codepoint_t start = startGlyph;
|
||||
hb_codepoint_t end = startGlyph + classValue.len;
|
||||
for (hb_codepoint_t iter = startGlyph - 1;
|
||||
hb_set_next (glyphs, &iter) && iter < end;)
|
||||
if (classValue[iter - start])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
|
||||
unsigned int count = classValue.len;
|
||||
if (klass == 0)
|
||||
|
@ -1154,7 +1271,8 @@ struct ClassDefFormat2
|
|||
}
|
||||
|
||||
template <typename set_t>
|
||||
inline bool add_coverage (set_t *glyphs) const {
|
||||
inline bool add_coverage (set_t *glyphs) const
|
||||
{
|
||||
unsigned int count = rangeRecord.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (rangeRecord[i].value)
|
||||
|
@ -1164,7 +1282,8 @@ struct ClassDefFormat2
|
|||
}
|
||||
|
||||
template <typename set_t>
|
||||
inline bool add_class (set_t *glyphs, unsigned int klass) const {
|
||||
inline bool add_class (set_t *glyphs, unsigned int klass) const
|
||||
{
|
||||
unsigned int count = rangeRecord.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1175,7 +1294,17 @@ struct ClassDefFormat2
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
/* TODO Speed up, using hb_set_next() and bsearch()? */
|
||||
unsigned int count = rangeRecord.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (rangeRecord[i].intersects (glyphs))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
|
||||
{
|
||||
unsigned int count = rangeRecord.len;
|
||||
if (klass == 0)
|
||||
{
|
||||
|
@ -1252,6 +1381,13 @@ struct ClassDef
|
|||
}
|
||||
}
|
||||
|
||||
inline bool intersects (const hb_set_t *glyphs) const {
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.intersects (glyphs);
|
||||
case 2: return u.format2.intersects (glyphs);
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.intersects_class (glyphs, klass);
|
||||
|
@ -1635,6 +1771,12 @@ struct FeatureVariations
|
|||
return (this+record.substitutions).find_substitute (feature_index);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (c->serializer->embed (*this));
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1648,7 +1790,7 @@ struct FeatureVariations
|
|||
LArrayOf<FeatureVariationRecord>
|
||||
varRecords;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, varRecords);
|
||||
DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -387,19 +387,6 @@ struct GDEF
|
|||
inline const VariationStore &get_var_store (void) const
|
||||
{ return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (version.sanitize (c) &&
|
||||
likely (version.major == 1) &&
|
||||
glyphClassDef.sanitize (c, this) &&
|
||||
attachList.sanitize (c, this) &&
|
||||
ligCaretList.sanitize (c, this) &&
|
||||
markAttachClassDef.sanitize (c, this) &&
|
||||
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
|
||||
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
|
||||
}
|
||||
|
||||
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
|
||||
* glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
|
||||
* Not to be confused with lookup_props which is very similar. */
|
||||
|
@ -434,6 +421,26 @@ struct GDEF
|
|||
const GDEF *table;
|
||||
};
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{
|
||||
return min_size +
|
||||
(version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
|
||||
(version.to_int () >= 0x00010003u ? varStore.static_size : 0);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (version.sanitize (c) &&
|
||||
likely (version.major == 1) &&
|
||||
glyphClassDef.sanitize (c, this) &&
|
||||
attachList.sanitize (c, this) &&
|
||||
ligCaretList.sanitize (c, this) &&
|
||||
markAttachClassDef.sanitize (c, this) &&
|
||||
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
|
||||
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version of the GDEF table--currently
|
||||
* 0x00010003u */
|
||||
|
|
|
@ -459,6 +459,9 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
|
|||
|
||||
struct SinglePosFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -466,9 +469,7 @@ struct SinglePosFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -483,6 +484,13 @@ struct SinglePosFormat1
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -507,6 +515,9 @@ struct SinglePosFormat1
|
|||
|
||||
struct SinglePosFormat2
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -514,9 +525,7 @@ struct SinglePosFormat2
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -535,6 +544,13 @@ struct SinglePosFormat2
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -598,6 +614,24 @@ struct PairSet
|
|||
{
|
||||
friend struct PairPosFormat1;
|
||||
|
||||
inline bool intersects (const hb_set_t *glyphs,
|
||||
const ValueFormat *valueFormats) const
|
||||
{
|
||||
unsigned int len1 = valueFormats[0].get_len ();
|
||||
unsigned int len2 = valueFormats[1].get_len ();
|
||||
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
|
||||
|
||||
const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (glyphs->has (record->secondGlyph))
|
||||
return true;
|
||||
record = &StructAtOffset<const PairValueRecord> (record, record_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c,
|
||||
const ValueFormat *valueFormats) const
|
||||
{
|
||||
|
@ -652,7 +686,8 @@ struct PairSet
|
|||
return_trace (false);
|
||||
}
|
||||
|
||||
struct sanitize_closure_t {
|
||||
struct sanitize_closure_t
|
||||
{
|
||||
const void *base;
|
||||
const ValueFormat *valueFormats;
|
||||
unsigned int len1; /* valueFormats[0].get_len() */
|
||||
|
@ -681,6 +716,20 @@ struct PairSet
|
|||
|
||||
struct PairPosFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
unsigned int count = pairSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (glyphs->has (iter.get_glyph ()) &&
|
||||
(this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -691,9 +740,7 @@ struct PairPosFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -709,6 +756,13 @@ struct PairPosFormat1
|
|||
return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -717,7 +771,8 @@ struct PairPosFormat1
|
|||
|
||||
unsigned int len1 = valueFormat[0].get_len ();
|
||||
unsigned int len2 = valueFormat[1].get_len ();
|
||||
PairSet::sanitize_closure_t closure = {
|
||||
PairSet::sanitize_closure_t closure =
|
||||
{
|
||||
this,
|
||||
valueFormat,
|
||||
len1,
|
||||
|
@ -747,6 +802,12 @@ struct PairPosFormat1
|
|||
|
||||
struct PairPosFormat2
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
return (this+coverage).intersects (glyphs) &&
|
||||
(this+classDef2).intersects (glyphs);
|
||||
}
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -755,9 +816,7 @@ struct PairPosFormat2
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -790,6 +849,13 @@ struct PairPosFormat2
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -889,6 +955,9 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
|
|||
|
||||
struct CursivePosFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -896,9 +965,7 @@ struct CursivePosFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1001,6 +1068,13 @@ struct CursivePosFormat1
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1047,6 +1121,10 @@ typedef AnchorMatrix BaseArray; /* base-major--
|
|||
|
||||
struct MarkBasePosFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+markCoverage).intersects (glyphs) &&
|
||||
(this+baseCoverage).intersects (glyphs); }
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -1055,9 +1133,7 @@ struct MarkBasePosFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+markCoverage;
|
||||
}
|
||||
{ return this+markCoverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1099,6 +1175,13 @@ struct MarkBasePosFormat1
|
|||
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1161,6 +1244,10 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
|
|||
|
||||
struct MarkLigPosFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+markCoverage).intersects (glyphs) &&
|
||||
(this+ligatureCoverage).intersects (glyphs); }
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -1169,9 +1256,7 @@ struct MarkLigPosFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+markCoverage;
|
||||
}
|
||||
{ return this+markCoverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1216,6 +1301,13 @@ struct MarkLigPosFormat1
|
|||
return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1274,6 +1366,10 @@ typedef AnchorMatrix Mark2Array; /* mark2-major--
|
|||
|
||||
struct MarkMarkPosFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+mark1Coverage).intersects (glyphs) &&
|
||||
(this+mark2Coverage).intersects (glyphs); }
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -1282,9 +1378,7 @@ struct MarkMarkPosFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+mark1Coverage;
|
||||
}
|
||||
{ return this+mark1Coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1330,6 +1424,13 @@ struct MarkMarkPosFormat1
|
|||
return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1388,7 +1489,7 @@ struct ChainContextPos : ChainContext {};
|
|||
|
||||
struct ExtensionPos : Extension<ExtensionPos>
|
||||
{
|
||||
typedef struct PosLookupSubTable LookupSubTable;
|
||||
typedef struct PosLookupSubTable SubTable;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1400,6 +1501,7 @@ struct ExtensionPos : Extension<ExtensionPos>
|
|||
|
||||
struct PosLookupSubTable
|
||||
{
|
||||
friend struct Lookup;
|
||||
friend struct PosLookup;
|
||||
|
||||
enum Type {
|
||||
|
@ -1453,8 +1555,10 @@ struct PosLookupSubTable
|
|||
|
||||
struct PosLookup : Lookup
|
||||
{
|
||||
inline const PosLookupSubTable& get_subtable (unsigned int i) const
|
||||
{ return Lookup::get_subtable<PosLookupSubTable> (i); }
|
||||
typedef struct PosLookupSubTable SubTable;
|
||||
|
||||
inline const SubTable& get_subtable (unsigned int i) const
|
||||
{ return Lookup::get_subtable<SubTable> (i); }
|
||||
|
||||
inline bool is_reverse (void) const
|
||||
{
|
||||
|
@ -1467,6 +1571,12 @@ struct PosLookup : Lookup
|
|||
return_trace (dispatch (c));
|
||||
}
|
||||
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
hb_intersects_context_t c (glyphs);
|
||||
return dispatch (&c);
|
||||
}
|
||||
|
||||
inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
|
@ -1487,18 +1597,15 @@ struct PosLookup : Lookup
|
|||
|
||||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{ return Lookup::dispatch<PosLookupSubTable> (c); }
|
||||
{ return Lookup::dispatch<SubTable> (c); }
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{ return Lookup::subset<SubTable> (c); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!Lookup::sanitize (c))) return_trace (false);
|
||||
return_trace (dispatch (c));
|
||||
}
|
||||
{ return Lookup::sanitize<SubTable> (c); }
|
||||
};
|
||||
|
||||
typedef OffsetListOf<PosLookup> PosLookupList;
|
||||
|
||||
/*
|
||||
* GPOS -- Glyph Positioning
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
|
||||
|
@ -1515,13 +1622,11 @@ struct GPOS : GSUBGPOS
|
|||
static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
|
||||
static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{ return GSUBGPOS::subset<PosLookup> (c); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
|
||||
const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
|
||||
return_trace (list.sanitize (c, this));
|
||||
}
|
||||
{ return GSUBGPOS::sanitize<PosLookup> (c); }
|
||||
|
||||
typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
|
||||
};
|
||||
|
|
|
@ -35,8 +35,16 @@
|
|||
namespace OT {
|
||||
|
||||
|
||||
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
|
||||
Supplier<GlyphID> &glyphs,
|
||||
Supplier<GlyphID> &substitutes,
|
||||
unsigned int num_glyphs);
|
||||
|
||||
struct SingleSubstFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -64,9 +72,7 @@ struct SingleSubstFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
|
@ -101,6 +107,30 @@ struct SingleSubstFormat1
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
hb_auto_t<hb_vector_t<GlyphID> > from;
|
||||
hb_auto_t<hb_vector_t<GlyphID> > to;
|
||||
hb_codepoint_t delta = deltaGlyphID;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (!c->plan->glyphset->has (iter.get_glyph ()))
|
||||
continue;
|
||||
from.push ()->set (iter.get_glyph ());
|
||||
to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF);
|
||||
}
|
||||
c->serializer->err (from.in_error () || to.in_error ());
|
||||
|
||||
Supplier<GlyphID> from_supplier (&from);
|
||||
Supplier<GlyphID> to_supplier (&to);
|
||||
SingleSubst_serialize (c->serializer,
|
||||
from_supplier,
|
||||
to_supplier,
|
||||
from.len);
|
||||
return_trace (from.len);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -120,6 +150,9 @@ struct SingleSubstFormat1
|
|||
|
||||
struct SingleSubstFormat2
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -147,9 +180,7 @@ struct SingleSubstFormat2
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
|
@ -160,14 +191,12 @@ struct SingleSubstFormat2
|
|||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
|
||||
unsigned int index = (this+coverage).get_coverage (glyph_id);
|
||||
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||
|
||||
if (unlikely (index >= substitute.len)) return_trace (false);
|
||||
|
||||
glyph_id = substitute[index];
|
||||
c->replace_glyph (glyph_id);
|
||||
c->replace_glyph (substitute[index]);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
@ -184,6 +213,29 @@ struct SingleSubstFormat2
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
hb_auto_t<hb_vector_t<GlyphID> > from;
|
||||
hb_auto_t<hb_vector_t<GlyphID> > to;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (!c->plan->glyphset->has (iter.get_glyph ()))
|
||||
continue;
|
||||
from.push ()->set (iter.get_glyph ());
|
||||
to.push ()->set (substitute[iter.get_coverage ()]);
|
||||
}
|
||||
c->serializer->err (from.in_error () || to.in_error ());
|
||||
|
||||
Supplier<GlyphID> from_supplier (&from);
|
||||
Supplier<GlyphID> to_supplier (&to);
|
||||
SingleSubst_serialize (c->serializer,
|
||||
from_supplier,
|
||||
to_supplier,
|
||||
from.len);
|
||||
return_trace (from.len);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -251,6 +303,17 @@ struct SingleSubst
|
|||
} u;
|
||||
};
|
||||
|
||||
static inline void
|
||||
SingleSubst_serialize (hb_serialize_context_t *c,
|
||||
Supplier<GlyphID> &glyphs,
|
||||
Supplier<GlyphID> &substitutes,
|
||||
unsigned int num_glyphs)
|
||||
{
|
||||
c->start_embed<SingleSubst> ()->serialize (c,
|
||||
glyphs,
|
||||
substitutes,
|
||||
num_glyphs);
|
||||
}
|
||||
|
||||
struct Sequence
|
||||
{
|
||||
|
@ -325,6 +388,9 @@ struct Sequence
|
|||
|
||||
struct MultipleSubstFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -348,9 +414,7 @@ struct MultipleSubstFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
|
@ -386,6 +450,13 @@ struct MultipleSubstFormat1
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -440,12 +511,72 @@ struct MultipleSubst
|
|||
} u;
|
||||
};
|
||||
|
||||
struct AlternateSet
|
||||
{
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
unsigned int count = alternates.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
c->out->add (alternates[i]);
|
||||
}
|
||||
|
||||
typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
{
|
||||
TRACE_COLLECT_GLYPHS (this);
|
||||
c->output->add_array (alternates.arrayZ, alternates.len);
|
||||
}
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
unsigned int count = alternates.len;
|
||||
|
||||
if (unlikely (!count)) return_trace (false);
|
||||
|
||||
hb_mask_t glyph_mask = c->buffer->cur().mask;
|
||||
hb_mask_t lookup_mask = c->lookup_mask;
|
||||
|
||||
/* Note: This breaks badly if two features enabled this lookup together. */
|
||||
unsigned int shift = hb_ctz (lookup_mask);
|
||||
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
|
||||
|
||||
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
|
||||
|
||||
c->replace_glyph (alternates[alt_index - 1]);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
Supplier<GlyphID> &glyphs,
|
||||
unsigned int num_glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (alternates.sanitize (c));
|
||||
}
|
||||
|
||||
protected:
|
||||
ArrayOf<GlyphID>
|
||||
alternates; /* Array of alternate GlyphIDs--in
|
||||
* arbitrary order */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, alternates);
|
||||
};
|
||||
|
||||
struct AlternateSubstFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{ return (this+coverage).intersects (glyphs); }
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -454,12 +585,8 @@ struct AlternateSubstFormat1
|
|||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (c->glyphs->has (iter.get_glyph ())) {
|
||||
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
|
||||
unsigned int count = alt_set.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
c->out->add (alt_set[i]);
|
||||
}
|
||||
if (c->glyphs->has (iter.get_glyph ()))
|
||||
(this+alternateSet[iter.get_coverage ()]).closure (c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,15 +599,12 @@ struct AlternateSubstFormat1
|
|||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
|
||||
c->output->add_array (alt_set.arrayZ, alt_set.len);
|
||||
(this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
|
||||
}
|
||||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
|
@ -491,29 +615,11 @@ struct AlternateSubstFormat1
|
|||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
|
||||
|
||||
unsigned int index = (this+coverage).get_coverage (glyph_id);
|
||||
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||
|
||||
const AlternateSet &alt_set = this+alternateSet[index];
|
||||
|
||||
if (unlikely (!alt_set.len)) return_trace (false);
|
||||
|
||||
hb_mask_t glyph_mask = c->buffer->cur().mask;
|
||||
hb_mask_t lookup_mask = c->lookup_mask;
|
||||
|
||||
/* Note: This breaks badly if two features enabled this lookup together. */
|
||||
unsigned int shift = hb_ctz (lookup_mask);
|
||||
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
|
||||
|
||||
if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
|
||||
|
||||
glyph_id = alt_set[alt_index - 1];
|
||||
|
||||
c->replace_glyph (glyph_id);
|
||||
|
||||
return_trace (true);
|
||||
return_trace ((this+alternateSet[index]).apply (c));
|
||||
}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
|
@ -534,6 +640,13 @@ struct AlternateSubstFormat1
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -591,6 +704,15 @@ struct AlternateSubst
|
|||
|
||||
struct Ligature
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
unsigned int count = component.len;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (!glyphs->has (component[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -694,6 +816,15 @@ struct Ligature
|
|||
|
||||
struct LigatureSet
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
unsigned int num_ligs = ligature.len;
|
||||
for (unsigned int i = 0; i < num_ligs; i++)
|
||||
if ((this+ligature[i]).intersects (glyphs))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -771,6 +902,20 @@ struct LigatureSet
|
|||
|
||||
struct LigatureSubstFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
unsigned int count = ligatureSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (glyphs->has (iter.get_glyph ()) &&
|
||||
(this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -798,9 +943,7 @@ struct LigatureSubstFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
|
@ -815,9 +958,8 @@ struct LigatureSubstFormat1
|
|||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
|
||||
|
||||
unsigned int index = (this+coverage).get_coverage (glyph_id);
|
||||
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||
|
||||
const LigatureSet &lig_set = this+ligatureSet[index];
|
||||
|
@ -846,6 +988,13 @@ struct LigatureSubstFormat1
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -915,7 +1064,7 @@ struct ChainContextSubst : ChainContext {};
|
|||
|
||||
struct ExtensionSubst : Extension<ExtensionSubst>
|
||||
{
|
||||
typedef struct SubstLookupSubTable LookupSubTable;
|
||||
typedef struct SubstLookupSubTable SubTable;
|
||||
|
||||
inline bool is_reverse (void) const;
|
||||
};
|
||||
|
@ -923,6 +1072,28 @@ struct ExtensionSubst : Extension<ExtensionSubst>
|
|||
|
||||
struct ReverseChainSingleSubstFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
if (!(this+coverage).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
|
||||
unsigned int count;
|
||||
|
||||
count = backtrack.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!(this+backtrack[i]).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
count = lookahead.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!(this+lookahead[i]).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -973,9 +1144,7 @@ struct ReverseChainSingleSubstFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool would_apply (hb_would_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1016,6 +1185,13 @@ struct ReverseChainSingleSubstFormat1
|
|||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1076,6 +1252,7 @@ struct ReverseChainSingleSubst
|
|||
|
||||
struct SubstLookupSubTable
|
||||
{
|
||||
friend struct Lookup;
|
||||
friend struct SubstLookup;
|
||||
|
||||
enum Type {
|
||||
|
@ -1126,16 +1303,18 @@ struct SubstLookupSubTable
|
|||
|
||||
struct SubstLookup : Lookup
|
||||
{
|
||||
inline const SubstLookupSubTable& get_subtable (unsigned int i) const
|
||||
{ return Lookup::get_subtable<SubstLookupSubTable> (i); }
|
||||
typedef SubstLookupSubTable SubTable;
|
||||
|
||||
inline const SubTable& get_subtable (unsigned int i) const
|
||||
{ return Lookup::get_subtable<SubTable> (i); }
|
||||
|
||||
inline static bool lookup_type_is_reverse (unsigned int lookup_type)
|
||||
{ return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
|
||||
{ return lookup_type == SubTable::ReverseChainSingle; }
|
||||
|
||||
inline bool is_reverse (void) const
|
||||
{
|
||||
unsigned int type = get_type ();
|
||||
if (unlikely (type == SubstLookupSubTable::Extension))
|
||||
if (unlikely (type == SubTable::Extension))
|
||||
return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
|
||||
return lookup_type_is_reverse (type);
|
||||
}
|
||||
|
@ -1146,6 +1325,12 @@ struct SubstLookup : Lookup
|
|||
return_trace (dispatch (c));
|
||||
}
|
||||
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
hb_intersects_context_t c (glyphs);
|
||||
return dispatch (&c);
|
||||
}
|
||||
|
||||
inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1186,9 +1371,9 @@ struct SubstLookup : Lookup
|
|||
|
||||
static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
|
||||
|
||||
inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
|
||||
inline SubTable& serialize_subtable (hb_serialize_context_t *c,
|
||||
unsigned int i)
|
||||
{ return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
|
||||
{ return get_subtables<SubTable> ()[i].serialize (c, this); }
|
||||
|
||||
inline bool serialize_single (hb_serialize_context_t *c,
|
||||
uint32_t lookup_props,
|
||||
|
@ -1197,7 +1382,7 @@ struct SubstLookup : Lookup
|
|||
unsigned int num_glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
|
||||
}
|
||||
|
||||
|
@ -1209,7 +1394,7 @@ struct SubstLookup : Lookup
|
|||
Supplier<GlyphID> &substitute_glyphs_list)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
|
||||
glyphs,
|
||||
substitute_len_list,
|
||||
|
@ -1225,7 +1410,7 @@ struct SubstLookup : Lookup
|
|||
Supplier<GlyphID> &alternate_glyphs_list)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
|
||||
glyphs,
|
||||
alternate_len_list,
|
||||
|
@ -1243,7 +1428,7 @@ struct SubstLookup : Lookup
|
|||
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
|
||||
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
|
||||
return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
|
||||
first_glyphs,
|
||||
ligature_per_first_glyph_count_list,
|
||||
|
@ -1270,32 +1455,15 @@ struct SubstLookup : Lookup
|
|||
|
||||
template <typename context_t>
|
||||
inline typename context_t::return_t dispatch (context_t *c) const
|
||||
{ return Lookup::dispatch<SubstLookupSubTable> (c); }
|
||||
{ return Lookup::dispatch<SubTable> (c); }
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{ return Lookup::subset<SubTable> (c); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!Lookup::sanitize (c))) return_trace (false);
|
||||
if (unlikely (!dispatch (c))) return_trace (false);
|
||||
|
||||
if (unlikely (get_type () == SubstLookupSubTable::Extension))
|
||||
{
|
||||
/* The spec says all subtables of an Extension lookup should
|
||||
* have the same type, which shall not be the Extension type
|
||||
* itself (but we already checked for that).
|
||||
* This is specially important if one has a reverse type! */
|
||||
unsigned int type = get_subtable (0).u.extension.get_type ();
|
||||
unsigned int count = get_subtable_count ();
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (get_subtable (i).u.extension.get_type () != type)
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
{ return Lookup::sanitize<SubTable> (c); }
|
||||
};
|
||||
|
||||
typedef OffsetListOf<SubstLookup> SubstLookupList;
|
||||
|
||||
/*
|
||||
* GSUB -- Glyph Substitution
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
|
||||
|
@ -1308,13 +1476,11 @@ struct GSUB : GSUBGPOS
|
|||
inline const SubstLookup& get_lookup (unsigned int i) const
|
||||
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{ return GSUBGPOS::subset<SubstLookup> (c); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
|
||||
const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
|
||||
return_trace (list.sanitize (c, this));
|
||||
}
|
||||
{ return GSUBGPOS::sanitize<SubstLookup> (c); }
|
||||
|
||||
typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
|
||||
};
|
||||
|
@ -1325,8 +1491,8 @@ struct GSUB : GSUBGPOS
|
|||
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
|
||||
{
|
||||
unsigned int type = get_type ();
|
||||
if (unlikely (type == SubstLookupSubTable::Extension))
|
||||
return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
|
||||
if (unlikely (type == SubTable::Extension))
|
||||
return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
|
||||
return SubstLookup::lookup_type_is_reverse (type);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,23 @@
|
|||
namespace OT {
|
||||
|
||||
|
||||
struct hb_intersects_context_t :
|
||||
hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
|
||||
{
|
||||
inline const char *get_name (void) { return "INTERSECTS"; }
|
||||
template <typename T>
|
||||
inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
|
||||
static return_t default_return_value (void) { return false; }
|
||||
bool stop_sublookup_iteration (return_t r) const { return r; }
|
||||
|
||||
const hb_set_t *glyphs;
|
||||
unsigned int debug_depth;
|
||||
|
||||
hb_intersects_context_t (const hb_set_t *glyphs_) :
|
||||
glyphs (glyphs_),
|
||||
debug_depth (0) {}
|
||||
};
|
||||
|
||||
struct hb_closure_context_t :
|
||||
hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
|
||||
{
|
||||
|
@ -49,15 +66,14 @@ struct hb_closure_context_t :
|
|||
inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
|
||||
static return_t default_return_value (void) { return HB_VOID; }
|
||||
bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
|
||||
return_t recurse (unsigned int lookup_index)
|
||||
void recurse (unsigned int lookup_index)
|
||||
{
|
||||
if (unlikely (nesting_level_left == 0 || !recurse_func))
|
||||
return default_return_value ();
|
||||
return;
|
||||
|
||||
nesting_level_left--;
|
||||
recurse_func (this, lookup_index);
|
||||
nesting_level_left++;
|
||||
return HB_VOID;
|
||||
}
|
||||
|
||||
bool should_visit_lookup (unsigned int lookup_index)
|
||||
|
@ -146,10 +162,10 @@ struct hb_collect_glyphs_context_t :
|
|||
inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
|
||||
static return_t default_return_value (void) { return HB_VOID; }
|
||||
bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
|
||||
return_t recurse (unsigned int lookup_index)
|
||||
void recurse (unsigned int lookup_index)
|
||||
{
|
||||
if (unlikely (nesting_level_left == 0 || !recurse_func))
|
||||
return default_return_value ();
|
||||
return;
|
||||
|
||||
/* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
|
||||
* past the previous check. For GSUB, we only want to collect the output
|
||||
|
@ -162,11 +178,11 @@ struct hb_collect_glyphs_context_t :
|
|||
*/
|
||||
|
||||
if (output == hb_set_get_empty ())
|
||||
return HB_VOID;
|
||||
return;
|
||||
|
||||
/* Return if new lookup was recursed to before. */
|
||||
if (recursed_lookups->has (lookup_index))
|
||||
return HB_VOID;
|
||||
return;
|
||||
|
||||
hb_set_t *old_before = before;
|
||||
hb_set_t *old_input = input;
|
||||
|
@ -183,7 +199,7 @@ struct hb_collect_glyphs_context_t :
|
|||
|
||||
recursed_lookups->add (lookup_index);
|
||||
|
||||
return HB_VOID;
|
||||
return;
|
||||
}
|
||||
|
||||
hb_face_t *face;
|
||||
|
@ -208,24 +224,16 @@ struct hb_collect_glyphs_context_t :
|
|||
after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
|
||||
output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
|
||||
recurse_func (nullptr),
|
||||
recursed_lookups (nullptr),
|
||||
recursed_lookups (hb_set_create ()),
|
||||
nesting_level_left (nesting_level_left_),
|
||||
debug_depth (0)
|
||||
{
|
||||
recursed_lookups = hb_set_create ();
|
||||
}
|
||||
~hb_collect_glyphs_context_t (void)
|
||||
{
|
||||
hb_set_destroy (recursed_lookups);
|
||||
}
|
||||
debug_depth (0) {}
|
||||
~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
|
||||
|
||||
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* XXX Can we remove this? */
|
||||
|
||||
template <typename set_t>
|
||||
struct hb_add_coverage_context_t :
|
||||
hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
|
||||
|
@ -599,7 +607,7 @@ struct hb_ot_apply_context_t :
|
|||
|
||||
|
||||
|
||||
typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
|
||||
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
|
||||
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
|
||||
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
|
||||
|
||||
|
@ -617,29 +625,29 @@ struct ContextApplyFuncs
|
|||
};
|
||||
|
||||
|
||||
static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
|
||||
static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
|
||||
{
|
||||
return glyphs->has (value);
|
||||
}
|
||||
static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
||||
static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
||||
{
|
||||
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
|
||||
return class_def.intersects_class (glyphs, value);
|
||||
}
|
||||
static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
||||
static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
||||
{
|
||||
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
|
||||
return (data+coverage).intersects (glyphs);
|
||||
}
|
||||
|
||||
static inline bool intersects_array (hb_closure_context_t *c,
|
||||
static inline bool intersects_array (const hb_set_t *glyphs,
|
||||
unsigned int count,
|
||||
const HBUINT16 values[],
|
||||
intersects_func_t intersects_func,
|
||||
const void *intersects_data)
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
|
||||
if (likely (!intersects_func (glyphs, values[i], intersects_data)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -1140,6 +1148,16 @@ struct ContextApplyLookupContext
|
|||
const void *match_data;
|
||||
};
|
||||
|
||||
static inline bool context_intersects (const hb_set_t *glyphs,
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
||||
ContextClosureLookupContext &lookup_context)
|
||||
{
|
||||
return intersects_array (glyphs,
|
||||
inputCount ? inputCount - 1 : 0, input,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data);
|
||||
}
|
||||
|
||||
static inline void context_closure_lookup (hb_closure_context_t *c,
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
||||
|
@ -1147,9 +1165,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
|
|||
const LookupRecord lookupRecord[],
|
||||
ContextClosureLookupContext &lookup_context)
|
||||
{
|
||||
if (intersects_array (c,
|
||||
inputCount ? inputCount - 1 : 0, input,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data))
|
||||
if (context_intersects (c->glyphs,
|
||||
inputCount, input,
|
||||
lookup_context))
|
||||
recurse_lookups (c,
|
||||
lookupCount, lookupRecord);
|
||||
}
|
||||
|
@ -1201,6 +1219,13 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
|
|||
|
||||
struct Rule
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
return context_intersects (glyphs,
|
||||
inputCount, inputZ,
|
||||
lookup_context);
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1261,6 +1286,15 @@ struct Rule
|
|||
|
||||
struct RuleSet
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
unsigned int num_rules = rule.len;
|
||||
for (unsigned int i = 0; i < num_rules; i++)
|
||||
if ((this+rule[i]).intersects (glyphs, lookup_context))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1318,22 +1352,41 @@ struct RuleSet
|
|||
|
||||
struct ContextFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
struct ContextClosureLookupContext lookup_context = {
|
||||
{intersects_glyph},
|
||||
nullptr
|
||||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (glyphs->has (iter.get_glyph ()) &&
|
||||
(this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
||||
const Coverage &cov = (this+coverage);
|
||||
|
||||
struct ContextClosureLookupContext lookup_context = {
|
||||
{intersects_glyph},
|
||||
nullptr
|
||||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (cov.intersects_coverage (c->glyphs, i)) {
|
||||
const RuleSet &rule_set = this+ruleSet[i];
|
||||
rule_set.closure (c, lookup_context);
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (c->glyphs->has (iter.get_glyph ()))
|
||||
(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1365,9 +1418,7 @@ struct ContextFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1384,6 +1435,13 @@ struct ContextFormat1
|
|||
return_trace (rule_set.apply (c, lookup_context));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1405,6 +1463,27 @@ struct ContextFormat1
|
|||
|
||||
struct ContextFormat2
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
if (!(this+coverage).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
const ClassDef &class_def = this+classDef;
|
||||
|
||||
struct ContextClosureLookupContext lookup_context = {
|
||||
{intersects_class},
|
||||
&class_def
|
||||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (class_def.intersects_class (glyphs, i) &&
|
||||
(this+ruleSet[i]).intersects (glyphs, lookup_context))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1457,9 +1536,7 @@ struct ContextFormat2
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1477,6 +1554,13 @@ struct ContextFormat2
|
|||
return_trace (rule_set.apply (c, lookup_context));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1501,6 +1585,20 @@ struct ContextFormat2
|
|||
|
||||
struct ContextFormat3
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
if (!(this+coverageZ[0]).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
struct ContextClosureLookupContext lookup_context = {
|
||||
{intersects_coverage},
|
||||
this
|
||||
};
|
||||
return context_intersects (glyphs,
|
||||
glyphCount, (const HBUINT16 *) (coverageZ + 1),
|
||||
lookup_context);
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1548,9 +1646,7 @@ struct ContextFormat3
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverageZ[0];
|
||||
}
|
||||
{ return this+coverageZ[0]; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1566,6 +1662,13 @@ struct ContextFormat3
|
|||
return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1638,6 +1741,26 @@ struct ChainContextApplyLookupContext
|
|||
const void *match_data[3];
|
||||
};
|
||||
|
||||
static inline bool chain_context_intersects (const hb_set_t *glyphs,
|
||||
unsigned int backtrackCount,
|
||||
const HBUINT16 backtrack[],
|
||||
unsigned int inputCount, /* Including the first glyph (not matched) */
|
||||
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
||||
unsigned int lookaheadCount,
|
||||
const HBUINT16 lookahead[],
|
||||
ChainContextClosureLookupContext &lookup_context)
|
||||
{
|
||||
return intersects_array (glyphs,
|
||||
backtrackCount, backtrack,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data[0])
|
||||
&& intersects_array (glyphs,
|
||||
inputCount ? inputCount - 1 : 0, input,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data[1])
|
||||
&& intersects_array (glyphs,
|
||||
lookaheadCount, lookahead,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
|
||||
}
|
||||
|
||||
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
|
||||
unsigned int backtrackCount,
|
||||
const HBUINT16 backtrack[],
|
||||
|
@ -1649,15 +1772,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
|
|||
const LookupRecord lookupRecord[],
|
||||
ChainContextClosureLookupContext &lookup_context)
|
||||
{
|
||||
if (intersects_array (c,
|
||||
if (chain_context_intersects (c->glyphs,
|
||||
backtrackCount, backtrack,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data[0])
|
||||
&& intersects_array (c,
|
||||
inputCount ? inputCount - 1 : 0, input,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data[1])
|
||||
&& intersects_array (c,
|
||||
inputCount, input,
|
||||
lookaheadCount, lookahead,
|
||||
lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
|
||||
lookup_context))
|
||||
recurse_lookups (c,
|
||||
lookupCount, lookupRecord);
|
||||
}
|
||||
|
@ -1737,6 +1856,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
|
|||
|
||||
struct ChainRule
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
||||
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
||||
return chain_context_intersects (glyphs,
|
||||
backtrack.len, backtrack.arrayZ,
|
||||
input.len, input.arrayZ,
|
||||
lookahead.len, lookahead.arrayZ,
|
||||
lookup_context);
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1823,6 +1953,14 @@ struct ChainRule
|
|||
|
||||
struct ChainRuleSet
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
unsigned int num_rules = rule.len;
|
||||
for (unsigned int i = 0; i < num_rules; i++)
|
||||
if ((this+rule[i]).intersects (glyphs, lookup_context))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -1877,10 +2015,28 @@ struct ChainRuleSet
|
|||
|
||||
struct ChainContextFormat1
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
struct ChainContextClosureLookupContext lookup_context = {
|
||||
{intersects_glyph},
|
||||
{nullptr, nullptr, nullptr}
|
||||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (glyphs->has (iter.get_glyph ()) &&
|
||||
(this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
const Coverage &cov = (this+coverage);
|
||||
|
||||
struct ChainContextClosureLookupContext lookup_context = {
|
||||
{intersects_glyph},
|
||||
|
@ -1888,10 +2044,12 @@ struct ChainContextFormat1
|
|||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (cov.intersects_coverage (c->glyphs, i)) {
|
||||
const ChainRuleSet &rule_set = this+ruleSet[i];
|
||||
rule_set.closure (c, lookup_context);
|
||||
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
||||
{
|
||||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (c->glyphs->has (iter.get_glyph ()))
|
||||
(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1923,9 +2081,7 @@ struct ChainContextFormat1
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -1941,6 +2097,13 @@ struct ChainContextFormat1
|
|||
return_trace (rule_set.apply (c, lookup_context));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -1961,6 +2124,30 @@ struct ChainContextFormat1
|
|||
|
||||
struct ChainContextFormat2
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
if (!(this+coverage).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
const ClassDef &backtrack_class_def = this+backtrackClassDef;
|
||||
const ClassDef &input_class_def = this+inputClassDef;
|
||||
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
||||
|
||||
struct ChainContextClosureLookupContext lookup_context = {
|
||||
{intersects_class},
|
||||
{&backtrack_class_def,
|
||||
&input_class_def,
|
||||
&lookahead_class_def}
|
||||
};
|
||||
|
||||
unsigned int count = ruleSet.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (input_class_def.intersects_class (glyphs, i) &&
|
||||
(this+ruleSet[i]).intersects (glyphs, lookup_context))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -2027,9 +2214,7 @@ struct ChainContextFormat2
|
|||
}
|
||||
|
||||
inline const Coverage &get_coverage (void) const
|
||||
{
|
||||
return this+coverage;
|
||||
}
|
||||
{ return this+coverage; }
|
||||
|
||||
inline bool apply (hb_ot_apply_context_t *c) const
|
||||
{
|
||||
|
@ -2052,6 +2237,13 @@ struct ChainContextFormat2
|
|||
return_trace (rule_set.apply (c, lookup_context));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2088,6 +2280,25 @@ struct ChainContextFormat2
|
|||
|
||||
struct ChainContextFormat3
|
||||
{
|
||||
inline bool intersects (const hb_set_t *glyphs) const
|
||||
{
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
|
||||
if (!(this+input[0]).intersects (glyphs))
|
||||
return false;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
struct ChainContextClosureLookupContext lookup_context = {
|
||||
{intersects_coverage},
|
||||
{this, this, this}
|
||||
};
|
||||
return chain_context_intersects (glyphs,
|
||||
backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
|
||||
input.len, (const HBUINT16 *) input.arrayZ + 1,
|
||||
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
|
||||
lookup_context);
|
||||
}
|
||||
|
||||
inline void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
TRACE_CLOSURE (this);
|
||||
|
@ -2176,6 +2387,13 @@ struct ChainContextFormat3
|
|||
lookup.len, lookup.arrayZ, lookup_context));
|
||||
}
|
||||
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
// TODO(subset)
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -2244,8 +2462,8 @@ struct ExtensionFormat1
|
|||
inline const X& get_subtable (void) const
|
||||
{
|
||||
unsigned int offset = extensionOffset;
|
||||
if (unlikely (!offset)) return Null(typename T::LookupSubTable);
|
||||
return StructAtOffset<typename T::LookupSubTable> (this, offset);
|
||||
if (unlikely (!offset)) return Null(typename T::SubTable);
|
||||
return StructAtOffset<typename T::SubTable> (this, offset);
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
|
@ -2253,7 +2471,7 @@ struct ExtensionFormat1
|
|||
{
|
||||
TRACE_DISPATCH (this, format);
|
||||
if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
|
||||
return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
|
||||
return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
|
||||
}
|
||||
|
||||
/* This is called from may_dispatch() above with hb_sanitize_context_t. */
|
||||
|
@ -2262,7 +2480,7 @@ struct ExtensionFormat1
|
|||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
extensionOffset != 0 &&
|
||||
extensionLookupType != T::LookupSubTable::Extension);
|
||||
extensionLookupType != T::SubTable::Extension);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -2290,8 +2508,8 @@ struct Extension
|
|||
inline const X& get_subtable (void) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
|
||||
default:return Null(typename T::LookupSubTable);
|
||||
case 1: return u.format1.template get_subtable<typename T::SubTable> ();
|
||||
default:return Null(typename T::SubTable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2370,14 +2588,43 @@ struct GSUBGPOS
|
|||
return get_feature (feature_index);
|
||||
}
|
||||
|
||||
template <typename TLookup>
|
||||
inline bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct GSUBGPOS *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
out->scriptList.serialize_subset (c, this+scriptList, out);
|
||||
out->featureList.serialize_subset (c, this+featureList, out);
|
||||
|
||||
typedef OffsetListOf<TLookup> TLookupList;
|
||||
/* TODO Use intersects() to count how many subtables survive? */
|
||||
CastR<OffsetTo<TLookupList> > (out->lookupList)
|
||||
.serialize_subset (c,
|
||||
this+CastR<const OffsetTo<TLookupList> > (lookupList),
|
||||
out);
|
||||
|
||||
if (version.to_int () >= 0x00010001u)
|
||||
out->featureVars.serialize_subset (c, this+featureVars, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{
|
||||
return min_size +
|
||||
(version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
|
||||
}
|
||||
|
||||
template <typename TLookup>
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
typedef OffsetListOf<TLookup> TLookupList;
|
||||
return_trace (version.sanitize (c) &&
|
||||
likely (version.major == 1) &&
|
||||
scriptList.sanitize (c, this) &&
|
||||
featureList.sanitize (c, this) &&
|
||||
lookupList.sanitize (c, this) &&
|
||||
CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
|
||||
(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_OT_MAXP_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-os2-unicode-ranges.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#define HB_OT_POST_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
#define HB_STRING_ARRAY_NAME format1_names
|
||||
#define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
|
||||
|
|
|
@ -173,7 +173,6 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
|
|||
ligatures_supplier,
|
||||
component_count_supplier,
|
||||
component_supplier);
|
||||
|
||||
c.end_serialize ();
|
||||
/* TODO sanitize the results? */
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-set.h"
|
||||
#include "hb-subset-glyf.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
static bool
|
||||
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-subset-plan.hh"
|
||||
#include "hb-subset.hh"
|
||||
|
||||
HB_INTERNAL bool
|
||||
hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
|
||||
|
|
|
@ -44,7 +44,7 @@ hb_subset_input_create_or_fail (void)
|
|||
|
||||
input->unicodes = hb_set_create ();
|
||||
input->glyphs = hb_set_create ();
|
||||
input->drop_ot_layout = true;
|
||||
input->drop_layout = true;
|
||||
|
||||
return input;
|
||||
}
|
||||
|
@ -106,30 +106,28 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input)
|
|||
return subset_input->glyphs;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_subset_input_drop_hints:
|
||||
* @subset_input: a subset_input.
|
||||
*
|
||||
* Since: 1.8.0
|
||||
**/
|
||||
HB_EXTERN hb_bool_t *
|
||||
hb_subset_input_drop_hints (hb_subset_input_t *subset_input)
|
||||
HB_EXTERN void
|
||||
hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
|
||||
hb_bool_t drop_hints)
|
||||
{
|
||||
return &subset_input->drop_hints;
|
||||
subset_input->drop_hints = drop_hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_subset_input_drop_ot_layout:
|
||||
* @subset_input: a subset_input.
|
||||
*
|
||||
* If enabled ot layout tables will be dropped as part of
|
||||
* the subsetting operation. Currently this defaults to
|
||||
* true.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
HB_EXTERN hb_bool_t *
|
||||
hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input)
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input)
|
||||
{
|
||||
return &subset_input->drop_ot_layout;
|
||||
return subset_input->drop_hints;
|
||||
}
|
||||
|
||||
HB_EXTERN void
|
||||
hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
|
||||
hb_bool_t drop_layout)
|
||||
{
|
||||
subset_input->drop_layout = drop_layout;
|
||||
}
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input)
|
||||
{
|
||||
return subset_input->drop_layout;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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): Garret Rieger, Roderick Sheeter
|
||||
*/
|
||||
|
||||
#ifndef HB_SUBSET_INPUT_HH
|
||||
#define HB_SUBSET_INPUT_HH
|
||||
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-subset.h"
|
||||
|
||||
#include "hb-font.hh"
|
||||
|
||||
struct hb_subset_input_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_set_t *unicodes;
|
||||
hb_set_t *glyphs;
|
||||
|
||||
bool drop_hints : 1;
|
||||
bool drop_layout : 1;
|
||||
/* TODO
|
||||
*
|
||||
* features
|
||||
* lookups
|
||||
* nameIDs
|
||||
* ...
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_SUBSET_INPUT_HH */
|
|
@ -24,11 +24,10 @@
|
|||
* Google Author(s): Garret Rieger, Roderick Sheeter
|
||||
*/
|
||||
|
||||
#include "hb-subset-plan.hh"
|
||||
#include "hb-map.hh"
|
||||
#include "hb-subset.hh"
|
||||
#include "hb-set.hh"
|
||||
|
||||
#include "hb-subset-plan.hh"
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
|
||||
|
@ -69,7 +68,7 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
static hb_set_t *
|
||||
_populate_gids_to_retain (hb_face_t *face,
|
||||
const hb_set_t *unicodes,
|
||||
bool close_over_gsub,
|
||||
|
@ -118,9 +117,10 @@ _populate_gids_to_retain (hb_face_t *face,
|
|||
while (all_gids_to_retain->next (&gid))
|
||||
glyphs->push (gid);
|
||||
|
||||
hb_set_destroy (all_gids_to_retain);
|
||||
glyf.fini ();
|
||||
cmap.fini ();
|
||||
|
||||
return all_gids_to_retain;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -135,7 +135,7 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
|
|||
/**
|
||||
* hb_subset_plan_create:
|
||||
* Computes a plan for subsetting the supplied face according
|
||||
* to a provide profile and input. The plan describes
|
||||
* to a provided input. The plan describes
|
||||
* which tables and glyphs should be retained.
|
||||
*
|
||||
* Return value: New subset plan.
|
||||
|
@ -144,23 +144,21 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
|
|||
**/
|
||||
hb_subset_plan_t *
|
||||
hb_subset_plan_create (hb_face_t *face,
|
||||
hb_subset_profile_t *profile,
|
||||
hb_subset_input_t *input)
|
||||
{
|
||||
hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
|
||||
|
||||
plan->drop_hints = input->drop_hints;
|
||||
plan->drop_ot_layout = input->drop_ot_layout;
|
||||
plan->drop_layout = input->drop_layout;
|
||||
plan->unicodes = hb_set_create();
|
||||
plan->glyphs.init();
|
||||
plan->source = hb_face_reference (face);
|
||||
plan->dest = hb_face_builder_create ();
|
||||
plan->codepoint_to_glyph = hb_map_create();
|
||||
plan->glyph_map = hb_map_create();
|
||||
|
||||
_populate_gids_to_retain (face,
|
||||
plan->glyphset = _populate_gids_to_retain (face,
|
||||
input->unicodes,
|
||||
!plan->drop_ot_layout,
|
||||
!plan->drop_layout,
|
||||
plan->unicodes,
|
||||
plan->codepoint_to_glyph,
|
||||
&plan->glyphs);
|
||||
|
@ -186,6 +184,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
|
|||
hb_face_destroy (plan->dest);
|
||||
hb_map_destroy (plan->codepoint_to_glyph);
|
||||
hb_map_destroy (plan->glyph_map);
|
||||
hb_set_destroy (plan->glyphset);
|
||||
|
||||
free (plan);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "hb.hh"
|
||||
|
||||
#include "hb-subset.h"
|
||||
#include "hb-subset.hh"
|
||||
#include "hb-subset-input.hh"
|
||||
|
||||
#include "hb-map.hh"
|
||||
|
||||
|
@ -39,15 +39,14 @@ struct hb_subset_plan_t
|
|||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_bool_t drop_hints;
|
||||
hb_bool_t drop_ot_layout;
|
||||
bool drop_hints : 1;
|
||||
bool drop_layout : 1;
|
||||
|
||||
// For each cp that we'd like to retain maps to the corresponding gid.
|
||||
hb_set_t *unicodes;
|
||||
|
||||
// This list contains the complete set of glyphs to retain and may contain
|
||||
// more glyphs then the lists above.
|
||||
hb_vector_t<hb_codepoint_t> glyphs;
|
||||
hb_set_t *glyphset;
|
||||
|
||||
hb_map_t *codepoint_to_glyph;
|
||||
hb_map_t *glyph_map;
|
||||
|
@ -56,7 +55,7 @@ struct hb_subset_plan_t
|
|||
hb_face_t *source;
|
||||
hb_face_t *dest;
|
||||
|
||||
inline hb_bool_t
|
||||
inline bool
|
||||
new_gid_for_codepoint (hb_codepoint_t codepoint,
|
||||
hb_codepoint_t *new_gid) const
|
||||
{
|
||||
|
@ -67,7 +66,7 @@ struct hb_subset_plan_t
|
|||
return new_gid_for_old_gid (old_gid, new_gid);
|
||||
}
|
||||
|
||||
inline hb_bool_t
|
||||
inline bool
|
||||
new_gid_for_old_gid (hb_codepoint_t old_gid,
|
||||
hb_codepoint_t *new_gid) const
|
||||
{
|
||||
|
@ -79,7 +78,7 @@ struct hb_subset_plan_t
|
|||
return true;
|
||||
}
|
||||
|
||||
inline hb_bool_t
|
||||
inline bool
|
||||
add_table (hb_tag_t tag,
|
||||
hb_blob_t *contents)
|
||||
{
|
||||
|
@ -97,7 +96,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
|
|||
|
||||
HB_INTERNAL hb_subset_plan_t *
|
||||
hb_subset_plan_create (hb_face_t *face,
|
||||
hb_subset_profile_t *profile,
|
||||
hb_subset_input_t *input);
|
||||
|
||||
HB_INTERNAL void
|
||||
|
|
111
src/hb-subset.cc
111
src/hb-subset.cc
|
@ -27,9 +27,8 @@
|
|||
#include "hb.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
#include "hb-subset-glyf.hh"
|
||||
#include "hb-subset.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
#include "hb-subset-glyf.hh"
|
||||
|
||||
#include "hb-open-file.hh"
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
|
@ -43,37 +42,73 @@
|
|||
#include "hb-ot-post-table.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
|
||||
|
||||
struct hb_subset_profile_t {
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
};
|
||||
|
||||
/**
|
||||
* hb_subset_profile_create:
|
||||
*
|
||||
* Return value: New profile with default settings.
|
||||
*
|
||||
* Since: 1.8.0
|
||||
**/
|
||||
hb_subset_profile_t *
|
||||
hb_subset_profile_create ()
|
||||
static unsigned int
|
||||
_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
|
||||
unsigned int table_len)
|
||||
{
|
||||
return hb_object_create<hb_subset_profile_t>();
|
||||
unsigned int src_glyphs = plan->source->get_num_glyphs ();
|
||||
unsigned int dst_glyphs = plan->glyphset->get_population ();
|
||||
|
||||
return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_subset_profile_destroy:
|
||||
*
|
||||
* Since: 1.8.0
|
||||
**/
|
||||
void
|
||||
hb_subset_profile_destroy (hb_subset_profile_t *profile)
|
||||
template<typename TableType>
|
||||
static bool
|
||||
_subset2 (hb_subset_plan_t *plan)
|
||||
{
|
||||
if (!hb_object_destroy (profile)) return;
|
||||
hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
|
||||
const TableType *table = source_blob->as<TableType> ();
|
||||
|
||||
free (profile);
|
||||
hb_tag_t tag = TableType::tableTag;
|
||||
hb_bool_t result = false;
|
||||
if (source_blob->data)
|
||||
{
|
||||
hb_auto_t<hb_vector_t<char> > buf;
|
||||
unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG(tag), buf_size);
|
||||
if (unlikely (!buf.alloc (buf_size)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG(tag), buf_size);
|
||||
return false;
|
||||
}
|
||||
retry:
|
||||
hb_serialize_context_t serializer (buf.arrayZ, buf_size);
|
||||
hb_subset_context_t c (plan, &serializer);
|
||||
result = table->subset (&c);
|
||||
if (serializer.ran_out_of_room)
|
||||
{
|
||||
buf_size += (buf_size >> 1) + 32;
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG(tag), buf_size);
|
||||
if (unlikely (!buf.alloc (buf_size)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG(tag), buf_size);
|
||||
return false;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
hb_blob_t *dest_blob = serializer.copy_blob ();
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG(tag), dest_blob->length);
|
||||
result = c.plan->add_table (tag, dest_blob);
|
||||
hb_blob_destroy (dest_blob);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG(tag));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
|
||||
|
||||
hb_blob_destroy (source_blob);
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TableType>
|
||||
|
@ -86,11 +121,9 @@ _subset (hb_subset_plan_t *plan)
|
|||
hb_tag_t tag = TableType::tableTag;
|
||||
hb_bool_t result = false;
|
||||
if (source_blob->data)
|
||||
{
|
||||
result = table->subset (plan);
|
||||
} else {
|
||||
else
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
|
||||
}
|
||||
|
||||
hb_blob_destroy (source_blob);
|
||||
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
|
||||
|
@ -149,6 +182,14 @@ _subset_table (hb_subset_plan_t *plan,
|
|||
case HB_OT_TAG_cff2:
|
||||
result = _subset<const OT::cff2> (plan);
|
||||
break;
|
||||
|
||||
case HB_OT_TAG_GSUB:
|
||||
result = _subset2<const OT::GSUB> (plan);
|
||||
break;
|
||||
case HB_OT_TAG_GPOS:
|
||||
result = _subset2<const OT::GPOS> (plan);
|
||||
break;
|
||||
|
||||
default:
|
||||
hb_blob_t *source_table = hb_face_reference_table(plan->source, tag);
|
||||
if (likely (source_table))
|
||||
|
@ -177,7 +218,7 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
|
|||
case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */
|
||||
case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */
|
||||
case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */
|
||||
return plan->drop_ot_layout;
|
||||
return plan->drop_layout;
|
||||
// Drop these tables below by default, list pulled
|
||||
// from fontTools:
|
||||
case HB_TAG ('B', 'A', 'S', 'E'):
|
||||
|
@ -206,19 +247,17 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
|
|||
/**
|
||||
* hb_subset:
|
||||
* @source: font face data to be subset.
|
||||
* @profile: profile to use for the subsetting.
|
||||
* @input: input to use for the subsetting.
|
||||
*
|
||||
* Subsets a font according to provided profile and input.
|
||||
* Subsets a font according to provided input.
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_subset (hb_face_t *source,
|
||||
hb_subset_profile_t *profile,
|
||||
hb_subset_input_t *input)
|
||||
{
|
||||
if (unlikely (!profile || !input || !source)) return hb_face_get_empty();
|
||||
if (unlikely (!input || !source)) return hb_face_get_empty();
|
||||
|
||||
hb_subset_plan_t *plan = hb_subset_plan_create (source, profile, input);
|
||||
hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
|
||||
|
||||
hb_tag_t table_tags[32];
|
||||
unsigned int offset = 0, count;
|
||||
|
@ -237,7 +276,7 @@ hb_subset (hb_face_t *source,
|
|||
success = success && _subset_table (plan, tag);
|
||||
}
|
||||
offset += count;
|
||||
} while (count == ARRAY_LENGTH (table_tags));
|
||||
} while (success && count == ARRAY_LENGTH (table_tags));
|
||||
|
||||
hb_face_t *result = success ? hb_face_reference(plan->dest) : hb_face_get_empty();
|
||||
hb_subset_plan_destroy (plan);
|
||||
|
|
|
@ -31,20 +31,6 @@
|
|||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* hb_subset_profile_t
|
||||
* Things that change based on target environment, e.g. OS.
|
||||
* Threadsafe for multiple concurrent subset operations.
|
||||
*/
|
||||
|
||||
typedef struct hb_subset_profile_t hb_subset_profile_t;
|
||||
|
||||
HB_EXTERN hb_subset_profile_t *
|
||||
hb_subset_profile_create (void);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_subset_profile_destroy (hb_subset_profile_t *profile);
|
||||
|
||||
/*
|
||||
* hb_subset_input_t
|
||||
*
|
||||
|
@ -68,16 +54,22 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input);
|
|||
HB_EXTERN hb_set_t *
|
||||
hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
|
||||
|
||||
HB_EXTERN hb_bool_t *
|
||||
hb_subset_input_drop_hints (hb_subset_input_t *subset_input);
|
||||
HB_EXTERN void
|
||||
hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
|
||||
hb_bool_t drop_hints);
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
|
||||
hb_bool_t drop_layout);
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input);
|
||||
|
||||
HB_EXTERN hb_bool_t *
|
||||
hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input);
|
||||
|
||||
/* hb_subset() */
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_subset (hb_face_t *source,
|
||||
hb_subset_profile_t *profile,
|
||||
hb_subset_input_t *input);
|
||||
|
||||
|
||||
|
|
|
@ -32,25 +32,28 @@
|
|||
|
||||
#include "hb-subset.h"
|
||||
|
||||
#include "hb-font.hh"
|
||||
#include "hb-machinery.hh"
|
||||
#include "hb-subset-input.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
struct hb_subset_input_t
|
||||
struct hb_subset_context_t :
|
||||
hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET>
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
inline const char *get_name (void) { return "SUBSET"; }
|
||||
template <typename T>
|
||||
inline bool dispatch (const T &obj) { return obj.subset (this); }
|
||||
static bool default_return_value (void) { return true; }
|
||||
bool stop_sublookup_iteration (bool r) const { return false; }
|
||||
|
||||
hb_set_t *unicodes;
|
||||
hb_set_t *glyphs;
|
||||
hb_subset_plan_t *plan;
|
||||
hb_serialize_context_t *serializer;
|
||||
unsigned int debug_depth;
|
||||
|
||||
hb_bool_t drop_hints;
|
||||
hb_bool_t drop_ot_layout;
|
||||
/* TODO
|
||||
*
|
||||
* features
|
||||
* lookups
|
||||
* nameIDs
|
||||
* ...
|
||||
*/
|
||||
hb_subset_context_t (hb_subset_plan_t *plan_,
|
||||
hb_serialize_context_t *serializer_) :
|
||||
plan (plan_),
|
||||
serializer (serializer_),
|
||||
debug_depth (0) {}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -72,6 +72,8 @@ struct hb_vector_t
|
|||
return p;
|
||||
}
|
||||
|
||||
inline bool in_error (void) const { return allocated == 0; }
|
||||
|
||||
/* Allocate for size but don't adjust len. */
|
||||
inline bool alloc (unsigned int size)
|
||||
{
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -72,11 +72,9 @@ static inline hb_face_t *
|
|||
hb_subset_test_create_subset (hb_face_t *source,
|
||||
hb_subset_input_t *input)
|
||||
{
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (source, profile, input);
|
||||
hb_face_t *subset = hb_subset (source, input);
|
||||
g_assert (subset);
|
||||
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_subset_input_destroy (input);
|
||||
return subset;
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ test_subset_glyf_with_gsub (void)
|
|||
|
||||
hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
|
||||
hb_set_destroy (codepoints);
|
||||
*hb_subset_input_drop_ot_layout (input) = false;
|
||||
hb_subset_input_set_drop_layout (input, false);
|
||||
|
||||
hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
|
||||
|
||||
|
@ -137,7 +137,7 @@ test_subset_glyf_without_gsub (void)
|
|||
|
||||
hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
|
||||
hb_set_destroy (codepoints);
|
||||
*hb_subset_input_drop_ot_layout (input) = true;
|
||||
hb_subset_input_set_drop_layout (input, true);
|
||||
|
||||
hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
|
||||
|
||||
|
@ -183,7 +183,7 @@ test_subset_glyf_strip_hints_simple (void)
|
|||
hb_set_add (codepoints, 'a');
|
||||
hb_set_add (codepoints, 'c');
|
||||
input = hb_subset_test_create_input (codepoints);
|
||||
*hb_subset_input_drop_hints(input) = true;
|
||||
hb_subset_input_set_drop_hints (input, true);
|
||||
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
||||
hb_set_destroy (codepoints);
|
||||
|
||||
|
@ -207,7 +207,7 @@ test_subset_glyf_strip_hints_composite (void)
|
|||
hb_face_t *face_generated_subset;
|
||||
hb_set_add (codepoints, 0x1fc);
|
||||
input = hb_subset_test_create_input (codepoints);
|
||||
*hb_subset_input_drop_hints(input) = true;
|
||||
hb_subset_input_set_drop_hints (input, true);
|
||||
|
||||
face_generated_subset = hb_subset_test_create_subset (face_components, input);
|
||||
hb_set_destroy (codepoints);
|
||||
|
@ -239,7 +239,7 @@ test_subset_glyf_strip_hints_invalid (void)
|
|||
}
|
||||
|
||||
hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
|
||||
*hb_subset_input_drop_hints(input) = true;
|
||||
hb_subset_input_set_drop_hints (input, true);
|
||||
hb_set_destroy (codepoints);
|
||||
|
||||
hb_face_t *face_subset = hb_subset_test_create_subset (face, input);
|
||||
|
|
|
@ -50,6 +50,25 @@ test_subset_hdmx_simple_subset (void)
|
|||
hb_face_destroy (face_ac);
|
||||
}
|
||||
|
||||
static void
|
||||
test_subset_hdmx_multiple_device_records (void)
|
||||
{
|
||||
hb_face_t *face_abc = hb_subset_test_open_font ("fonts/Roboto-Regular.multihdmx.abc.ttf");
|
||||
hb_face_t *face_a = hb_subset_test_open_font ("fonts/Roboto-Regular.multihdmx.a.ttf");
|
||||
|
||||
hb_set_t *codepoints = hb_set_create ();
|
||||
hb_face_t *face_abc_subset;
|
||||
hb_set_add (codepoints, 'a');
|
||||
face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||
hb_set_destroy (codepoints);
|
||||
|
||||
hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('h','d','m','x'));
|
||||
|
||||
hb_face_destroy (face_abc_subset);
|
||||
hb_face_destroy (face_abc);
|
||||
hb_face_destroy (face_a);
|
||||
}
|
||||
|
||||
static void
|
||||
test_subset_hdmx_invalid (void)
|
||||
{
|
||||
|
@ -61,13 +80,11 @@ test_subset_hdmx_invalid (void)
|
|||
hb_set_add (codepoints, 'b');
|
||||
hb_set_add (codepoints, 'c');
|
||||
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (face, profile, input);
|
||||
hb_face_t *subset = hb_subset (face, input);
|
||||
g_assert (subset);
|
||||
g_assert (subset == hb_face_get_empty ());
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_face_destroy (subset);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
@ -83,13 +100,11 @@ test_subset_hdmx_fails_sanitize (void)
|
|||
hb_set_add (codepoints, 'b');
|
||||
hb_set_add (codepoints, 'c');
|
||||
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (face, profile, input);
|
||||
hb_face_t *subset = hb_subset (face, input);
|
||||
g_assert (subset);
|
||||
g_assert (subset == hb_face_get_empty ());
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_face_destroy (subset);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
@ -119,6 +134,7 @@ main (int argc, char **argv)
|
|||
hb_test_init (&argc, &argv);
|
||||
|
||||
hb_test_add (test_subset_hdmx_simple_subset);
|
||||
hb_test_add (test_subset_hdmx_multiple_device_records);
|
||||
hb_test_add (test_subset_hdmx_invalid);
|
||||
hb_test_add (test_subset_hdmx_fails_sanitize);
|
||||
hb_test_add (test_subset_hdmx_noop);
|
||||
|
|
|
@ -161,13 +161,11 @@ test_subset_invalid_hmtx (void)
|
|||
hb_set_add (codepoints, 'b');
|
||||
hb_set_add (codepoints, 'c');
|
||||
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (face, profile, input);
|
||||
hb_face_t *subset = hb_subset (face, input);
|
||||
g_assert (subset);
|
||||
g_assert (subset == hb_face_get_empty ());
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_face_destroy (subset);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
|
|
@ -40,13 +40,11 @@ test_subset_32_tables (void)
|
|||
hb_set_add (codepoints, 'b');
|
||||
hb_set_add (codepoints, 'c');
|
||||
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (face, profile, input);
|
||||
hb_face_t *subset = hb_subset (face, input);
|
||||
g_assert (subset);
|
||||
g_assert (subset != hb_face_get_empty ());
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_face_destroy (subset);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
@ -62,13 +60,11 @@ test_subset_no_inf_loop (void)
|
|||
hb_set_add (codepoints, 'b');
|
||||
hb_set_add (codepoints, 'c');
|
||||
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (face, profile, input);
|
||||
hb_face_t *subset = hb_subset (face, input);
|
||||
g_assert (subset);
|
||||
g_assert (subset == hb_face_get_empty ());
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_face_destroy (subset);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
@ -84,13 +80,11 @@ test_subset_crash (void)
|
|||
hb_set_add (codepoints, 'b');
|
||||
hb_set_add (codepoints, 'c');
|
||||
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||
hb_face_t *subset = hb_subset (face, profile, input);
|
||||
hb_face_t *subset = hb_subset (face, input);
|
||||
g_assert (subset);
|
||||
g_assert (subset == hb_face_get_empty ());
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
hb_face_destroy (subset);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
|
|
@ -10,13 +10,11 @@ void trySubset (hb_face_t *face,
|
|||
const hb_codepoint_t text[],
|
||||
int text_length,
|
||||
bool drop_hints,
|
||||
bool drop_ot_layout)
|
||||
bool drop_layout)
|
||||
{
|
||||
hb_subset_profile_t *profile = hb_subset_profile_create ();
|
||||
|
||||
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
|
||||
*hb_subset_input_drop_hints (input) = drop_hints;
|
||||
*hb_subset_input_drop_ot_layout (input) = drop_ot_layout;
|
||||
hb_subset_input_set_drop_hints (input, drop_hints);
|
||||
hb_subset_input_set_drop_layout (input, drop_layout);
|
||||
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
|
||||
|
||||
for (int i = 0; i < text_length; i++)
|
||||
|
@ -24,11 +22,10 @@ void trySubset (hb_face_t *face,
|
|||
hb_set_add (codepoints, text[i]);
|
||||
}
|
||||
|
||||
hb_face_t *result = hb_subset (face, profile, input);
|
||||
hb_face_t *result = hb_subset (face, input);
|
||||
hb_face_destroy (result);
|
||||
|
||||
hb_subset_input_destroy (input);
|
||||
hb_subset_profile_destroy (profile);
|
||||
}
|
||||
|
||||
void trySubset (hb_face_t *face,
|
||||
|
@ -37,10 +34,10 @@ void trySubset (hb_face_t *face,
|
|||
{
|
||||
for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++)
|
||||
{
|
||||
for (unsigned int drop_ot_layout = 0; drop_ot_layout < 2; drop_ot_layout++)
|
||||
for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++)
|
||||
{
|
||||
trySubset (face, text, text_length,
|
||||
(bool) drop_hints, (bool) drop_ot_layout);
|
||||
(bool) drop_hints, (bool) drop_layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "main-font-text.hh"
|
||||
#include "hb-subset.h"
|
||||
#include "hb-subset.hh" /* XXX */
|
||||
|
||||
/*
|
||||
* Command line interface to the harfbuzz font subsetter.
|
||||
|
@ -90,19 +89,17 @@ struct subset_consumer_t
|
|||
|
||||
void finish (const font_options_t *font_opts)
|
||||
{
|
||||
input->drop_hints = subset_options.drop_hints;
|
||||
hb_subset_input_set_drop_hints (input, subset_options.drop_hints);
|
||||
|
||||
hb_subset_profile_t *subset_profile = hb_subset_profile_create();
|
||||
hb_face_t *face = hb_font_get_face (font);
|
||||
|
||||
hb_face_t *new_face = hb_subset(face, subset_profile, input);
|
||||
hb_face_t *new_face = hb_subset(face, input);
|
||||
hb_blob_t *result = hb_face_reference_blob (new_face);
|
||||
|
||||
failed = !hb_blob_get_length (result);
|
||||
if (!failed)
|
||||
write_file (options.output_file, result);
|
||||
|
||||
hb_subset_profile_destroy (subset_profile);
|
||||
hb_subset_input_destroy (input);
|
||||
hb_blob_destroy (result);
|
||||
hb_face_destroy (new_face);
|
||||
|
|
Loading…
Reference in New Issue