Update HarfBuzz to 7.1.0

This commit is contained in:
Pedro J. Estébanez 2023-02-13 10:44:33 +01:00
parent df7834ac96
commit abc13dbd0b
205 changed files with 14886 additions and 5156 deletions

View file

@ -227,19 +227,23 @@ License: Expat
Files: ./thirdparty/harfbuzz/ Files: ./thirdparty/harfbuzz/
Comment: HarfBuzz text shaping library Comment: HarfBuzz text shaping library
Copyright: 2010-2020, Google, Inc. Copyright: 2010-2022, Google, Inc.
2018-2020, Ebrahim Byagowi 2015-2020, Ebrahim Byagowi
2019-2020, Facebook, Inc. 2019,2020, Facebook, Inc.
2012, Mozilla Foundation 2012, 2015, Mozilla Foundation
2011, Codethink Limited 2011, Codethink Limited
2008, 2010, Nokia Corporation and/or its subsidiary(-ies) 2008, 2010, Nokia Corporation and/or its subsidiary(-ies)
2009, Keith Stribley 2009, Keith Stribley
2009, Martin Hosken and SIL International 2011, Martin Hosken and SIL International
2007, Chris Wilson 2007, Chris Wilson
2005-2006, 2020-2021, Behdad Esfahbod 2005-2006, 2020-2023, Behdad Esfahbod
2005, David Turner 2004, 2007-2010, 2013, 2021-2023, Red Hat, Inc.
2004, 2007-2010, Red Hat, Inc. 1998-2005, David Turner and Werner Lemberg
1998-2004, David Turner and Werner Lemberg 2016, Igalia, S.L.
2022, Matthias Clasen
2018, 2021, Khaled Hosny
2018-2020, Adobe, Inc.
2013-2015, Alexei Podtelezhnikov
License: HarfBuzz License: HarfBuzz
Files: ./thirdparty/icu4c/ Files: ./thirdparty/icu4c/

View file

@ -53,16 +53,19 @@ if env["builtin_harfbuzz"]:
"src/hb-buffer-serialize.cc", "src/hb-buffer-serialize.cc",
"src/hb-buffer-verify.cc", "src/hb-buffer-verify.cc",
"src/hb-buffer.cc", "src/hb-buffer.cc",
# "src/hb-cairo-utils.cc",
# "src/hb-cairo.cc",
"src/hb-common.cc", "src/hb-common.cc",
#'src/hb-coretext.cc', # "src/hb-coretext.cc",
#'src/hb-directwrite.cc', # "src/hb-directwrite.cc",
"src/hb-draw.cc", "src/hb-draw.cc",
"src/hb-face-builder.cc",
"src/hb-face.cc", "src/hb-face.cc",
"src/hb-fallback-shape.cc", "src/hb-fallback-shape.cc",
"src/hb-font.cc", "src/hb-font.cc",
#'src/hb-gdi.cc', # "src/hb-gdi.cc",
#'src/hb-glib.cc', # "src/hb-glib.cc",
#'src/hb-gobject-structs.cc', # "src/hb-gobject-structs.cc",
"src/hb-icu.cc", "src/hb-icu.cc",
"src/hb-map.cc", "src/hb-map.cc",
"src/hb-number.cc", "src/hb-number.cc",
@ -94,6 +97,9 @@ if env["builtin_harfbuzz"]:
"src/hb-ot-shape.cc", "src/hb-ot-shape.cc",
"src/hb-ot-tag.cc", "src/hb-ot-tag.cc",
"src/hb-ot-var.cc", "src/hb-ot-var.cc",
"src/hb-outline.cc",
"src/hb-paint-extents.cc",
"src/hb-paint.cc",
"src/hb-set.cc", "src/hb-set.cc",
"src/hb-shape-plan.cc", "src/hb-shape-plan.cc",
"src/hb-shape.cc", "src/hb-shape.cc",
@ -104,12 +110,13 @@ if env["builtin_harfbuzz"]:
"src/hb-subset-cff1.cc", "src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc", "src/hb-subset-cff2.cc",
"src/hb-subset-input.cc", "src/hb-subset-input.cc",
"src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc", "src/hb-subset-plan.cc",
"src/hb-subset-repacker.cc", "src/hb-subset-repacker.cc",
"src/hb-subset.cc", "src/hb-subset.cc",
"src/hb-ucd.cc", "src/hb-ucd.cc",
"src/hb-unicode.cc", "src/hb-unicode.cc",
#'src/hb-uniscribe.cc' # "src/hb-uniscribe.cc",
] ]
if freetype_enabled: if freetype_enabled:

View file

@ -290,16 +290,19 @@ thirdparty_harfbuzz_sources = [
"src/hb-buffer-serialize.cc", "src/hb-buffer-serialize.cc",
"src/hb-buffer-verify.cc", "src/hb-buffer-verify.cc",
"src/hb-buffer.cc", "src/hb-buffer.cc",
# "src/hb-cairo-utils.cc",
# "src/hb-cairo.cc",
"src/hb-common.cc", "src/hb-common.cc",
#'src/hb-coretext.cc', # "src/hb-coretext.cc",
#'src/hb-directwrite.cc', # "src/hb-directwrite.cc",
"src/hb-draw.cc", "src/hb-draw.cc",
"src/hb-face-builder.cc",
"src/hb-face.cc", "src/hb-face.cc",
"src/hb-fallback-shape.cc", "src/hb-fallback-shape.cc",
"src/hb-font.cc", "src/hb-font.cc",
#'src/hb-gdi.cc', # "src/hb-gdi.cc",
#'src/hb-glib.cc', # "src/hb-glib.cc",
#'src/hb-gobject-structs.cc', # "src/hb-gobject-structs.cc",
"src/hb-icu.cc", "src/hb-icu.cc",
"src/hb-map.cc", "src/hb-map.cc",
"src/hb-number.cc", "src/hb-number.cc",
@ -331,6 +334,9 @@ thirdparty_harfbuzz_sources = [
"src/hb-ot-shape.cc", "src/hb-ot-shape.cc",
"src/hb-ot-tag.cc", "src/hb-ot-tag.cc",
"src/hb-ot-var.cc", "src/hb-ot-var.cc",
"src/hb-outline.cc",
"src/hb-paint-extents.cc",
"src/hb-paint.cc",
"src/hb-set.cc", "src/hb-set.cc",
"src/hb-shape-plan.cc", "src/hb-shape-plan.cc",
"src/hb-shape.cc", "src/hb-shape.cc",
@ -341,11 +347,13 @@ thirdparty_harfbuzz_sources = [
"src/hb-subset-cff1.cc", "src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc", "src/hb-subset-cff2.cc",
"src/hb-subset-input.cc", "src/hb-subset-input.cc",
"src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc", "src/hb-subset-plan.cc",
"src/hb-subset-repacker.cc",
"src/hb-subset.cc", "src/hb-subset.cc",
"src/hb-ucd.cc", "src/hb-ucd.cc",
"src/hb-unicode.cc", "src/hb-unicode.cc",
#'src/hb-uniscribe.cc' # "src/hb-uniscribe.cc",
] ]
if env["freetype_enabled"]: if env["freetype_enabled"]:

View file

@ -248,13 +248,15 @@ Files extracted from upstream source:
## harfbuzz ## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz - Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 6.0.0 (afcae83a064843d71d47624bc162e121cc56c08b, 2022) - Version: 7.1.0 (60841e26187576bff477c1a09ee2ffe544844abc, 2023)
- License: MIT - License: MIT
Files extracted from upstream source: Files extracted from upstream source:
- the `src` folder
- `AUTHORS`, `COPYING`, `THANKS` - `AUTHORS`, `COPYING`, `THANKS`
- from the `src` folder, recursively
- all the `*.c`, `*.cc`, `*.h`, `*.hh` files
- _except_ `main.cc`, `harfbuzz*.cc`, `failing-alloc.c`, `test*.cc`
## icu4c ## icu4c

View file

@ -2,19 +2,23 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
For parts of HarfBuzz that are licensed under different licenses see individual For parts of HarfBuzz that are licensed under different licenses see individual
files names COPYING in subdirectories where applicable. files names COPYING in subdirectories where applicable.
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc. Copyright © 2010-2022 Google, Inc.
Copyright © 2018,2019,2020 Ebrahim Byagowi Copyright © 2015-2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc. Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012 Mozilla Foundation Copyright © 2012,2015 Mozilla Foundation
Copyright © 2011 Codethink Limited Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International Copyright © 2011 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson Copyright © 2007 Chris Wilson
Copyright © 2005,2006,2020,2021 Behdad Esfahbod Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
Copyright © 2005 David Turner Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. Copyright © 1998-2005 David Turner and Werner Lemberg
Copyright © 1998-2004 David Turner and Werner Lemberg Copyright © 2016 Igalia S.L.
Copyright © 2022 Matthias Clasen
Copyright © 2018,2021 Khaled Hosny
Copyright © 2018,2019,2020 Adobe, Inc
Copyright © 2013-2015 Alexei Podtelezhnikov
For full copyright notices consult the individual files in the package. For full copyright notices consult the individual files in the package.

View file

@ -24,10 +24,11 @@
* Google Author(s): Seigo Nonaka, Calder Kitagawa * Google Author(s): Seigo Nonaka, Calder Kitagawa
*/ */
#ifndef HB_OT_COLOR_CBDT_TABLE_HH #ifndef OT_COLOR_CBDT_CBDT_HH
#define HB_OT_COLOR_CBDT_TABLE_HH #define OT_COLOR_CBDT_CBDT_HH
#include "hb-open-type.hh" #include "../../../hb-open-type.hh"
#include "../../../hb-paint.hh"
/* /*
* CBLC -- Color Bitmap Location * CBLC -- Color Bitmap Location
@ -80,12 +81,15 @@ struct SmallGlyphMetrics
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const
{ {
extents->x_bearing = font->em_scale_x (bearingX); extents->x_bearing = bearingX;
extents->y_bearing = font->em_scale_y (bearingY); extents->y_bearing = bearingY;
extents->width = font->em_scale_x (width); extents->width = width;
extents->height = font->em_scale_y (-static_cast<int>(height)); extents->height = -static_cast<int> (height);
if (scale)
font->scale_glyph_extents (extents);
} }
HBUINT8 height; HBUINT8 height;
@ -307,7 +311,7 @@ struct IndexSubtable
} }
} }
bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const
{ {
switch (u.header.indexFormat) switch (u.header.indexFormat)
{ {
@ -504,8 +508,8 @@ struct IndexSubtableRecord
return num_missing; return num_missing;
} }
bool get_extents (hb_glyph_extents_t *extents, const void *base) const bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const
{ return (base+offsetToSubtable).get_extents (extents); } { return (base+offsetToSubtable).get_extents (extents, scale); }
bool get_image_data (unsigned int gid, bool get_image_data (unsigned int gid,
const void *base, const void *base,
@ -833,7 +837,7 @@ struct CBDT
} }
bool bool
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const
{ {
const void *base; const void *base;
const BitmapSizeTable &strike = this->cblc->choose_strike (font); const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@ -841,7 +845,7 @@ struct CBDT
if (!subtable_record || !strike.ppemX || !strike.ppemY) if (!subtable_record || !strike.ppemX || !strike.ppemY)
return false; return false;
if (subtable_record->get_extents (extents, base)) if (subtable_record->get_extents (extents, base, scale))
return true; return true;
unsigned int image_offset = 0, image_length = 0, image_format = 0; unsigned int image_offset = 0, image_length = 0, image_format = 0;
@ -858,26 +862,29 @@ struct CBDT
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
return false; return false;
auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset); auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
glyphFormat17.glyphMetrics.get_extents (font, extents); glyphFormat17.glyphMetrics.get_extents (font, extents, scale);
break; break;
} }
case 18: { case 18: {
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
return false; return false;
auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset); auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
glyphFormat18.glyphMetrics.get_extents (font, extents); glyphFormat18.glyphMetrics.get_extents (font, extents, scale);
break; break;
} }
default: return false; /* TODO: Support other image formats. */ default: return false; /* TODO: Support other image formats. */
} }
/* Convert to font units. */ /* Convert to font units. */
if (scale)
{
float x_scale = upem / (float) strike.ppemX; float x_scale = upem / (float) strike.ppemX;
float y_scale = upem / (float) strike.ppemY; float y_scale = upem / (float) strike.ppemY;
extents->x_bearing = roundf (extents->x_bearing * x_scale); extents->x_bearing = roundf (extents->x_bearing * x_scale);
extents->y_bearing = roundf (extents->y_bearing * y_scale); extents->y_bearing = roundf (extents->y_bearing * y_scale);
extents->width = roundf (extents->width * x_scale); extents->width = roundf (extents->width * x_scale);
extents->height = roundf (extents->height * y_scale); extents->height = roundf (extents->height * y_scale);
}
return true; return true;
} }
@ -934,6 +941,32 @@ struct CBDT
bool has_data () const { return cbdt.get_length (); } bool has_data () const { return cbdt.get_length (); }
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
hb_glyph_extents_t extents;
hb_glyph_extents_t pixel_extents;
hb_blob_t *blob = reference_png (font, glyph);
if (unlikely (blob == hb_blob_get_empty ()))
return false;
if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents)))
return false;
if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
return false;
bool ret = funcs->image (data,
blob,
pixel_extents.width, -pixel_extents.height,
HB_PAINT_IMAGE_FORMAT_PNG,
font->slant_xy,
&extents);
hb_blob_destroy (blob);
return ret;
}
private: private:
hb_blob_ptr_t<CBLC> cblc; hb_blob_ptr_t<CBLC> cblc;
hb_blob_ptr_t<CBDT> cbdt; hb_blob_ptr_t<CBDT> cbdt;
@ -994,4 +1027,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t {
} /* namespace OT */ } /* namespace OT */
#endif /* HB_OT_COLOR_CBDT_TABLE_HH */ #endif /* OT_COLOR_CBDT_CBDT_HH */

View file

@ -25,12 +25,14 @@
* Google Author(s): Calder Kitagawa * Google Author(s): Calder Kitagawa
*/ */
#ifndef HB_OT_COLOR_COLR_TABLE_HH #ifndef OT_COLOR_COLR_COLR_HH
#define HB_OT_COLOR_COLR_TABLE_HH #define OT_COLOR_COLR_COLR_HH
#include "hb-open-type.hh" #include "../../../hb.hh"
#include "hb-ot-layout-common.hh" #include "../../../hb-open-type.hh"
#include "hb-ot-var-common.hh" #include "../../../hb-ot-var-common.hh"
#include "../../../hb-paint.hh"
#include "../../../hb-paint-extents.hh"
/* /*
* COLR -- Color * COLR -- Color
@ -38,13 +40,82 @@
*/ */
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R') #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
#ifndef HB_COLRV1_MAX_NESTING_LEVEL
#define HB_COLRV1_MAX_NESTING_LEVEL 16 namespace OT {
#endif struct hb_paint_context_t;
}
namespace OT { namespace OT {
struct COLR; struct COLR;
struct Paint;
struct hb_paint_context_t :
hb_dispatch_context_t<hb_paint_context_t>
{
template <typename T>
return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
static return_t default_return_value () { return hb_empty_t (); }
const COLR* get_colr_table () const
{ return reinterpret_cast<const COLR *> (base); }
public:
const void *base;
hb_paint_funcs_t *funcs;
void *data;
hb_font_t *font;
unsigned int palette_index;
hb_color_t foreground;
VarStoreInstancer &instancer;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
hb_paint_context_t (const void *base_,
hb_paint_funcs_t *funcs_,
void *data_,
hb_font_t *font_,
unsigned int palette_,
hb_color_t foreground_,
VarStoreInstancer &instancer_) :
base (base_),
funcs (funcs_),
data (data_),
font (font_),
palette_index (palette_),
foreground (foreground_),
instancer (instancer_)
{ }
hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
{
hb_color_t color = foreground;
*is_foreground = true;
if (color_index != 0xffff)
{
if (!funcs->custom_palette_color (data, color_index, &color))
{
unsigned int clen = 1;
hb_face_t *face = hb_font_get_face (font);
hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
}
*is_foreground = false;
}
return HB_COLOR (hb_color_get_blue (color),
hb_color_get_green (color),
hb_color_get_red (color),
hb_color_get_alpha (color) * alpha);
}
inline void recurse (const Paint &paint);
};
struct hb_colrv1_closure_context_t : struct hb_colrv1_closure_context_t :
hb_dispatch_context_t<hb_colrv1_closure_context_t> hb_dispatch_context_t<hb_colrv1_closure_context_t>
{ {
@ -98,7 +169,7 @@ struct hb_colrv1_closure_context_t :
hb_set_t *glyphs_, hb_set_t *glyphs_,
hb_set_t *layer_indices_, hb_set_t *layer_indices_,
hb_set_t *palette_indices_, hb_set_t *palette_indices_,
unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
base (base_), base (base_),
glyphs (glyphs_), glyphs (glyphs_),
layer_indices (layer_indices_), layer_indices (layer_indices_),
@ -160,6 +231,8 @@ struct BaseGlyphRecord
template <typename T> template <typename T>
struct Variable struct Variable
{ {
static constexpr bool is_variable = true;
Variable<T>* copy (hb_serialize_context_t *c) const Variable<T>* copy (hb_serialize_context_t *c) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
@ -182,6 +255,23 @@ struct Variable
return_trace (c->check_struct (this) && value.sanitize (c)); return_trace (c->check_struct (this) && value.sanitize (c));
} }
void paint_glyph (hb_paint_context_t *c) const
{
value.paint_glyph (c, varIdxBase);
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
const VarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, varIdxBase, instancer);
}
hb_paint_extend_t get_extend () const
{
return value.get_extend ();
}
protected: protected:
T value; T value;
public: public:
@ -193,6 +283,8 @@ struct Variable
template <typename T> template <typename T>
struct NoVariable struct NoVariable
{ {
static constexpr bool is_variable = false;
static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION; static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
NoVariable<T>* copy (hb_serialize_context_t *c) const NoVariable<T>* copy (hb_serialize_context_t *c) const
@ -216,6 +308,23 @@ struct NoVariable
return_trace (c->check_struct (this) && value.sanitize (c)); return_trace (c->check_struct (this) && value.sanitize (c));
} }
void paint_glyph (hb_paint_context_t *c) const
{
value.paint_glyph (c, varIdxBase);
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
const VarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
}
hb_paint_extend_t get_extend () const
{
return value.get_extend ();
}
T value; T value;
public: public:
DEFINE_SIZE_STATIC (T::static_size); DEFINE_SIZE_STATIC (T::static_size);
@ -233,7 +342,7 @@ struct ColorStop
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this); auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW)); HB_SERIALIZE_ERROR_INT_OVERFLOW));
} }
@ -243,6 +352,17 @@ struct ColorStop
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *out,
uint32_t varIdx,
const VarStoreInstancer &instancer) const
{
out->offset = stopOffset.to_float(instancer (varIdx, 0));
out->color = c->get_color (paletteIndex,
alpha.to_float (instancer (varIdx, 1)),
&out->is_foreground);
}
F2DOT14 stopOffset; F2DOT14 stopOffset;
HBUINT16 paletteIndex; HBUINT16 paletteIndex;
F2DOT14 alpha; F2DOT14 alpha;
@ -294,6 +414,52 @@ struct ColorLine
stops.sanitize (c)); stops.sanitize (c));
} }
/* get up to count stops from start */
unsigned int
get_color_stops (hb_paint_context_t *c,
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops,
const VarStoreInstancer &instancer) const
{
unsigned int len = stops.len;
if (count && color_stops)
{
unsigned int i;
for (i = 0; i < *count && start + i < len; i++)
stops[start + i].get_color_stop (c, &color_stops[i], instancer);
*count = i;
}
return len;
}
HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
void *color_line_data,
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops,
void *user_data)
{
const ColorLine *thiz = (const ColorLine *) color_line_data;
hb_paint_context_t *c = (hb_paint_context_t *) user_data;
return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
}
hb_paint_extend_t get_extend () const
{
return (hb_paint_extend_t) (unsigned int) extend;
}
HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
void *color_line_data,
void *user_data)
{
const ColorLine *thiz = (const ColorLine *) color_line_data;
return thiz->get_extend ();
}
Extend extend; Extend extend;
Array16Of<Var<ColorStop>> stops; Array16Of<Var<ColorStop>> stops;
public: public:
@ -357,6 +523,17 @@ struct Affine2x3
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
c->funcs->push_transform (c->data,
xx.to_float (c->instancer (varIdxBase, 0)),
yx.to_float (c->instancer (varIdxBase, 1)),
xy.to_float (c->instancer (varIdxBase, 2)),
yy.to_float (c->instancer (varIdxBase, 3)),
dx.to_float (c->instancer (varIdxBase, 4)),
dy.to_float (c->instancer (varIdxBase, 5)));
}
F16DOT16 xx; F16DOT16 xx;
F16DOT16 yx; F16DOT16 yx;
F16DOT16 xy; F16DOT16 xy;
@ -376,7 +553,7 @@ struct PaintColrLayers
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex), return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW)); HB_SERIALIZE_ERROR_INT_OVERFLOW));
return_trace (true); return_trace (true);
@ -388,6 +565,8 @@ struct PaintColrLayers
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
inline void paint_glyph (hb_paint_context_t *c) const;
HBUINT8 format; /* format = 1 */ HBUINT8 format; /* format = 1 */
HBUINT8 numLayers; HBUINT8 numLayers;
HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */
@ -405,7 +584,7 @@ struct PaintSolid
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this); auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW)); HB_SERIALIZE_ERROR_INT_OVERFLOW));
} }
@ -415,6 +594,17 @@ struct PaintSolid
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
hb_bool_t is_foreground;
hb_color_t color;
color = c->get_color (paletteIndex,
alpha.to_float (c->instancer (varIdxBase, 0)),
&is_foreground);
c->funcs->color (c->data, is_foreground, color);
}
HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ HBUINT8 format; /* format = 2(noVar) or 3(Var)*/
HBUINT16 paletteIndex; HBUINT16 paletteIndex;
F2DOT14 alpha; F2DOT14 alpha;
@ -443,6 +633,23 @@ struct PaintLinearGradient
return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
hb_color_line_t cl = {
(void *) &(this+colorLine),
(this+colorLine).static_get_color_stops, c,
(this+colorLine).static_get_extend, nullptr
};
c->funcs->linear_gradient (c->data, &cl,
x0 + c->instancer (varIdxBase, 0),
y0 + c->instancer (varIdxBase, 1),
x1 + c->instancer (varIdxBase, 2),
y1 + c->instancer (varIdxBase, 3),
x2 + c->instancer (varIdxBase, 4),
y2 + c->instancer (varIdxBase, 5));
}
HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ HBUINT8 format; /* format = 4(noVar) or 5 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient
* table) to ColorLine subtable. */ * table) to ColorLine subtable. */
@ -477,6 +684,23 @@ struct PaintRadialGradient
return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
hb_color_line_t cl = {
(void *) &(this+colorLine),
(this+colorLine).static_get_color_stops, c,
(this+colorLine).static_get_extend, nullptr
};
c->funcs->radial_gradient (c->data, &cl,
x0 + c->instancer (varIdxBase, 0),
y0 + c->instancer (varIdxBase, 1),
radius0 + c->instancer (varIdxBase, 2),
x1 + c->instancer (varIdxBase, 3),
y1 + c->instancer (varIdxBase, 4),
radius1 + c->instancer (varIdxBase, 5));
}
HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ HBUINT8 format; /* format = 6(noVar) or 7 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient
* table) to ColorLine subtable. */ * table) to ColorLine subtable. */
@ -511,6 +735,21 @@ struct PaintSweepGradient
return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
hb_color_line_t cl = {
(void *) &(this+colorLine),
(this+colorLine).static_get_color_stops, c,
(this+colorLine).static_get_extend, nullptr
};
c->funcs->sweep_gradient (c->data, &cl,
centerX + c->instancer (varIdxBase, 0),
centerY + c->instancer (varIdxBase, 1),
(startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * (float) M_PI,
(endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * (float) M_PI);
}
HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient
* table) to ColorLine subtable. */ * table) to ColorLine subtable. */
@ -522,8 +761,6 @@ struct PaintSweepGradient
DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
}; };
struct Paint;
// Paint a non-COLR glyph, filled as indicated by paint. // Paint a non-COLR glyph, filled as indicated by paint.
struct PaintGlyph struct PaintGlyph
{ {
@ -548,6 +785,17 @@ struct PaintGlyph
return_trace (c->check_struct (this) && paint.sanitize (c, this)); return_trace (c->check_struct (this) && paint.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c) const
{
c->funcs->push_inverse_root_transform (c->data, c->font);
c->funcs->push_clip_glyph (c->data, gid, c->font);
c->funcs->push_root_transform (c->data, c->font);
c->recurse (this+paint);
c->funcs->pop_transform (c->data);
c->funcs->pop_clip (c->data);
c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 10 */ HBUINT8 format; /* format = 10 */
Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
HBUINT16 gid; HBUINT16 gid;
@ -575,6 +823,8 @@ struct PaintColrGlyph
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
inline void paint_glyph (hb_paint_context_t *c) const;
HBUINT8 format; /* format = 11 */ HBUINT8 format; /* format = 11 */
HBUINT16 gid; HBUINT16 gid;
public: public:
@ -603,6 +853,13 @@ struct PaintTransform
transform.sanitize (c, this)); transform.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c) const
{
(this+transform).paint_glyph (c);
c->recurse (this+src);
c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ HBUINT8 format; /* format = 12(noVar) or 13 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
Offset24To<Var<Affine2x3>> transform; Offset24To<Var<Affine2x3>> transform;
@ -629,6 +886,16 @@ struct PaintTranslate
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float ddx = dx + c->instancer (varIdxBase, 0);
float ddy = dy + c->instancer (varIdxBase, 1);
bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
c->recurse (this+src);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ HBUINT8 format; /* format = 14(noVar) or 15 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
FWORD dx; FWORD dx;
@ -656,6 +923,16 @@ struct PaintScale
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
bool p1 = c->funcs->push_scale (c->data, sx, sy);
c->recurse (this+src);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ HBUINT8 format; /* format = 16 (noVar) or 17(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScale table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
F2DOT14 scaleX; F2DOT14 scaleX;
@ -683,6 +960,22 @@ struct PaintScaleAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
float tCenterX = centerX + c->instancer (varIdxBase, 2);
float tCenterY = centerY + c->instancer (varIdxBase, 3);
bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
bool p2 = c->funcs->push_scale (c->data, sx, sy);
bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
c->recurse (this+src);
if (p3) c->funcs->pop_transform (c->data);
if (p2) c->funcs->pop_transform (c->data);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ HBUINT8 format; /* format = 18 (noVar) or 19(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
F2DOT14 scaleX; F2DOT14 scaleX;
@ -712,6 +1005,15 @@ struct PaintScaleUniform
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float s = scale.to_float (c->instancer (varIdxBase, 0));
bool p1 = c->funcs->push_scale (c->data, s, s);
c->recurse (this+src);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ HBUINT8 format; /* format = 20 (noVar) or 21(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
F2DOT14 scale; F2DOT14 scale;
@ -738,6 +1040,21 @@ struct PaintScaleUniformAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float s = scale.to_float (c->instancer (varIdxBase, 0));
float tCenterX = centerX + c->instancer (varIdxBase, 1);
float tCenterY = centerY + c->instancer (varIdxBase, 2);
bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
bool p2 = c->funcs->push_scale (c->data, s, s);
bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
c->recurse (this+src);
if (p3) c->funcs->pop_transform (c->data);
if (p2) c->funcs->pop_transform (c->data);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ HBUINT8 format; /* format = 22 (noVar) or 23(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
F2DOT14 scale; F2DOT14 scale;
@ -766,6 +1083,15 @@ struct PaintRotate
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float a = angle.to_float (c->instancer (varIdxBase, 0));
bool p1 = c->funcs->push_rotate (c->data, a);
c->recurse (this+src);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ HBUINT8 format; /* format = 24 (noVar) or 25(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
F2DOT14 angle; F2DOT14 angle;
@ -792,6 +1118,21 @@ struct PaintRotateAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float a = angle.to_float (c->instancer (varIdxBase, 0));
float tCenterX = centerX + c->instancer (varIdxBase, 1);
float tCenterY = centerY + c->instancer (varIdxBase, 2);
bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
bool p2 = c->funcs->push_rotate (c->data, a);
bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
c->recurse (this+src);
if (p3) c->funcs->pop_transform (c->data);
if (p2) c->funcs->pop_transform (c->data);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ HBUINT8 format; /* format = 26 (noVar) or 27(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
F2DOT14 angle; F2DOT14 angle;
@ -820,6 +1161,16 @@ struct PaintSkew
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
bool p1 = c->funcs->push_skew (c->data, sx, sy);
c->recurse (this+src);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ HBUINT8 format; /* format = 28(noVar) or 29 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
F2DOT14 xSkewAngle; F2DOT14 xSkewAngle;
@ -847,6 +1198,22 @@ struct PaintSkewAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this)); return_trace (c->check_struct (this) && src.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
float tCenterX = centerX + c->instancer (varIdxBase, 2);
float tCenterY = centerY + c->instancer (varIdxBase, 3);
bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
bool p2 = c->funcs->push_skew (c->data, sx, sy);
bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
c->recurse (this+src);
if (p3) c->funcs->pop_transform (c->data);
if (p2) c->funcs->pop_transform (c->data);
if (p1) c->funcs->pop_transform (c->data);
}
HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ HBUINT8 format; /* format = 30(noVar) or 31 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
F2DOT14 xSkewAngle; F2DOT14 xSkewAngle;
@ -879,6 +1246,14 @@ struct PaintComposite
backdrop.sanitize (c, this)); backdrop.sanitize (c, this));
} }
void paint_glyph (hb_paint_context_t *c) const
{
c->recurse (this+backdrop);
c->funcs->push_group (c->data);
c->recurse (this+src);
c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
}
HBUINT8 format; /* format = 32 */ HBUINT8 format; /* format = 32 */
Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */
@ -948,8 +1323,8 @@ struct ClipBox
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
@ -1084,7 +1459,7 @@ struct ClipList
if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
const hb_set_t& glyphset = *c->plan->_glyphset_colred; const hb_set_t& glyphset = c->plan->_glyphset_colred;
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_map_t new_gid_offset_map; hb_map_t new_gid_offset_map;
@ -1142,7 +1517,7 @@ struct Paint
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
return_trace (c->no_dispatch_return_value ()); return_trace (c->no_dispatch_return_value ());
return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...))); return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
@ -1151,8 +1526,8 @@ struct Paint
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...)); case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
@ -1194,35 +1569,35 @@ struct Paint
union { union {
HBUINT8 format; HBUINT8 format;
PaintColrLayers paintformat1; PaintColrLayers paintformat1;
PaintSolid paintformat2; NoVariable<PaintSolid> paintformat2;
Variable<PaintSolid> paintformat3; Variable<PaintSolid> paintformat3;
PaintLinearGradient<NoVariable> paintformat4; NoVariable<PaintLinearGradient<NoVariable>> paintformat4;
Variable<PaintLinearGradient<Variable>> paintformat5; Variable<PaintLinearGradient<Variable>> paintformat5;
PaintRadialGradient<NoVariable> paintformat6; NoVariable<PaintRadialGradient<NoVariable>> paintformat6;
Variable<PaintRadialGradient<Variable>> paintformat7; Variable<PaintRadialGradient<Variable>> paintformat7;
PaintSweepGradient<NoVariable> paintformat8; NoVariable<PaintSweepGradient<NoVariable>> paintformat8;
Variable<PaintSweepGradient<Variable>> paintformat9; Variable<PaintSweepGradient<Variable>> paintformat9;
PaintGlyph paintformat10; PaintGlyph paintformat10;
PaintColrGlyph paintformat11; PaintColrGlyph paintformat11;
PaintTransform<NoVariable> paintformat12; PaintTransform<NoVariable> paintformat12;
PaintTransform<Variable> paintformat13; PaintTransform<Variable> paintformat13;
PaintTranslate paintformat14; NoVariable<PaintTranslate> paintformat14;
Variable<PaintTranslate> paintformat15; Variable<PaintTranslate> paintformat15;
PaintScale paintformat16; NoVariable<PaintScale> paintformat16;
Variable<PaintScale> paintformat17; Variable<PaintScale> paintformat17;
PaintScaleAroundCenter paintformat18; NoVariable<PaintScaleAroundCenter> paintformat18;
Variable<PaintScaleAroundCenter> paintformat19; Variable<PaintScaleAroundCenter> paintformat19;
PaintScaleUniform paintformat20; NoVariable<PaintScaleUniform> paintformat20;
Variable<PaintScaleUniform> paintformat21; Variable<PaintScaleUniform> paintformat21;
PaintScaleUniformAroundCenter paintformat22; NoVariable<PaintScaleUniformAroundCenter> paintformat22;
Variable<PaintScaleUniformAroundCenter> paintformat23; Variable<PaintScaleUniformAroundCenter> paintformat23;
PaintRotate paintformat24; NoVariable<PaintRotate> paintformat24;
Variable<PaintRotate> paintformat25; Variable<PaintRotate> paintformat25;
PaintRotateAroundCenter paintformat26; NoVariable<PaintRotateAroundCenter> paintformat26;
Variable<PaintRotateAroundCenter> paintformat27; Variable<PaintRotateAroundCenter> paintformat27;
PaintSkew paintformat28; NoVariable<PaintSkew> paintformat28;
Variable<PaintSkew> paintformat29; Variable<PaintSkew> paintformat29;
PaintSkewAroundCenter paintformat30; NoVariable<PaintSkewAroundCenter> paintformat30;
Variable<PaintSkewAroundCenter> paintformat31; Variable<PaintSkewAroundCenter> paintformat31;
PaintComposite paintformat32; PaintComposite paintformat32;
} u; } u;
@ -1269,7 +1644,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
const hb_set_t* glyphset = c->plan->_glyphset_colred; const hb_set_t* glyphset = &c->plan->_glyphset_colred;
for (const auto& _ : as_array ()) for (const auto& _ : as_array ())
{ {
@ -1323,7 +1698,14 @@ struct COLR
{ {
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
bool has_data () const { return numBaseGlyphs; } bool has_v0_data () const { return numBaseGlyphs; }
bool has_v1_data () const
{
if (version == 1)
return (this+baseGlyphList).len > 0;
return false;
}
unsigned int get_glyph_layers (hb_codepoint_t glyph, unsigned int get_glyph_layers (hb_codepoint_t glyph,
unsigned int start_offset, unsigned int start_offset,
@ -1503,7 +1885,7 @@ struct COLR
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
const hb_set_t& glyphset = *c->plan->_glyphset_colred; const hb_set_t& glyphset = c->plan->_glyphset_colred;
auto base_it = auto base_it =
+ hb_range (c->plan->num_output_glyphs ()) + hb_range (c->plan->num_output_glyphs ())
@ -1552,7 +1934,7 @@ struct COLR
if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
out_layers[i].glyphId = new_gid; out_layers[i].glyphId = new_gid;
out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
} }
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers); return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
@ -1585,10 +1967,23 @@ struct COLR
colr_prime->layerList.serialize_subset (c, layerList, this); colr_prime->layerList.serialize_subset (c, layerList, this);
colr_prime->clipList.serialize_subset (c, clipList, this); colr_prime->clipList.serialize_subset (c, clipList, this);
colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
//TODO: subset varStore once it's implemented in fonttools colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
return_trace (true); return_trace (true);
} }
const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
{
const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
if (record)
{
const Paint &paint = &baseglyph_paintrecords+record->paint;
return &paint;
}
else
return nullptr;
}
bool bool
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{ {
@ -1599,14 +1994,138 @@ struct COLR
this+varIdxMap, this+varIdxMap,
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
if ((this+clipList).get_extents (glyph, if (get_clip (glyph, extents, instancer))
extents,
instancer))
{ {
extents->x_bearing = font->em_scale_x (extents->x_bearing); font->scale_glyph_extents (extents);
extents->y_bearing = font->em_scale_x (extents->y_bearing); return true;
extents->width = font->em_scale_x (extents->width); }
extents->height = font->em_scale_x (extents->height);
auto *extents_funcs = hb_paint_extents_get_funcs ();
hb_paint_extents_context_t extents_data;
bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
hb_extents_t e = extents_data.get_extents ();
if (e.is_void ())
{
extents->x_bearing = 0;
extents->y_bearing = 0;
extents->width = 0;
extents->height = 0;
}
else
{
extents->x_bearing = e.xmin;
extents->y_bearing = e.ymax;
extents->width = e.xmax - e.xmin;
extents->height = e.ymin - e.ymax;
}
return ret;
}
bool
has_paint_for_glyph (hb_codepoint_t glyph) const
{
if (version == 1)
{
const Paint *paint = get_base_glyph_paint (glyph);
return paint != nullptr;
}
return false;
}
bool get_clip (hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
const VarStoreInstancer instancer) const
{
return (this+clipList).get_extents (glyph,
extents,
instancer);
}
bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{
VarStoreInstancer instancer (this+varStore,
this+varIdxMap,
hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
if (version == 1)
{
const Paint *paint = get_base_glyph_paint (glyph);
if (paint)
{
// COLRv1 glyph
VarStoreInstancer instancer (this+varStore,
this+varIdxMap,
hb_array (font->coords, font->num_coords));
bool is_bounded = true;
if (clip)
{
hb_glyph_extents_t extents;
if (get_clip (glyph, &extents, instancer))
{
font->scale_glyph_extents (&extents);
c.funcs->push_clip_rectangle (c.data,
extents.x_bearing,
extents.y_bearing + extents.height,
extents.x_bearing + extents.width,
extents.y_bearing);
}
else
{
auto *extents_funcs = hb_paint_extents_get_funcs ();
hb_paint_extents_context_t extents_data;
paint_glyph (font, glyph,
extents_funcs, &extents_data,
palette_index, foreground,
false);
hb_extents_t extents = extents_data.get_extents ();
is_bounded = extents_data.is_bounded ();
c.funcs->push_clip_rectangle (c.data,
extents.xmin,
extents.ymin,
extents.xmax,
extents.ymax);
}
}
c.funcs->push_root_transform (c.data, font);
if (is_bounded)
c.recurse (*paint);
c.funcs->pop_transform (c.data);
if (clip)
c.funcs->pop_clip (c.data);
return true;
}
}
const BaseGlyphRecord *record = get_base_glyph_record (glyph);
if (record && ((hb_codepoint_t) record->glyphId == glyph))
{
// COLRv0 glyph
for (const auto &r : (this+layersZ).as_array (numLayers)
.sub_array (record->firstLayerIdx, record->numLayers))
{
hb_bool_t is_foreground;
hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
c.funcs->color (c.data, is_foreground, color);
c.funcs->pop_clip (c.data);
}
return true; return true;
} }
@ -1635,7 +2154,50 @@ struct COLR_accelerator_t : COLR::accelerator_t {
COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
}; };
void
hb_paint_context_t::recurse (const Paint &paint)
{
if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
depth_left--;
edge_count--;
paint.dispatch (this);
depth_left++;
}
void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
{
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
const Paint &paint = paint_offset_lists.get_paint (i);
c->funcs->push_group (c->data);
c->recurse (paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
}
}
void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
{
const COLR *colr_table = c->get_colr_table ();
const Paint *paint = colr_table->get_base_glyph_paint (gid);
hb_glyph_extents_t extents = {0};
bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
if (has_clip_box)
c->funcs->push_clip_rectangle (c->data,
extents.x_bearing,
extents.y_bearing + extents.height,
extents.x_bearing + extents.width,
extents.y_bearing);
if (paint)
c->recurse (*paint);
if (has_clip_box)
c->funcs->pop_clip (c->data);
}
} /* namespace OT */ } /* namespace OT */
#endif /* OT_COLOR_COLR_COLR_HH */
#endif /* HB_OT_COLOR_COLR_TABLE_HH */

View file

@ -24,12 +24,11 @@
* *
*/ */
#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH #ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH
#define HB_OT_COLR_COLRV1_CLOSURE_HH #define OT_COLOR_COLR_COLRV1_CLOSURE_HH
#include "hb-open-type.hh" #include "../../../hb-open-type.hh"
#include "hb-ot-layout-common.hh" #include "COLR.hh"
#include "hb-ot-color-colr-table.hh"
/* /*
* COLR -- Color * COLR -- Color
@ -105,4 +104,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons
} /* namespace OT */ } /* namespace OT */
#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */ #endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */

View file

@ -25,12 +25,12 @@
* Google Author(s): Sascha Brawer * Google Author(s): Sascha Brawer
*/ */
#ifndef HB_OT_COLOR_CPAL_TABLE_HH #ifndef OT_COLOR_CPAL_CPAL_HH
#define HB_OT_COLOR_CPAL_TABLE_HH #define OT_COLOR_CPAL_CPAL_HH
#include "hb-open-type.hh" #include "../../../hb-open-type.hh"
#include "hb-ot-color.h" #include "../../../hb-ot-color.h"
#include "hb-ot-name.h" #include "../../../hb-ot-name.h"
/* /*
@ -239,7 +239,7 @@ struct CPAL
TRACE_SUBSET (this); TRACE_SUBSET (this);
if (!numPalettes) return_trace (false); if (!numPalettes) return_trace (false);
const hb_map_t *color_index_map = c->plan->colr_palettes; const hb_map_t *color_index_map = &c->plan->colr_palettes;
if (color_index_map->is_empty ()) return_trace (false); if (color_index_map->is_empty ()) return_trace (false);
hb_set_t retained_color_indices; hb_set_t retained_color_indices;
@ -319,4 +319,4 @@ struct CPAL
} /* namespace OT */ } /* namespace OT */
#endif /* HB_OT_COLOR_CPAL_TABLE_HH */ #endif /* OT_COLOR_CPAL_CPAL_HH */

View file

@ -25,11 +25,11 @@
* Google Author(s): Calder Kitagawa * Google Author(s): Calder Kitagawa
*/ */
#ifndef HB_OT_COLOR_SBIX_TABLE_HH #ifndef OT_COLOR_SBIX_SBIX_HH
#define HB_OT_COLOR_SBIX_TABLE_HH #define OT_COLOR_SBIX_SBIX_HH
#include "hb-open-type.hh" #include "../../../hb-open-type.hh"
#include "hb-ot-layout-common.hh" #include "../../../hb-paint.hh"
/* /*
* sbix -- Standard Bitmap Graphics * sbix -- Standard Bitmap Graphics
@ -213,10 +213,11 @@ struct sbix
bool get_extents (hb_font_t *font, bool get_extents (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const hb_glyph_extents_t *extents,
bool scale = true) const
{ {
/* We only support PNG right now, and following function checks type. */ /* We only support PNG right now, and following function checks type. */
return get_png_extents (font, glyph, extents); return get_png_extents (font, glyph, extents, scale);
} }
hb_blob_t *reference_png (hb_font_t *font, hb_blob_t *reference_png (hb_font_t *font,
@ -231,6 +232,37 @@ struct sbix
num_glyphs, available_ppem); num_glyphs, available_ppem);
} }
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ())
return false;
int x_offset = 0, y_offset = 0;
unsigned int strike_ppem = 0;
hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
hb_glyph_extents_t extents;
hb_glyph_extents_t pixel_extents;
if (blob == hb_blob_get_empty ())
return false;
if (!hb_font_get_glyph_extents (font, glyph, &extents))
return false;
if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
return false;
bool ret = funcs->image (data,
blob,
pixel_extents.width, -pixel_extents.height,
HB_PAINT_IMAGE_FORMAT_PNG,
font->slant_xy,
&extents);
hb_blob_destroy (blob);
return ret;
}
private: private:
const SBIXStrike &choose_strike (hb_font_t *font) const const SBIXStrike &choose_strike (hb_font_t *font) const
@ -285,7 +317,8 @@ struct sbix
bool get_png_extents (hb_font_t *font, bool get_png_extents (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const hb_glyph_extents_t *extents,
bool scale = true) const
{ {
/* Following code is safe to call even without data. /* Following code is safe to call even without data.
* But faster to short-circuit. */ * But faster to short-circuit. */
@ -310,22 +343,18 @@ struct sbix
extents->height = -1 * png.IHDR.height; extents->height = -1 * png.IHDR.height;
/* Convert to font units. */ /* Convert to font units. */
if (strike_ppem) if (strike_ppem && scale)
{ {
float scale = font->face->get_upem () / (float) strike_ppem; float scale = font->face->get_upem () / (float) strike_ppem;
extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); extents->x_bearing = roundf (extents->x_bearing * scale);
extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); extents->y_bearing = roundf (extents->y_bearing * scale);
extents->width = font->em_scalef_x (extents->width * scale); extents->width = roundf (extents->width * scale);
extents->height = font->em_scalef_y (extents->height * scale); extents->height = roundf (extents->height * scale);
}
else
{
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_y (extents->y_bearing);
extents->width = font->em_scale_x (extents->width);
extents->height = font->em_scale_y (extents->height);
} }
if (scale)
font->scale_glyph_extents (extents);
hb_blob_destroy (blob); hb_blob_destroy (blob);
return strike_ppem; return strike_ppem;
@ -420,4 +449,4 @@ struct sbix_accelerator_t : sbix::accelerator_t {
} /* namespace OT */ } /* namespace OT */
#endif /* HB_OT_COLOR_SBIX_TABLE_HH */ #endif /* OT_COLOR_SBIX_SBIX_HH */

View file

@ -22,10 +22,12 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/ */
#ifndef HB_OT_COLOR_SVG_TABLE_HH #ifndef OT_COLOR_SVG_SVG_HH
#define HB_OT_COLOR_SVG_TABLE_HH #define OT_COLOR_SVG_SVG_HH
#include "hb-open-type.hh" #include "../../../hb-open-type.hh"
#include "../../../hb-blob.hh"
#include "../../../hb-paint.hh"
/* /*
* SVG -- SVG (Scalable Vector Graphics) * SVG -- SVG (Scalable Vector Graphics)
@ -91,8 +93,31 @@ struct SVG
bool has_data () const { return table->has_data (); } bool has_data () const { return table->has_data (); }
bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ())
return false;
hb_blob_t *blob = reference_blob_for_glyph (glyph);
if (blob == hb_blob_get_empty ())
return false;
funcs->image (data,
blob,
0, 0,
HB_PAINT_IMAGE_FORMAT_SVG,
font->slant_xy,
nullptr);
hb_blob_destroy (blob);
return true;
}
private: private:
hb_blob_ptr_t<SVG> table; hb_blob_ptr_t<SVG> table;
public:
DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t<SVG>));
}; };
const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
@ -123,4 +148,4 @@ struct SVG_accelerator_t : SVG::accelerator_t {
} /* namespace OT */ } /* namespace OT */
#endif /* HB_OT_COLOR_SVG_TABLE_HH */ #endif /* OT_COLOR_SVG_SVG_HH */

View file

@ -147,6 +147,7 @@ struct Coverage
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto it = auto it =
+ iter () + iter ()
| hb_take (c->plan->source->get_num_glyphs ())
| hb_filter (c->plan->glyph_map_gsub) | hb_filter (c->plan->glyph_map_gsub)
| hb_map_retains_sorting (c->plan->glyph_map_gsub) | hb_map_retains_sorting (c->plan->glyph_map_gsub)
; ;

View file

@ -0,0 +1,918 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2011,2012 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.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef OT_LAYOUT_GDEF_GDEF_HH
#define OT_LAYOUT_GDEF_GDEF_HH
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-font.hh"
namespace OT {
/*
* Attachment List Table
*/
/* Array of contour point indices--in increasing numerical order */
struct AttachPoint : Array16Of<HBUINT16>
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (out->serialize (c->serializer, + iter ()));
}
};
struct AttachList
{
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (point_count)
*point_count = 0;
return 0;
}
const AttachPoint &points = this+attachPoint[index];
if (point_count)
{
+ points.as_array ().sub_array (start_offset, point_count)
| hb_sink (hb_array (point_array, *point_count))
;
}
return points.len;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, attachPoint)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
}
protected:
Offset16To<Coverage>
coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
Array16OfOffset16To<AttachPoint>
attachPoint; /* Array of AttachPoint tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, attachPoint);
};
/*
* Ligature Caret Table
*/
struct CaretValueFormat1
{
friend struct CaretValue;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (true);
}
private:
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 1 */
FWORD coordinate; /* X or Y value, in design units */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat2
{
friend struct CaretValue;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (true);
}
private:
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
{
hb_position_t x, y;
font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 2 */
HBUINT16 caretValuePoint; /* Contour point index on glyph */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat3
{
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
if (!c->serializer->embed (caretValueFormat)) return_trace (false);
if (!c->serializer->embed (coordinate)) return_trace (false);
unsigned varidx = (this+deviceTable).get_variation_index ();
if (c->plan->layout_variation_idx_delta_map.has (varidx))
{
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
}
if (c->plan->all_axes_pinned)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
return_trace (false);
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ (this+deviceTable).collect_variation_indices (c); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */
Offset16To<Device>
deviceTable; /* Offset to Device table for X or Y
* value--from beginning of CaretValue
* table */
public:
DEFINE_SIZE_STATIC (6);
};
struct CaretValue
{
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
case 2: return u.format2.get_caret_value (font, direction, glyph_id);
case 3: return u.format3.get_caret_value (font, direction, var_store);
default:return 0;
}
}
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.format) {
case 1:
case 2:
return;
case 3:
u.format3.collect_variation_indices (c);
return;
default: return;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
CaretValueFormat1 format1;
CaretValueFormat2 format2;
CaretValueFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct LigGlyph
{
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
if (caret_count)
{
+ carets.as_array ().sub_array (start_offset, caret_count)
| hb_map (hb_add (this))
| hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
| hb_sink (hb_array (caret_array, *caret_count))
;
}
return carets.len;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_iter (carets)
| hb_apply (subset_offset_array (c, out->carets, this))
;
return_trace (bool (out->carets));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (const Offset16To<CaretValue>& offset : carets.iter ())
(this+offset).collect_variation_indices (c);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (carets.sanitize (c, this));
}
protected:
Array16OfOffset16To<CaretValue>
carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
* --in increasing coordinate order */
public:
DEFINE_SIZE_ARRAY (2, carets);
};
struct LigCaretList
{
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (caret_count)
*caret_count = 0;
return 0;
}
const LigGlyph &lig_glyph = this+ligGlyph[index];
return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, ligGlyph)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+coverage, ligGlyph)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
}
protected:
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
Array16OfOffset16To<LigGlyph>
ligGlyph; /* Array of LigGlyph tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, ligGlyph);
};
struct MarkGlyphSetsFormat1
{
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
bool ret = true;
for (const Offset32To<Coverage>& offset : coverage.iter ())
{
auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o))
{
ret = false;
break;
}
//not using o->serialize_subset (c, offset, this, out) here because
//OTS doesn't allow null offset.
//See issue: https://github.com/khaledhosny/ots/issues/172
c->serializer->push ();
c->dispatch (this+offset);
c->serializer->add_link (*o, c->serializer->pop_pack ());
}
return_trace (ret && out->coverage.len);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Array16Of<Offset32To<Coverage>>
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
DEFINE_SIZE_ARRAY (4, coverage);
};
struct MarkGlyphSets
{
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1: return u.format1.covers (set_index, glyph_id);
default:return false;
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
switch (u.format) {
case 1: return_trace (u.format1.subset (c));
default:return_trace (false);
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
MarkGlyphSetsFormat1 format1;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/*
* GDEF -- Glyph Definition
* https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
*/
template <typename Types>
struct GDEFVersion1_2
{
friend struct GDEF;
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
* 0x00010003u */
typename Types::template OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
* GDEF header (may be Null) */
typename Types::template OffsetTo<AttachList>
attachList; /* Offset to list of glyphs with
* attachment points--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<LigCaretList>
ligCaretList; /* Offset to list of positioning points
* for ligature carets--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<ClassDef>
markAttachClassDef; /* Offset to class definition table for
* mark attachment type--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<MarkGlyphSets>
markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
Offset32To<VariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010003. */
public:
DEFINE_SIZE_MIN (4 + 4 * Types::size);
unsigned int get_size () const
{
return min_size +
(version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
(version.to_int () >= 0x00010003u ? varStore.static_size : 0);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
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)));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_markglyphsetsdef = false;
if (version.to_int () >= 0x00010002u)
{
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
}
bool subset_varstore = false;
if (version.to_int () >= 0x00010003u)
{
if (c->plan->all_axes_pinned)
out->varStore = 0;
else
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
}
if (subset_varstore)
{
out->version.minor = 3;
} else if (subset_markglyphsetsdef) {
out->version.minor = 2;
} else {
out->version.minor = 0;
}
return_trace (subset_glyphclassdef || subset_attachlist ||
subset_ligcaretlist || subset_markattachclassdef ||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
(out->version.to_int () >= 0x00010003u && subset_varstore));
}
};
struct GDEF
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses {
UnclassifiedGlyph = 0,
BaseGlyph = 1,
LigatureGlyph = 2,
MarkGlyph = 3,
ComponentGlyph = 4
};
unsigned int get_size () const
{
switch (u.version.major) {
case 1: return u.version1.get_size ();
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.get_size ();
#endif
default: return u.version.static_size;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false);
switch (u.version.major) {
case 1: return_trace (u.version1.sanitize (c));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (u.version2.sanitize (c));
#endif
default: return_trace (true);
}
}
bool subset (hb_subset_context_t *c) const
{
switch (u.version.major) {
case 1: return u.version1.subset (c);
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.subset (c);
#endif
default: return false;
}
}
bool has_glyph_classes () const
{
switch (u.version.major) {
case 1: return u.version1.glyphClassDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.glyphClassDef != 0;
#endif
default: return false;
}
}
const ClassDef &get_glyph_class_def () const
{
switch (u.version.major) {
case 1: return this+u.version1.glyphClassDef;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.glyphClassDef;
#endif
default: return Null(ClassDef);
}
}
bool has_attach_list () const
{
switch (u.version.major) {
case 1: return u.version1.attachList != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.attachList != 0;
#endif
default: return false;
}
}
const AttachList &get_attach_list () const
{
switch (u.version.major) {
case 1: return this+u.version1.attachList;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.attachList;
#endif
default: return Null(AttachList);
}
}
bool has_lig_carets () const
{
switch (u.version.major) {
case 1: return u.version1.ligCaretList != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.ligCaretList != 0;
#endif
default: return false;
}
}
const LigCaretList &get_lig_caret_list () const
{
switch (u.version.major) {
case 1: return this+u.version1.ligCaretList;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.ligCaretList;
#endif
default: return Null(LigCaretList);
}
}
bool has_mark_attachment_types () const
{
switch (u.version.major) {
case 1: return u.version1.markAttachClassDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.markAttachClassDef != 0;
#endif
default: return false;
}
}
const ClassDef &get_mark_attach_class_def () const
{
switch (u.version.major) {
case 1: return this+u.version1.markAttachClassDef;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.markAttachClassDef;
#endif
default: return Null(ClassDef);
}
}
bool has_mark_glyph_sets () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.markGlyphSetsDef != 0;
#endif
default: return false;
}
}
const MarkGlyphSets &get_mark_glyph_sets () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.markGlyphSetsDef;
#endif
default: return Null(MarkGlyphSets);
}
}
bool has_var_store () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.varStore != 0;
#endif
default: return false;
}
}
const VariationStore &get_var_store () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
default: return Null(VariationStore);
}
}
bool has_data () const { return u.version.to_int (); }
unsigned int get_glyph_class (hb_codepoint_t glyph) const
{ return get_glyph_class_def ().get_class (glyph); }
void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
{ get_glyph_class_def ().collect_class (glyphs, klass); }
unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
{ return get_mark_attach_class_def ().get_class (glyph); }
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{ return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{ return get_lig_caret_list ().get_lig_carets (font,
direction, glyph_id, get_var_store(),
start_offset, caret_count, caret_array); }
bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return get_mark_glyph_sets ().covers (set_index, glyph_id); }
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit the mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
unsigned int klass = get_glyph_class (glyph);
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
switch (klass) {
default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case MarkGlyph:
klass = get_mark_attachment_type (glyph);
return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
}
}
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<GDEF> (face);
if (unlikely (table->is_blocklisted (table.get_blob (), face)))
{
hb_blob_destroy (table.get_blob ());
table = hb_blob_get_empty ();
}
}
~accelerator_t () { table.destroy (); }
hb_blob_ptr_t<GDEF> table;
};
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
if (layout_variation_indices->is_empty ()) return;
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ())
{
uint16_t major = idx >> 16;
if (major >= get_var_store ().get_sub_table_count ()) break;
if (major != last_major)
{
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
if (!layout_variation_idx_delta_map->has (idx))
continue;
int delta = hb_second (layout_variation_idx_delta_map->get (idx));
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
}
protected:
union {
FixedVersion<> version; /* Version identifier */
GDEFVersion1_2<SmallTypes> version1;
#ifndef HB_NO_BEYOND_64K
GDEFVersion1_2<MediumTypes> version2;
#endif
} u;
public:
DEFINE_SIZE_MIN (4);
};
struct GDEF_accelerator_t : GDEF::accelerator_t {
GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_LAYOUT_GDEF_GDEF_HH */

View file

@ -51,9 +51,9 @@ struct AnchorFormat3
if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
if (c->plan->layout_variation_idx_delta_map->has (x_varidx)) if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
{ {
int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx)); int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
if (delta != 0) if (delta != 0)
{ {
if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
@ -63,9 +63,9 @@ struct AnchorFormat3
} }
unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
if (c->plan->layout_variation_idx_delta_map->has (y_varidx)) if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
{ {
int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx)); int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
if (delta != 0) if (delta != 0)
{ {
if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
@ -80,8 +80,8 @@ struct AnchorFormat3
if (!c->serializer->embed (xDeviceTable)) return_trace (false); if (!c->serializer->embed (xDeviceTable)) return_trace (false);
if (!c->serializer->embed (yDeviceTable)) return_trace (false); if (!c->serializer->embed (yDeviceTable)) return_trace (false);
out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
return_trace (out); return_trace (out);
} }

View file

@ -19,8 +19,8 @@ struct CursivePos
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ()); default:return_trace (c->default_return_value ());

View file

@ -143,7 +143,7 @@ struct CursivePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"cursive attaching glyph at %d to glyph at %d", "cursive attaching glyph at %u to glyph at %u",
i, j); i, j);
} }
@ -241,7 +241,7 @@ struct CursivePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"cursive attached glyph at %d to glyph at %d", "cursive attached glyph at %u to glyph at %u",
i, j); i, j);
} }

View file

@ -42,7 +42,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"attaching mark glyph at %d to glyph at %d", "attaching mark glyph at %u to glyph at %u",
c->buffer->idx, glyph_pos); c->buffer->idx, glyph_pos);
} }
@ -56,7 +56,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"attached mark glyph at %d to glyph at %d", "attached mark glyph at %u to glyph at %u",
c->buffer->idx, glyph_pos); c->buffer->idx, glyph_pos);
} }

View file

@ -22,8 +22,8 @@ struct MarkBasePos
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K

View file

@ -90,6 +90,25 @@ struct MarkBasePosFormat1_2
const Coverage &get_coverage () const { return this+markCoverage; } const Coverage &get_coverage () const { return this+markCoverage; }
static inline bool accept (hb_buffer_t *buffer, unsigned idx)
{
/* We only want to attach to the first of a MultipleSubst sequence.
* https://github.com/harfbuzz/harfbuzz/issues/740
* Reject others...
* ...but stop if we find a mark in the MultipleSubst sequence:
* https://github.com/harfbuzz/harfbuzz/issues/1020 */
return !_hb_glyph_info_multiplied (&buffer->info[idx]) ||
0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) ||
(idx == 0 ||
_hb_glyph_info_is_mark (&buffer->info[idx - 1]) ||
!_hb_glyph_info_multiplied (&buffer->info[idx - 1]) ||
_hb_glyph_info_get_lig_id (&buffer->info[idx]) !=
_hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) ||
_hb_glyph_info_get_lig_comp (&buffer->info[idx]) !=
_hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1
);
}
bool apply (hb_ot_apply_context_t *c) const bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
@ -97,48 +116,54 @@ struct MarkBasePosFormat1_2
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false); if (likely (mark_index == NOT_COVERED)) return_trace (false);
/* Now we search backwards for a non-mark glyph */ /* Now we search backwards for a non-mark glyph.
* We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
do {
unsigned unsafe_from; if (c->last_base_until > buffer->idx)
if (!skippy_iter.prev (&unsafe_from))
{ {
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); c->last_base_until = 0;
c->last_base = -1;
}
unsigned j;
for (j = buffer->idx; j > c->last_base_until; j--)
{
auto match = skippy_iter.match (buffer->info[j - 1]);
if (match == skippy_iter.MATCH)
{
// https://github.com/harfbuzz/harfbuzz/issues/4124
if (!accept (buffer, j - 1) &&
NOT_COVERED == (this+baseCoverage).get_coverage (buffer->info[j - 1].codepoint))
match = skippy_iter.SKIP;
}
if (match == skippy_iter.MATCH)
{
c->last_base = (signed) j - 1;
break;
}
}
c->last_base_until = buffer->idx;
if (c->last_base == -1)
{
buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
return_trace (false); return_trace (false);
} }
/* We only want to attach to the first of a MultipleSubst sequence. unsigned idx = (unsigned) c->last_base;
* https://github.com/harfbuzz/harfbuzz/issues/740
* Reject others...
* ...but stop if we find a mark in the MultipleSubst sequence:
* https://github.com/harfbuzz/harfbuzz/issues/1020 */
if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
(skippy_iter.idx == 0 ||
_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) ||
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
_hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
_hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
))
break;
skippy_iter.reject ();
} while (true);
/* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint);
if (base_index == NOT_COVERED) if (base_index == NOT_COVERED)
{ {
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false); return_trace (false);
} }
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
} }
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const

View file

@ -22,8 +22,8 @@ struct MarkLigPos
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K

View file

@ -100,24 +100,41 @@ struct MarkLigPosFormat1_2
if (likely (mark_index == NOT_COVERED)) return_trace (false); if (likely (mark_index == NOT_COVERED)) return_trace (false);
/* Now we search backwards for a non-mark glyph */ /* Now we search backwards for a non-mark glyph */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from)) if (c->last_base_until > buffer->idx)
{ {
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); c->last_base_until = 0;
c->last_base = -1;
}
unsigned j;
for (j = buffer->idx; j > c->last_base_until; j--)
{
auto match = skippy_iter.match (buffer->info[j - 1]);
if (match == skippy_iter.MATCH)
{
c->last_base = (signed) j - 1;
break;
}
}
c->last_base_until = buffer->idx;
if (c->last_base == -1)
{
buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
return_trace (false); return_trace (false);
} }
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ unsigned idx = (unsigned) c->last_base;
//if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int j = skippy_iter.idx; /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint);
if (lig_index == NOT_COVERED) if (lig_index == NOT_COVERED)
{ {
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false); return_trace (false);
} }
@ -128,7 +145,7 @@ struct MarkLigPosFormat1_2
unsigned int comp_count = lig_attach.rows; unsigned int comp_count = lig_attach.rows;
if (unlikely (!comp_count)) if (unlikely (!comp_count))
{ {
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false); return_trace (false);
} }
@ -137,7 +154,7 @@ struct MarkLigPosFormat1_2
* can directly use the component index. If not, we attach the mark * can directly use the component index. If not, we attach the mark
* glyph to the last component of the ligature. */ * glyph to the last component of the ligature. */
unsigned int comp_index; unsigned int comp_index;
unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (lig_id && lig_id == mark_id && mark_comp > 0) if (lig_id && lig_id == mark_id && mark_comp > 0)
@ -145,7 +162,7 @@ struct MarkLigPosFormat1_2
else else
comp_index = comp_count - 1; comp_index = comp_count - 1;
return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
} }
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const

View file

@ -22,8 +22,8 @@ struct MarkMarkPos
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K

View file

@ -25,8 +25,8 @@ struct PairPos
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));

View file

@ -43,7 +43,7 @@ struct PairPosFormat1_3
{ {
valueFormat, valueFormat,
len1, len1,
1 + len1 + len2 PairSet::get_size (len1, len2)
}; };
return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
@ -177,9 +177,7 @@ struct PairPosFormat1_3
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
{ {
unsigned len1 = valueFormat[0].get_len (); unsigned record_size = PairSet::get_size (valueFormat);
unsigned len2 = valueFormat[1].get_len ();
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
unsigned format1 = 0; unsigned format1 = 0;
unsigned format2 = 0; unsigned format2 = 0;

View file

@ -49,7 +49,7 @@ struct PairPosFormat2_4
unsigned int len1 = valueFormat1.get_len (); unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len (); unsigned int len2 = valueFormat2.get_len ();
unsigned int stride = len1 + len2; unsigned int stride = HBUINT16::static_size * (len1 + len2);
unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_range ((const void *) values, return_trace (c->check_range ((const void *) values,
@ -220,7 +220,7 @@ struct PairPosFormat2_4
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"try kerning glyphs at %d,%d", "try kerning glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx); c->buffer->idx, skippy_iter.idx);
} }
@ -231,14 +231,14 @@ struct PairPosFormat2_4
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"kerned glyphs at %d,%d", "kerned glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx); c->buffer->idx, skippy_iter.idx);
} }
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"tried kerning glyphs at %d,%d", "tried kerning glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx); c->buffer->idx, skippy_iter.idx);
} }
@ -298,8 +298,8 @@ struct PairPosFormat2_4
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{ {
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map); valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_map); valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
} }
} }

View file

@ -24,11 +24,22 @@ struct PairSet
public: public:
DEFINE_SIZE_MIN (2); DEFINE_SIZE_MIN (2);
static unsigned get_size (unsigned len1, unsigned len2)
{
return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
}
static unsigned get_size (const ValueFormat valueFormats[2])
{
unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len ();
return get_size (len1, len2);
}
struct sanitize_closure_t struct sanitize_closure_t
{ {
const ValueFormat *valueFormats; const ValueFormat *valueFormats;
unsigned int len1; /* valueFormats[0].get_len() */ unsigned int len1; /* valueFormats[0].get_len() */
unsigned int stride; /* 1 + len1 + len2 */ unsigned int stride; /* bytes */
}; };
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
@ -37,7 +48,6 @@ struct PairSet
if (!(c->check_struct (this) if (!(c->check_struct (this)
&& c->check_range (&firstPairValueRecord, && c->check_range (&firstPairValueRecord,
len, len,
HBUINT16::static_size,
closure->stride))) return_trace (false); closure->stride))) return_trace (false);
unsigned int count = len; unsigned int count = len;
@ -49,9 +59,7 @@ struct PairSet
bool intersects (const hb_set_t *glyphs, bool intersects (const hb_set_t *glyphs,
const ValueFormat *valueFormats) const const ValueFormat *valueFormats) const
{ {
unsigned int len1 = valueFormats[0].get_len (); unsigned record_size = get_size (valueFormats);
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = &firstPairValueRecord; const PairValueRecord *record = &firstPairValueRecord;
unsigned int count = len; unsigned int count = len;
@ -67,9 +75,7 @@ struct PairSet
void collect_glyphs (hb_collect_glyphs_context_t *c, void collect_glyphs (hb_collect_glyphs_context_t *c,
const ValueFormat *valueFormats) const const ValueFormat *valueFormats) const
{ {
unsigned int len1 = valueFormats[0].get_len (); unsigned record_size = get_size (valueFormats);
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = &firstPairValueRecord; const PairValueRecord *record = &firstPairValueRecord;
c->input->add_array (&record->secondGlyph, len, record_size); c->input->add_array (&record->secondGlyph, len, record_size);
@ -78,9 +84,7 @@ struct PairSet
void collect_variation_indices (hb_collect_variation_indices_context_t *c, void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats) const const ValueFormat *valueFormats) const
{ {
unsigned len1 = valueFormats[0].get_len (); unsigned record_size = get_size (valueFormats);
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = &firstPairValueRecord; const PairValueRecord *record = &firstPairValueRecord;
unsigned count = len; unsigned count = len;
@ -101,7 +105,7 @@ struct PairSet
hb_buffer_t *buffer = c->buffer; hb_buffer_t *buffer = c->buffer;
unsigned int len1 = valueFormats[0].get_len (); unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len (); unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); unsigned record_size = get_size (len1, len2);
const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
&firstPairValueRecord, &firstPairValueRecord,
@ -112,7 +116,7 @@ struct PairSet
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"try kerning glyphs at %d,%d", "try kerning glyphs at %u,%u",
c->buffer->idx, pos); c->buffer->idx, pos);
} }
@ -123,14 +127,14 @@ struct PairSet
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"kerned glyphs at %d,%d", "kerned glyphs at %u,%u",
c->buffer->idx, pos); c->buffer->idx, pos);
} }
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"tried kerning glyphs at %d,%d", "tried kerning glyphs at %u,%u",
c->buffer->idx, pos); c->buffer->idx, pos);
} }
@ -168,7 +172,7 @@ struct PairSet
unsigned len1 = valueFormats[0].get_len (); unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len (); unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); unsigned record_size = get_size (len1, len2);
typename PairValueRecord::context_t context = typename PairValueRecord::context_t context =
{ {
@ -177,7 +181,7 @@ struct PairSet
newFormats, newFormats,
len1, len1,
&glyph_map, &glyph_map,
c->plan->layout_variation_idx_delta_map &c->plan->layout_variation_idx_delta_map
}; };
const PairValueRecord *record = &firstPairValueRecord; const PairValueRecord *record = &firstPairValueRecord;

View file

@ -72,8 +72,8 @@ struct SinglePos
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));

View file

@ -28,7 +28,15 @@ struct SinglePosFormat1
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) && coverage.sanitize (c, this) &&
/* The coverage table may use a range to represent a set
* of glyphs, which means a small number of bytes can
* generate a large glyph set. Manually modify the
* sanitizer max ops to take this into account.
*
* Note: This check *must* be right after coverage sanitize. */
c->check_ops ((this + coverage).get_population () >> 1) &&
valueFormat.sanitize_value (c, this, values)); valueFormat.sanitize_value (c, this, values));
} }
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
@ -63,7 +71,7 @@ struct SinglePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"positioning glyph at %d", "positioning glyph at %u",
c->buffer->idx); c->buffer->idx);
} }
@ -72,7 +80,7 @@ struct SinglePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"positioned glyph at %d", "positioned glyph at %u",
c->buffer->idx); c->buffer->idx);
} }
@ -144,7 +152,7 @@ struct SinglePosFormat1
; ;
bool ret = bool (it); bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
return_trace (ret); return_trace (ret);
} }
}; };

View file

@ -73,7 +73,7 @@ struct SinglePosFormat2
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"positioning glyph at %d", "positioning glyph at %u",
c->buffer->idx); c->buffer->idx);
} }
@ -84,7 +84,7 @@ struct SinglePosFormat2
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"positioned glyph at %d", "positioned glyph at %u",
c->buffer->idx); c->buffer->idx);
} }
@ -163,7 +163,7 @@ struct SinglePosFormat2
; ;
bool ret = bool (it); bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
return_trace (ret); return_trace (ret);
} }
}; };

View file

@ -371,7 +371,7 @@ struct ValueFormat : HBUINT16
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
if (!sanitize_value_devices (c, base, values)) if (!sanitize_value_devices (c, base, values))
return_trace (false); return_trace (false);
values += stride; values = &StructAtOffset<const Value> (values, stride);
} }
return_trace (true); return_trace (true);

View file

@ -61,7 +61,7 @@ struct AlternateSet
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"replacing glyph at %d (alternate substitution)", "replacing glyph at %u (alternate substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -70,8 +70,8 @@ struct AlternateSet
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replaced glyph at %d (alternate substitution)", "replaced glyph at %u (alternate substitution)",
c->buffer->idx - 1); c->buffer->idx - 1u);
} }
return_trace (true); return_trace (true);

View file

@ -23,8 +23,8 @@ struct AlternateSubst
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K

View file

@ -69,7 +69,7 @@ struct Ligature
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"replacing glyph at %d (ligature substitution)", "replacing glyph at %u (ligature substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -78,8 +78,8 @@ struct Ligature
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replaced glyph at %d (ligature substitution)", "replaced glyph at %u (ligature substitution)",
c->buffer->idx - 1); c->buffer->idx - 1u);
} }
return_trace (true); return_trace (true);
@ -138,7 +138,7 @@ struct Ligature
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"ligated glyph at %d", "ligated glyph at %u",
pos); pos);
} }

View file

@ -23,8 +23,8 @@ struct LigatureSubst
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K

View file

@ -24,8 +24,8 @@ struct MultipleSubst
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K

View file

@ -20,8 +20,8 @@ struct ReverseChainSingleSubst
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ()); default:return_trace (c->default_return_value ());

View file

@ -135,7 +135,7 @@ struct ReverseChainSingleSubstFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replacing glyph at %d (reverse chaining substitution)", "replacing glyph at %u (reverse chaining substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -144,7 +144,7 @@ struct ReverseChainSingleSubstFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replaced glyph at %d (reverse chaining substitution)", "replaced glyph at %u (reverse chaining substitution)",
c->buffer->idx); c->buffer->idx);
} }

View file

@ -44,7 +44,7 @@ struct Sequence
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"replacing glyph at %d (multiple substitution)", "replacing glyph at %u (multiple substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -53,8 +53,8 @@ struct Sequence
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replaced glyph at %d (multiple subtitution)", "replaced glyph at %u (multiple subtitution)",
c->buffer->idx - 1); c->buffer->idx - 1u);
} }
return_trace (true); return_trace (true);
@ -67,7 +67,7 @@ struct Sequence
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"deleting glyph at %d (multiple substitution)", "deleting glyph at %u (multiple substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -77,7 +77,7 @@ struct Sequence
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"deleted glyph at %d (multiple substitution)", "deleted glyph at %u (multiple substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -88,7 +88,7 @@ struct Sequence
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"multiplying glyph at %d", "multiplying glyph at %u",
c->buffer->idx); c->buffer->idx);
} }

View file

@ -27,8 +27,8 @@ struct SingleSubst
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ {
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format); TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) { switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));

View file

@ -25,7 +25,15 @@ struct SingleSubstFormat1_3
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
/* The coverage table may use a range to represent a set
* of glyphs, which means a small number of bytes can
* generate a large glyph set. Manually modify the
* sanitizer max ops to take this into account.
*
* Note: This check *must* be right after coverage sanitize. */
c->check_ops ((this + coverage).get_population () >> 1));
} }
hb_codepoint_t get_mask () const hb_codepoint_t get_mask () const
@ -103,7 +111,7 @@ struct SingleSubstFormat1_3
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"replacing glyph at %d (single substitution)", "replacing glyph at %u (single substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -112,8 +120,8 @@ struct SingleSubstFormat1_3
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replaced glyph at %d (single substitution)", "replaced glyph at %u (single substitution)",
c->buffer->idx - 1); c->buffer->idx - 1u);
} }
return_trace (true); return_trace (true);

View file

@ -87,7 +87,7 @@ struct SingleSubstFormat2_4
{ {
c->buffer->sync_so_far (); c->buffer->sync_so_far ();
c->buffer->message (c->font, c->buffer->message (c->font,
"replacing glyph at %d (single substitution)", "replacing glyph at %u (single substitution)",
c->buffer->idx); c->buffer->idx);
} }
@ -96,8 +96,8 @@ struct SingleSubstFormat2_4
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{ {
c->buffer->message (c->font, c->buffer->message (c->font,
"replaced glyph at %d (single substitution)", "replaced glyph at %u (single substitution)",
c->buffer->idx - 1); c->buffer->idx - 1u);
} }
return_trace (true); return_trace (true);

View file

@ -18,11 +18,6 @@ struct glyf_accelerator_t;
namespace glyf_impl { namespace glyf_impl {
#ifndef HB_GLYF_MAX_POINTS
#define HB_GLYF_MAX_POINTS 10000
#endif
enum phantom_point_index_t enum phantom_point_index_t
{ {
PHANTOM_LEFT = 0, PHANTOM_LEFT = 0,
@ -85,28 +80,38 @@ struct Glyph
} }
void update_mtx (const hb_subset_plan_t *plan, void update_mtx (const hb_subset_plan_t *plan,
int xMin, int yMax, int xMin, int xMax,
int yMin, int yMax,
const contour_point_vector_t &all_points) const const contour_point_vector_t &all_points) const
{ {
hb_codepoint_t new_gid = 0; hb_codepoint_t new_gid = 0;
if (!plan->new_gid_for_old_gid (gid, &new_gid)) if (!plan->new_gid_for_old_gid (gid, &new_gid))
return; return;
if (type != EMPTY)
{
plan->bounds_width_map.set (new_gid, xMax - xMin);
plan->bounds_height_map.set (new_gid, yMax - yMin);
}
unsigned len = all_points.length; unsigned len = all_points.length;
float leftSideX = all_points[len - 4].x; float leftSideX = all_points[len - 4].x;
float rightSideX = all_points[len - 3].x; float rightSideX = all_points[len - 3].x;
float topSideY = all_points[len - 2].y; float topSideY = all_points[len - 2].y;
float bottomSideY = all_points[len - 1].y; float bottomSideY = all_points[len - 1].y;
int hori_aw = roundf (rightSideX - leftSideX); signed hori_aw = roundf (rightSideX - leftSideX);
if (hori_aw < 0) hori_aw = 0; if (hori_aw < 0) hori_aw = 0;
int lsb = roundf (xMin - leftSideX); int lsb = roundf (xMin - leftSideX);
plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb)); plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
//flag value should be computed using non-empty glyphs
if (type != EMPTY && lsb != xMin)
plan->head_maxp_info.allXMinIsLsb = false;
int vert_aw = roundf (topSideY - bottomSideY); signed vert_aw = roundf (topSideY - bottomSideY);
if (vert_aw < 0) vert_aw = 0; if (vert_aw < 0) vert_aw = 0;
int tsb = roundf (topSideY - yMax); int tsb = roundf (topSideY - yMax);
plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb)); plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
} }
bool compile_header_bytes (const hb_subset_plan_t *plan, bool compile_header_bytes (const hb_subset_plan_t *plan,
@ -114,7 +119,7 @@ struct Glyph
hb_bytes_t &dest_bytes /* OUT */) const hb_bytes_t &dest_bytes /* OUT */) const
{ {
GlyphHeader *glyph_header = nullptr; GlyphHeader *glyph_header = nullptr;
if (type != EMPTY && all_points.length > 4) if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
{ {
glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
if (unlikely (!glyph_header)) return false; if (unlikely (!glyph_header)) return false;
@ -138,18 +143,33 @@ struct Glyph
yMax = hb_max (yMax, y); yMax = hb_max (yMax, y);
} }
update_mtx (plan, roundf (xMin), roundf (yMax), all_points); update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points);
/*for empty glyphs: all_points only include phantom points. int rounded_xMin = roundf (xMin);
int rounded_xMax = roundf (xMax);
int rounded_yMin = roundf (yMin);
int rounded_yMax = roundf (yMax);
if (type != EMPTY)
{
plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
}
/* when pinned at default, no need to compile glyph header
* and for empty glyphs: all_points only include phantom points.
* just update metrics and then return */ * just update metrics and then return */
if (!glyph_header) if (!glyph_header)
return true; return true;
glyph_header->numberOfContours = header->numberOfContours; glyph_header->numberOfContours = header->numberOfContours;
glyph_header->xMin = roundf (xMin);
glyph_header->yMin = roundf (yMin); glyph_header->xMin = rounded_xMin;
glyph_header->xMax = roundf (xMax); glyph_header->yMin = rounded_yMin;
glyph_header->yMax = roundf (yMax); glyph_header->xMax = rounded_xMax;
glyph_header->yMax = rounded_yMax;
dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
return true; return true;
@ -162,15 +182,34 @@ struct Glyph
hb_bytes_t &dest_end /* OUT */) hb_bytes_t &dest_end /* OUT */)
{ {
contour_point_vector_t all_points, deltas; contour_point_vector_t all_points, deltas;
if (!get_points (font, glyf, all_points, &deltas, false, false)) unsigned composite_contours = 0;
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
unsigned *composite_contours_p = &composite_contours;
// don't compute head/maxp values when glyph has no contours(type is EMPTY)
// also ignore .notdef glyph when --notdef-outline is not enabled
if (type == EMPTY ||
(gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
{
head_maxp_info_p = nullptr;
composite_contours_p = nullptr;
}
if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
return false; return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for // .notdef, set type to empty so we only update metrics and don't compile bytes for
// it // it
if (gid == 0 && if (gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
{
type = EMPTY; type = EMPTY;
dest_start = hb_bytes_t ();
dest_end = hb_bytes_t ();
}
//dont compile bytes when pinned at default, just recalculate bounds
if (!plan->pinned_at_default) {
switch (type) { switch (type) {
case COMPOSITE: case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
@ -191,6 +230,7 @@ struct Glyph
dest_end = hb_bytes_t (); dest_end = hb_bytes_t ();
break; break;
} }
}
if (!compile_header_bytes (plan, all_points, dest_start)) if (!compile_header_bytes (plan, all_points, dest_start))
{ {
@ -208,13 +248,25 @@ struct Glyph
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */, contour_point_vector_t &all_points /* OUT */,
contour_point_vector_t *deltas = nullptr, /* OUT */ contour_point_vector_t *deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
bool shift_points_hori = true, bool shift_points_hori = true,
bool use_my_metrics = true, bool use_my_metrics = true,
bool phantom_only = false, bool phantom_only = false,
hb_array_t<int> coords = hb_array_t<int> (), hb_array_t<int> coords = hb_array_t<int> (),
unsigned int depth = 0) const unsigned int depth = 0,
unsigned *edge_count = nullptr) const
{ {
if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
unsigned stack_edge_count = 0;
if (!edge_count) edge_count = &stack_edge_count;
if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
(*edge_count)++;
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
}
if (!coords) if (!coords)
coords = hb_array (font->coords, font->num_coords); coords = hb_array (font->coords, font->num_coords);
@ -226,6 +278,10 @@ struct Glyph
switch (type) { switch (type) {
case SIMPLE: case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
if (depth > 0 && composite_contours)
*composite_contours += (unsigned) header->numberOfContours;
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
return false; return false;
break; break;
@ -301,6 +357,8 @@ struct Glyph
switch (type) { switch (type) {
case SIMPLE: case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
if (!inplace) if (!inplace)
all_points.extend (points.as_array ()); all_points.extend (points.as_array ());
break; break;
@ -311,17 +369,19 @@ struct Glyph
for (auto &item : get_composite_iterator ()) for (auto &item : get_composite_iterator ())
{ {
comp_points.reset (); comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font, .get_points (font,
glyf_accelerator, glyf_accelerator,
comp_points, comp_points,
deltas, deltas,
head_maxp_info,
composite_contours,
shift_points_hori, shift_points_hori,
use_my_metrics, use_my_metrics,
phantom_only, phantom_only,
coords, coords,
depth + 1))) depth + 1,
edge_count)))
return false; return false;
/* Copy phantom points from component if USE_MY_METRICS flag set */ /* Copy phantom points from component if USE_MY_METRICS flag set */
@ -357,6 +417,13 @@ struct Glyph
comp_index++; comp_index++;
} }
if (head_maxp_info && depth == 0)
{
if (composite_contours)
head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
}
all_points.extend (phantoms); all_points.extend (phantoms);
} break; } break;
#ifndef HB_NO_VAR_COMPOSITES #ifndef HB_NO_VAR_COMPOSITES
@ -370,7 +437,11 @@ struct Glyph
comp_points.reset (); comp_points.reset ();
coord_setter_t coord_setter (coords); auto component_coords = coords;
if (item.is_reset_unspecified_axes ())
component_coords = hb_array<int> ();
coord_setter_t coord_setter (component_coords);
item.set_variations (coord_setter, record_points); item.set_variations (coord_setter, record_points);
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
@ -378,11 +449,14 @@ struct Glyph
glyf_accelerator, glyf_accelerator,
comp_points, comp_points,
deltas, deltas,
head_maxp_info,
nullptr,
shift_points_hori, shift_points_hori,
use_my_metrics, use_my_metrics,
phantom_only, phantom_only,
coord_setter.get_coords (), coord_setter.get_coords (),
depth + 1))) depth + 1,
edge_count)))
return false; return false;
/* Apply component transformation */ /* Apply component transformation */

View file

@ -21,10 +21,12 @@ struct GlyphHeader
/* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
int lsb = hb_min (xMin, xMax); int lsb = hb_min (xMin, xMax);
(void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
extents->x_bearing = font->em_scale_x (lsb); extents->x_bearing = lsb;
extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); extents->y_bearing = hb_max (yMin, yMax);
extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); extents->width = hb_max (xMin, xMax) - hb_min (xMin, xMax);
extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); extents->height = hb_min (yMin, yMax) - hb_max (yMin, yMax);
font->scale_glyph_extents (extents);
return true; return true;
} }

View file

@ -20,7 +20,7 @@ struct SimpleGlyph
FLAG_X_SAME = 0x10, FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20, FLAG_Y_SAME = 0x20,
FLAG_OVERLAP_SIMPLE = 0x40, FLAG_OVERLAP_SIMPLE = 0x40,
FLAG_RESERVED2 = 0x80 FLAG_CUBIC = 0x80
}; };
const GlyphHeader &header; const GlyphHeader &header;
@ -184,7 +184,7 @@ struct SimpleGlyph
if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
if (!points_.resize (num_points)) return false; if (!points_.resize (num_points)) return false;
if (phantom_only) return true; if (phantom_only) return true;
@ -272,9 +272,9 @@ struct SimpleGlyph
unsigned num_points = all_points.length - 4; unsigned num_points = all_points.length - 4;
hb_vector_t<uint8_t> flags, x_coords, y_coords; hb_vector_t<uint8_t> flags, x_coords, y_coords;
if (unlikely (!flags.alloc (num_points))) return false; if (unlikely (!flags.alloc (num_points, true))) return false;
if (unlikely (!x_coords.alloc (2*num_points))) return false; if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
if (unlikely (!y_coords.alloc (2*num_points))) return false; if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
uint8_t lastflag = 255, repeat = 0; uint8_t lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0; int prev_x = 0, prev_y = 0;

View file

@ -21,22 +21,14 @@ struct SubsetGlyph
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
bool use_short_loca, bool use_short_loca,
const hb_subset_plan_t *plan, const hb_subset_plan_t *plan)
hb_font_t *font)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
if (font)
{
const OT::glyf_accelerator_t &glyf = *font->face->table.glyf;
if (!this->compile_bytes_with_deltas (plan, font, glyf))
return_trace (false);
}
hb_bytes_t dest_glyph = dest_start.copy (c); hb_bytes_t dest_glyph = dest_start.copy (c);
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
unsigned int pad_length = use_short_loca ? padding () : 0; unsigned int pad_length = use_short_loca ? padding () : 0;
DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
HBUINT8 pad; HBUINT8 pad;
pad = 0; pad = 0;

View file

@ -29,6 +29,7 @@ struct VarCompositeGlyphRecord
HAVE_TCENTER_Y = 0x0800, HAVE_TCENTER_Y = 0x0800,
GID_IS_24 = 0x1000, GID_IS_24 = 0x1000,
AXES_HAVE_VARIATION = 0x2000, AXES_HAVE_VARIATION = 0x2000,
RESET_UNSPECIFIED_AXES = 0x4000,
}; };
public: public:
@ -60,6 +61,7 @@ struct VarCompositeGlyphRecord
bool has_more () const { return true; } bool has_more () const { return true; }
bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; }
hb_codepoint_t get_gid () const hb_codepoint_t get_gid () const
{ {
@ -165,8 +167,8 @@ struct VarCompositeGlyphRecord
float translateX = 0.f; float translateX = 0.f;
float translateY = 0.f; float translateY = 0.f;
float rotation = 0.f; float rotation = 0.f;
float scaleX = 1.f * (1 << 12); float scaleX = 1.f * (1 << 10);
float scaleY = 1.f * (1 << 12); float scaleY = 1.f * (1 << 10);
float skewX = 0.f; float skewX = 0.f;
float skewY = 0.f; float skewY = 0.f;
float tCenterX = 0.f; float tCenterX = 0.f;
@ -187,7 +189,7 @@ struct VarCompositeGlyphRecord
if (flags & AXES_HAVE_VARIATION) if (flags & AXES_HAVE_VARIATION)
{ {
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
rec_points[i].x = *q++; rec_points[i].x = q++->to_int ();
rec_points += count; rec_points += count;
} }
else else
@ -197,11 +199,11 @@ struct VarCompositeGlyphRecord
if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++; if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++;
if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++; if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++;
if (flags & HAVE_ROTATION) rotation = * (const F2DOT14 *) p++; if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_SCALE_X) scaleX = * (const F4DOT12 *) p++; if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int ();
if (flags & HAVE_SCALE_Y) scaleY = * (const F4DOT12 *) p++; if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int ();
if (flags & HAVE_SKEW_X) skewX = * (const F2DOT14 *) p++; if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_SKEW_Y) skewY = * (const F2DOT14 *) p++; if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++; if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++;
if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++; if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++;
@ -270,19 +272,19 @@ struct VarCompositeGlyphRecord
} }
if (flags & HAVE_ROTATION) if (flags & HAVE_ROTATION)
{ {
rotation = rec_points[0].x / (1 << 14); rotation = rec_points[0].x / (1 << 12);
rec_points++; rec_points++;
} }
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
{ {
scaleX = rec_points[0].x / (1 << 12); scaleX = rec_points[0].x / (1 << 10);
scaleY = rec_points[0].y / (1 << 12); scaleY = rec_points[0].y / (1 << 10);
rec_points++; rec_points++;
} }
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
{ {
skewX = rec_points[0].x / (1 << 14); skewX = rec_points[0].x / (1 << 12);
skewY = rec_points[0].y / (1 << 14); skewY = rec_points[0].y / (1 << 12);
rec_points++; rec_points++;
} }
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
@ -316,9 +318,8 @@ struct VarCompositeGlyphRecord
{ {
unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++; unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
signed v = have_variations ? rec_points[i].x : *a++; signed v = have_variations ? rec_points[i].x : a++->to_int ();
v += setter[axis_index];
v = hb_clamp (v, -(1<<14), (1<<14)); v = hb_clamp (v, -(1<<14), (1<<14));
setter[axis_index] = v; setter[axis_index] = v;
} }

View file

@ -25,7 +25,7 @@ _write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
| hb_map ([=, &offset] (unsigned int padded_size) | hb_map ([=, &offset] (unsigned int padded_size)
{ {
offset += padded_size; offset += padded_size;
DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset);
return offset >> right_shift; return offset >> right_shift;
}) })
| hb_sink (dest) | hb_sink (dest)
@ -44,6 +44,20 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
head_prime->indexToLocFormat = use_short_loca ? 0 : 1; head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
if (plan->normalized_coords)
{
head_prime->xMin = plan->head_maxp_info.xMin;
head_prime->xMax = plan->head_maxp_info.xMax;
head_prime->yMin = plan->head_maxp_info.yMin;
head_prime->yMax = plan->head_maxp_info.yMax;
unsigned orig_flag = head_prime->flags;
if (plan->head_maxp_info.allXMinIsLsb)
orig_flag |= 1 << 1;
else
orig_flag &= ~(1 << 1);
head_prime->flags = orig_flag;
}
bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
hb_blob_destroy (head_prime_blob); hb_blob_destroy (head_prime_blob);
@ -61,7 +75,7 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
if (unlikely (!loca_prime_data)) return false; if (unlikely (!loca_prime_data)) return false;
DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u",
entry_size, num_offsets, entry_size * num_offsets); entry_size, num_offsets, entry_size * num_offsets);
if (use_short_loca) if (use_short_loca)

View file

@ -7,6 +7,7 @@
#include "../../hb-ot-hmtx-table.hh" #include "../../hb-ot-hmtx-table.hh"
#include "../../hb-ot-var-gvar-table.hh" #include "../../hb-ot-var-gvar-table.hh"
#include "../../hb-draw.hh" #include "../../hb-draw.hh"
#include "../../hb-paint.hh"
#include "glyf-helpers.hh" #include "glyf-helpers.hh"
#include "Glyph.hh" #include "Glyph.hh"
@ -42,14 +43,13 @@ struct glyf
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
Iterator it, Iterator it,
bool use_short_loca, bool use_short_loca,
const hb_subset_plan_t *plan, const hb_subset_plan_t *plan)
hb_font_t *font)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
unsigned init_len = c->length (); unsigned init_len = c->length ();
for (auto &_ : it) for (auto &_ : it)
if (unlikely (!_.serialize (c, use_short_loca, plan, font))) if (unlikely (!_.serialize (c, use_short_loca, plan)))
return false; return false;
/* As a special case when all glyph in the font are empty, add a zero byte /* As a special case when all glyph in the font are empty, add a zero byte
@ -75,59 +75,66 @@ struct glyf
glyf *glyf_prime = c->serializer->start_embed <glyf> (); glyf *glyf_prime = c->serializer->start_embed <glyf> ();
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
_populate_subset_glyphs (c->plan, glyphs);
hb_font_t *font = nullptr; hb_font_t *font = nullptr;
if (!c->plan->pinned_at_default) if (c->plan->normalized_coords)
{ {
font = _create_font_for_instancing (c->plan); font = _create_font_for_instancing (c->plan);
if (unlikely (!font)) return false; if (unlikely (!font)) return false;
} }
auto padded_offsets = hb_vector_t<unsigned> padded_offsets;
+ hb_iter (glyphs) unsigned num_glyphs = c->plan->num_output_glyphs ();
| hb_map (&glyf_impl::SubsetGlyph::padded_size) if (unlikely (!padded_offsets.resize (num_glyphs)))
; return false;
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
if (!_populate_subset_glyphs (c->plan, font, glyphs))
return false;
if (font)
hb_font_destroy (font);
unsigned max_offset = 0;
for (unsigned i = 0; i < num_glyphs; i++)
{
padded_offsets[i] = glyphs[i].padded_size ();
max_offset += padded_offsets[i];
}
bool use_short_loca = false; bool use_short_loca = false;
if (likely (!c->plan->force_long_loca)) if (likely (!c->plan->force_long_loca))
{
unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
use_short_loca = max_offset < 0x1FFFF; use_short_loca = max_offset < 0x1FFFF;
}
glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan, font);
if (!use_short_loca) { if (!use_short_loca) {
padded_offsets = for (unsigned i = 0; i < num_glyphs; i++)
+ hb_iter (glyphs) padded_offsets[i] = glyphs[i].length ();
| hb_map (&glyf_impl::SubsetGlyph::length)
;
} }
if (font) bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
{ if (c->plan->normalized_coords && !c->plan->pinned_at_default)
_free_compiled_subset_glyphs (&glyphs); _free_compiled_subset_glyphs (glyphs, glyphs.length - 1);
hb_font_destroy (font);
} if (!result) return false;
if (unlikely (c->serializer->in_error ())) return_trace (false); if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
padded_offsets, padded_offsets.iter (),
use_short_loca))); use_short_loca)));
} }
void bool
_populate_subset_glyphs (const hb_subset_plan_t *plan, _populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const; hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
hb_font_t * hb_font_t *
_create_font_for_instancing (const hb_subset_plan_t *plan) const; _create_font_for_instancing (const hb_subset_plan_t *plan) const;
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs, unsigned index) const
{ {
for (auto _ : *glyphs) for (unsigned i = 0; i <= index && i < glyphs.length; i++)
_.free_compiled_bytes (); glyphs[i].free_compiled_bytes ();
} }
protected: protected:
@ -193,7 +200,7 @@ struct glyf_accelerator_t
contour_point_vector_t all_points; contour_point_vector_t all_points;
bool phantom_only = !consumer.is_consuming_contour_points (); bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only))) if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
return false; return false;
if (consumer.is_consuming_contour_points ()) if (consumer.is_consuming_contour_points ())
@ -247,19 +254,14 @@ struct glyf_accelerator_t
extents->y_bearing = 0; extents->y_bearing = 0;
return; return;
} }
if (scaled)
{
extents->x_bearing = font->em_scalef_x (min_x);
extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
extents->y_bearing = font->em_scalef_y (max_y);
extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
}
else
{ {
extents->x_bearing = roundf (min_x); extents->x_bearing = roundf (min_x);
extents->width = roundf (max_x - extents->x_bearing); extents->width = roundf (max_x - extents->x_bearing);
extents->y_bearing = roundf (max_y); extents->y_bearing = roundf (max_y);
extents->height = roundf (min_y - extents->y_bearing); extents->height = roundf (min_y - extents->y_bearing);
if (scaled)
font->scale_glyph_extents (extents);
} }
} }
@ -337,6 +339,15 @@ struct glyf_accelerator_t
return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
} }
bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
{
funcs->push_clip_glyph (data, gid, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
return true;
}
const glyf_impl::Glyph const glyf_impl::Glyph
glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
{ {
@ -385,14 +396,16 @@ struct glyf_accelerator_t
}; };
inline void inline bool
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{ {
OT::glyf_accelerator_t glyf (plan->source); OT::glyf_accelerator_t glyf (plan->source);
unsigned num_glyphs = plan->num_output_glyphs (); unsigned num_glyphs = plan->num_output_glyphs ();
if (!glyphs.resize (num_glyphs)) return; if (!glyphs.resize (num_glyphs)) return false;
unsigned idx = 0;
for (auto p : plan->glyph_map->iter ()) for (auto p : plan->glyph_map->iter ())
{ {
unsigned new_gid = p.second; unsigned new_gid = p.second;
@ -401,7 +414,7 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
if (unlikely (new_gid == 0 && if (unlikely (new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
plan->pinned_at_default) !plan->normalized_coords)
subset_glyph.source_glyph = glyf_impl::Glyph (); subset_glyph.source_glyph = glyf_impl::Glyph ();
else else
{ {
@ -414,7 +427,20 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
subset_glyph.drop_hints_bytes (); subset_glyph.drop_hints_bytes ();
else else
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
if (font)
{
if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
{
// when pinned at default, only bounds are updated, thus no need to free
if (!plan->pinned_at_default && idx > 0)
_free_compiled_subset_glyphs (glyphs, idx - 1);
return false;
} }
idx++;
}
}
return true;
} }
inline hb_font_t * inline hb_font_t *
@ -424,10 +450,10 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
if (unlikely (font == hb_font_get_empty ())) return nullptr; if (unlikely (font == hb_font_get_empty ())) return nullptr;
hb_vector_t<hb_variation_t> vars; hb_vector_t<hb_variation_t> vars;
if (unlikely (!vars.alloc (plan->user_axes_location->get_population ()))) if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
return nullptr; return nullptr;
for (auto _ : *plan->user_axes_location) for (auto _ : plan->user_axes_location)
{ {
hb_variation_t var; hb_variation_t var;
var.tag = _.first; var.tag = _.first;
@ -436,7 +462,7 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
} }
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
#endif #endif
return font; return font;
} }

View file

@ -26,22 +26,29 @@ struct path_builder_t
optional_point_t lerp (optional_point_t p, float t) optional_point_t lerp (optional_point_t p, float t)
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
} first_oncurve, first_offcurve, last_offcurve; } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{ {
font = font_; font = font_;
draw_session = &draw_session_; draw_session = &draw_session_;
first_oncurve = first_offcurve = last_offcurve = optional_point_t (); first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t ();
} }
/* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
See also: See also:
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
* https://stackoverflow.com/a/20772557 */ * https://stackoverflow.com/a/20772557
*
* Cubic support added. */
void consume_point (const contour_point_t &point) void consume_point (const contour_point_t &point)
{ {
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
#ifdef HB_NO_CUBIC_GLYF
bool is_cubic = false;
#else
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif
optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
if (!first_oncurve) if (!first_oncurve)
{ {
@ -52,7 +59,12 @@ struct path_builder_t
} }
else else
{ {
if (first_offcurve) if (is_cubic && !first_offcurve2)
{
first_offcurve2 = first_offcurve;
first_offcurve = p;
}
else if (first_offcurve)
{ {
optional_point_t mid = first_offcurve.lerp (p, .5f); optional_point_t mid = first_offcurve.lerp (p, .5f);
first_oncurve = mid; first_oncurve = mid;
@ -69,18 +81,43 @@ struct path_builder_t
{ {
if (is_on_curve) if (is_on_curve)
{ {
if (last_offcurve2)
{
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
p.x, p.y);
last_offcurve2 = optional_point_t ();
}
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
p.x, p.y); p.x, p.y);
last_offcurve = optional_point_t (); last_offcurve = optional_point_t ();
} }
else else
{
if (is_cubic && !last_offcurve2)
{
last_offcurve2 = last_offcurve;
last_offcurve = p;
}
else
{ {
optional_point_t mid = last_offcurve.lerp (p, .5f); optional_point_t mid = last_offcurve.lerp (p, .5f);
if (is_cubic)
{
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve2 = optional_point_t ();
}
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y); mid.x, mid.y);
last_offcurve = p; last_offcurve = p;
} }
} }
}
else else
{ {
if (is_on_curve) if (is_on_curve)
@ -94,19 +131,40 @@ struct path_builder_t
{ {
if (first_offcurve && last_offcurve) if (first_offcurve && last_offcurve)
{ {
optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); optional_point_t mid = last_offcurve.lerp (first_offcurve2 ?
first_offcurve2 :
first_offcurve, .5f);
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y); mid.x, mid.y);
last_offcurve = optional_point_t (); last_offcurve = optional_point_t ();
/* now check the rest */
} }
/* now check the rest */
if (first_offcurve && first_oncurve) if (first_offcurve && first_oncurve)
{
if (first_offcurve2)
draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y); first_oncurve.x, first_oncurve.y);
}
else if (last_offcurve && first_oncurve) else if (last_offcurve && first_oncurve)
{
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y); first_oncurve.x, first_oncurve.y);
}
else if (first_oncurve) else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y); draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve) else if (first_offcurve)
@ -117,7 +175,7 @@ struct path_builder_t
} }
/* Getting ready for the next contour */ /* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = optional_point_t (); first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
draw_session->close_path (); draw_session->close_path ();
} }
} }

589
thirdparty/harfbuzz/src/OT/name/name.hh vendored Normal file
View file

@ -0,0 +1,589 @@
/*
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef OT_NAME_NAME_HH
#define OT_NAME_NAME_HH
#include "../../hb-open-type.hh"
#include "../../hb-ot-name-language.hh"
#include "../../hb-aat-layout.hh"
#include "../../hb-utf.hh"
namespace OT {
template <typename in_utf_t, typename out_utf_t>
inline unsigned int
hb_ot_name_convert_utf (hb_bytes_t bytes,
unsigned int *text_size /* IN/OUT */,
typename out_utf_t::codepoint_t *text /* OUT */)
{
unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
const typename in_utf_t::codepoint_t *src_end = src + src_len;
typename out_utf_t::codepoint_t *dst = text;
hb_codepoint_t unicode;
const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
if (text_size && *text_size)
{
(*text_size)--; /* Save room for NUL-termination. */
const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
while (src < src_end && dst < dst_end)
{
const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
if (dst_next == dst)
break; /* Out-of-room. */
dst = dst_next;
src = src_next;
}
*text_size = dst - text;
*dst = 0; /* NUL-terminate. */
}
/* Accumulate length of rest. */
unsigned int dst_len = dst - text;
while (src < src_end)
{
src = in_utf_t::next (src, src_end, &unicode, replacement);
dst_len += out_utf_t::encode_len (unicode);
}
return dst_len;
}
#define entry_score var.u16[0]
#define entry_index var.u16[1]
/*
* name -- Naming
* https://docs.microsoft.com/en-us/typography/opentype/spec/name
*/
#define HB_OT_TAG_name HB_TAG('n','a','m','e')
#define UNSUPPORTED 42
struct NameRecord
{
hb_language_t language (hb_face_t *face) const
{
#ifndef HB_NO_OT_NAME_LANGUAGE
unsigned int p = platformID;
unsigned int l = languageID;
if (p == 3)
return _hb_ot_name_language_for_ms_code (l);
if (p == 1)
return _hb_ot_name_language_for_mac_code (l);
#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
if (p == 0)
return face->table.ltag->get_language (l);
#endif
#endif
return HB_LANGUAGE_INVALID;
}
uint16_t score () const
{
/* Same order as in cmap::find_best_subtable(). */
unsigned int p = platformID;
unsigned int e = encodingID;
/* 32-bit. */
if (p == 3 && e == 10) return 0;
if (p == 0 && e == 6) return 1;
if (p == 0 && e == 4) return 2;
/* 16-bit. */
if (p == 3 && e == 1) return 3;
if (p == 0 && e == 3) return 4;
if (p == 0 && e == 2) return 5;
if (p == 0 && e == 1) return 6;
if (p == 0 && e == 0) return 7;
/* Symbol. */
if (p == 3 && e == 0) return 8;
/* We treat all Mac Latin names as ASCII only. */
if (p == 1 && e == 0) return 10; /* 10 is magic number :| */
return UNSUPPORTED;
}
NameRecord* copy (hb_serialize_context_t *c, const void *base
#ifdef HB_EXPERIMENTAL_API
, const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
#endif
) const
{
TRACE_SERIALIZE (this);
HB_UNUSED auto snap = c->snapshot ();
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
#ifdef HB_EXPERIMENTAL_API
hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID);
hb_bytes_t* name_bytes;
if (name_table_overrides->has (record_ids, &name_bytes)) {
hb_bytes_t encoded_bytes = *name_bytes;
char *name_str_utf16_be = nullptr;
if (platformID != 1)
{
unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
if (!name_str_utf16_be)
{
c->revert (snap);
return_trace (nullptr);
}
hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
(hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
c->revert (snap);
hb_free (name_str_utf16_be);
return_trace (nullptr);
}
encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
}
else
{
// mac platform, copy the UTF-8 string(all ascii characters) as is
if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
c->revert (snap);
return_trace (nullptr);
}
}
out->offset = 0;
c->push ();
encoded_bytes.copy (c);
c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0);
hb_free (name_str_utf16_be);
}
else
#endif
{
out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
}
return_trace (out);
}
bool isUnicode () const
{
unsigned int p = platformID;
unsigned int e = encodingID;
return (p == 0 ||
(p == 3 && (e == 0 || e == 1 || e == 10)));
}
static int cmp (const void *pa, const void *pb)
{
const NameRecord *a = (const NameRecord *)pa;
const NameRecord *b = (const NameRecord *)pb;
if (a->platformID != b->platformID)
return a->platformID - b->platformID;
if (a->encodingID != b->encodingID)
return a->encodingID - b->encodingID;
if (a->languageID != b->languageID)
return a->languageID - b->languageID;
if (a->nameID != b->nameID)
return a->nameID - b->nameID;
if (a->length != b->length)
return a->length - b->length;
return 0;
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
}
HBUINT16 platformID; /* Platform ID. */
HBUINT16 encodingID; /* Platform-specific encoding ID. */
HBUINT16 languageID; /* Language ID. */
HBUINT16 nameID; /* Name ID. */
HBUINT16 length; /* String length (in bytes). */
NNOffset16To<UnsizedArrayOf<HBUINT8>>
offset; /* String offset from start of storage area (in bytes). */
public:
DEFINE_SIZE_STATIC (12);
};
static int
_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact)
{
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
/* Compare by name_id, then language. */
if (a->name_id != b->name_id)
return a->name_id - b->name_id;
if (a->language == b->language) return 0;
if (!a->language) return -1;
if (!b->language) return +1;
const char *astr = hb_language_to_string (a->language);
const char *bstr = hb_language_to_string (b->language);
signed c = strcmp (astr, bstr);
// 'a' is the user request, and 'b' is string in the font.
// If eg. user asks for "en-us" and font has "en", approve.
if (!exact && c &&
hb_language_matches (b->language, a->language))
return 0;
return c;
}
static int
_hb_ot_name_entry_cmp (const void *pa, const void *pb)
{
/* Compare by name_id, then language, then score, then index. */
int v = _hb_ot_name_entry_cmp_key (pa, pb, true);
if (v)
return v;
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
if (a->entry_score != b->entry_score)
return a->entry_score - b->entry_score;
if (a->entry_index != b->entry_index)
return a->entry_index - b->entry_index;
return 0;
}
struct name
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
unsigned int get_size () const
{ return min_size + count * nameRecordZ.item_size; }
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
bool serialize (hb_serialize_context_t *c,
Iterator it,
const void *src_string_pool
#ifdef HB_EXPERIMENTAL_API
, const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records
, const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
#endif
)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
unsigned total_count = it.len ()
#ifdef HB_EXPERIMENTAL_API
+ insert_name_records.length
#endif
;
this->format = 0;
if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return false;
NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size);
if (unlikely (!name_records)) return_trace (false);
hb_array_t<NameRecord> records (name_records, total_count);
for (const NameRecord& record : it)
{
hb_memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
#ifdef HB_EXPERIMENTAL_API
for (unsigned i = 0; i < insert_name_records.length; i++)
{
const hb_ot_name_record_ids_t& ids = insert_name_records[i];
NameRecord record;
record.platformID = ids.platform_id;
record.encodingID = ids.encoding_id;
record.languageID = ids.language_id;
record.nameID = ids.name_id;
record.length = 0; // handled in NameRecord copy()
record.offset = 0;
memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
#endif
records.qsort ();
c->copy_all (records,
src_string_pool
#ifdef HB_EXPERIMENTAL_API
, name_table_overrides
#endif
);
hb_free (records.arrayZ);
if (unlikely (c->ran_out_of_room ())) return_trace (false);
this->stringOffset = c->length ();
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
name *name_prime = c->serializer->start_embed<name> ();
if (unlikely (!name_prime)) return_trace (false);
#ifdef HB_EXPERIMENTAL_API
const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
&c->plan->name_table_overrides;
#endif
auto it =
+ nameRecordZ.as_array (count)
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
| hb_filter (c->plan->name_languages, &NameRecord::languageID)
| hb_filter ([&] (const NameRecord& namerecord) {
return
(c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
|| namerecord.isUnicode ();
})
#ifdef HB_EXPERIMENTAL_API
| hb_filter ([&] (const NameRecord& namerecord) {
if (name_table_overrides->is_empty ())
return true;
hb_ot_name_record_ids_t rec_ids (namerecord.platformID,
namerecord.encodingID,
namerecord.languageID,
namerecord.nameID);
hb_bytes_t *p;
if (name_table_overrides->has (rec_ids, &p) &&
(*p).length == 0)
return false;
return true;
})
#endif
;
#ifdef HB_EXPERIMENTAL_API
hb_hashmap_t<hb_ot_name_record_ids_t, unsigned> retained_name_record_ids;
for (const NameRecord& rec : it)
{
hb_ot_name_record_ids_t rec_ids (rec.platformID,
rec.encodingID,
rec.languageID,
rec.nameID);
retained_name_record_ids.set (rec_ids, 1);
}
hb_vector_t<hb_ot_name_record_ids_t> insert_name_records;
if (!name_table_overrides->is_empty ())
{
if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
return_trace (false);
for (const auto& record_ids : name_table_overrides->keys ())
{
if (name_table_overrides->get (record_ids).length == 0)
continue;
if (retained_name_record_ids.has (record_ids))
continue;
insert_name_records.push (record_ids);
}
}
#endif
return (name_prime->serialize (c->serializer, it,
std::addressof (this + stringOffset)
#ifdef HB_EXPERIMENTAL_API
, insert_name_records
, name_table_overrides
#endif
));
}
bool sanitize_records (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
const void *string_pool = (this+stringOffset).arrayZ;
return_trace (nameRecordZ.sanitize (c, count, string_pool));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (format == 0 || format == 1) &&
c->check_array (nameRecordZ.arrayZ, count) &&
c->check_range (this, stringOffset) &&
sanitize_records (c));
}
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<name> (face);
assert (this->table.get_length () >= this->table->stringOffset);
this->pool = (const char *) (const void *) (this->table+this->table->stringOffset);
this->pool_len = this->table.get_length () - this->table->stringOffset;
const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
this->table->count);
this->names.alloc (all_names.length, true);
for (unsigned int i = 0; i < all_names.length; i++)
{
hb_ot_name_entry_t *entry = this->names.push ();
entry->name_id = all_names[i].nameID;
entry->language = all_names[i].language (face);
entry->entry_score = all_names[i].score ();
entry->entry_index = i;
}
this->names.qsort (_hb_ot_name_entry_cmp);
/* Walk and pick best only for each name_id,language pair,
* while dropping unsupported encodings. */
unsigned int j = 0;
for (unsigned int i = 0; i < this->names.length; i++)
{
if (this->names[i].entry_score == UNSUPPORTED ||
this->names[i].language == HB_LANGUAGE_INVALID)
continue;
if (i &&
this->names[i - 1].name_id == this->names[i].name_id &&
this->names[i - 1].language == this->names[i].language)
continue;
this->names[j++] = this->names[i];
}
this->names.resize (j);
}
~accelerator_t ()
{
this->table.destroy ();
}
int get_index (hb_ot_name_id_t name_id,
hb_language_t language,
unsigned int *width=nullptr) const
{
const hb_ot_name_entry_t key = {name_id, {0}, language};
const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
this->names.length,
sizeof (hb_ot_name_entry_t),
_hb_ot_name_entry_cmp_key,
true);
if (!entry)
{
entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
this->names.length,
sizeof (hb_ot_name_entry_t),
_hb_ot_name_entry_cmp_key,
false);
}
if (!entry)
return -1;
if (width)
*width = entry->entry_score < 10 ? 2 : 1;
return entry->entry_index;
}
hb_bytes_t get_name (unsigned int idx) const
{
const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count);
const NameRecord &record = all_names[idx];
const hb_bytes_t string_pool (pool, pool_len);
return string_pool.sub_array (record.offset, record.length);
}
private:
const char *pool;
unsigned int pool_len;
public:
hb_blob_ptr_t<name> table;
hb_vector_t<hb_ot_name_entry_t> names;
};
public:
/* We only implement format 0 for now. */
HBUINT16 format; /* Format selector (=0/1). */
HBUINT16 count; /* Number of name records. */
NNOffset16To<UnsizedArrayOf<HBUINT8>>
stringOffset; /* Offset to start of string storage (from start of table). */
UnsizedArrayOf<NameRecord>
nameRecordZ; /* The name records where count is the number of records. */
public:
DEFINE_SIZE_ARRAY (6, nameRecordZ);
};
#undef entry_index
#undef entry_score
struct name_accelerator_t : name::accelerator_t {
name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_NAME_NAME_HH */

View file

@ -123,7 +123,7 @@ struct graph_t
while (a || b) while (a || b)
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, DEBUG_MSG (SUBSET_REPACK, nullptr,
" 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b); " 0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b);
a++; a++;
b++; b++;
} }
@ -700,6 +700,9 @@ struct graph_t
} }
} }
if (in_error ())
return false;
if (!made_changes) if (!made_changes)
return false; return false;
@ -833,7 +836,11 @@ struct graph_t
if (index_map.has (node_idx)) if (index_map.has (node_idx))
return; return;
index_map.set (node_idx, duplicate (node_idx)); unsigned clone_idx = duplicate (node_idx);
if (!check_success (clone_idx != (unsigned) -1))
return;
index_map.set (node_idx, clone_idx);
for (const auto& l : object (node_idx).all_links ()) { for (const auto& l : object (node_idx).all_links ()) {
duplicate_subgraph (l.objidx, index_map); duplicate_subgraph (l.objidx, index_map);
} }
@ -918,12 +925,12 @@ struct graph_t
{ {
// Can't duplicate this node, doing so would orphan the original one as all remaining links // Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent. // to child are from parent.
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u => %u",
parent_idx, child_idx); parent_idx, child_idx);
return -1; return -1;
} }
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u => %u",
parent_idx, child_idx); parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx); unsigned clone_idx = duplicate (child_idx);
@ -981,7 +988,7 @@ struct graph_t
*/ */
bool raise_childrens_priority (unsigned parent_idx) bool raise_childrens_priority (unsigned parent_idx)
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %u",
parent_idx); parent_idx);
// This operation doesn't change ordering until a sort is run, so no need // This operation doesn't change ordering until a sort is run, so no need
// to invalidate positions. It does not change graph structure so no need // to invalidate positions. It does not change graph structure so no need

View file

@ -153,8 +153,8 @@ void print_overflows (graph_t& graph,
const auto& child = graph.vertices_[o.child]; const auto& child = graph.vertices_[o.child];
DEBUG_MSG (SUBSET_REPACK, nullptr, DEBUG_MSG (SUBSET_REPACK, nullptr,
" overflow from " " overflow from "
"%4d (%4d in, %4d out, space %2d) => " "%4u (%4u in, %4u out, space %2u) => "
"%4d (%4d in, %4d out, space %2d)", "%4u (%4u in, %4u out, space %2u)",
o.parent, o.parent,
parent.incoming_edges (), parent.incoming_edges (),
parent.obj.real_links.length + parent.obj.virtual_links.length, parent.obj.real_links.length + parent.obj.virtual_links.length,
@ -165,7 +165,7 @@ void print_overflows (graph_t& graph,
graph.space_for (o.child)); graph.space_for (o.child));
} }
if (overflows.length > 10) { if (overflows.length > 10) {
DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %u more overflows.", overflows.length - 10);
} }
} }

View file

@ -1,119 +0,0 @@
/*
* Copyright © 2022 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
*/
#include "gsubgpos-context.hh"
#include "classdef-graph.hh"
typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t;
typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
unsigned cov_expected, unsigned class_def_expected)
{
graph::class_def_size_estimator_t estimator (list.iter ());
unsigned result = estimator.incremental_coverage_size (klass);
if (result != cov_expected)
{
printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
return false;
}
result = estimator.incremental_class_def_size (klass);
if (result != class_def_expected)
{
printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
return false;
}
return true;
}
static void test_class_and_coverage_size_estimates ()
{
gid_and_class_list_t empty = {
};
assert (incremental_size_is (empty, 0, 0, 0));
assert (incremental_size_is (empty, 1, 0, 0));
gid_and_class_list_t class_zero = {
{5, 0},
};
assert (incremental_size_is (class_zero, 0, 2, 0));
gid_and_class_list_t consecutive = {
{4, 0},
{5, 0},
{6, 1},
{7, 1},
{8, 2},
{9, 2},
{10, 2},
{11, 2},
};
assert (incremental_size_is (consecutive, 0, 4, 0));
assert (incremental_size_is (consecutive, 1, 4, 4));
assert (incremental_size_is (consecutive, 2, 8, 6));
gid_and_class_list_t non_consecutive = {
{4, 0},
{5, 0},
{6, 1},
{7, 1},
{9, 2},
{10, 2},
{11, 2},
{12, 2},
};
assert (incremental_size_is (non_consecutive, 0, 4, 0));
assert (incremental_size_is (non_consecutive, 1, 4, 6));
assert (incremental_size_is (non_consecutive, 2, 8, 6));
gid_and_class_list_t multiple_ranges = {
{4, 0},
{5, 0},
{6, 1},
{7, 1},
{9, 1},
{11, 1},
{12, 1},
{13, 1},
};
assert (incremental_size_is (multiple_ranges, 0, 4, 0));
assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
}
int
main (int argc, char **argv)
{
test_class_and_coverage_size_estimates ();
}

View file

@ -28,6 +28,7 @@
#define HB_AAT_LAYOUT_COMMON_HH #define HB_AAT_LAYOUT_COMMON_HH
#include "hb-aat-layout.hh" #include "hb-aat-layout.hh"
#include "hb-aat-map.hh"
#include "hb-open-type.hh" #include "hb-open-type.hh"
namespace OT { namespace OT {
@ -39,6 +40,43 @@ namespace AAT {
using namespace OT; using namespace OT;
struct ankr;
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
const char *get_name () { return "APPLY"; }
template <typename T>
return_t dispatch (const T &obj) { return obj.apply (this); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
const hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
const OT::GDEF *gdef_table;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
HB_INTERNAL ~hb_aat_apply_context_t ();
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
};
/* /*
* Lookup Table * Lookup Table
*/ */
@ -740,16 +778,44 @@ struct StateTableDriver
num_glyphs (face_->get_num_glyphs ()) {} num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t> template <typename context_t>
void drive (context_t *c) void drive (context_t *c, hb_aat_apply_context_t *ac)
{ {
if (!c->in_place) if (!c->in_place)
buffer->clear_output (); buffer->clear_output ();
int state = StateTableT::STATE_START_OF_TEXT; int state = StateTableT::STATE_START_OF_TEXT;
// If there's only one range, we already checked the flag.
auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr;
for (buffer->idx = 0; buffer->successful;) for (buffer->idx = 0; buffer->successful;)
{ {
/* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
if (last_range)
{
auto *range = last_range;
if (buffer->idx < buffer->len)
{
unsigned cluster = buffer->cur().cluster;
while (cluster < range->cluster_first)
range--;
while (cluster > range->cluster_last)
range++;
last_range = range;
}
if (!(range->flags & ac->subtable_flags))
{
if (buffer->idx == buffer->len || unlikely (!buffer->successful))
break;
state = StateTableT::STATE_START_OF_TEXT;
(void) buffer->next_glyph ();
continue;
}
}
unsigned int klass = buffer->idx < buffer->len ? unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : machine.get_class (buffer->cur().codepoint, num_glyphs) :
(unsigned) StateTableT::CLASS_END_OF_TEXT; (unsigned) StateTableT::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const EntryT &entry = machine.get_entry (state, klass); const EntryT &entry = machine.get_entry (state, klass);
@ -845,41 +911,6 @@ struct StateTableDriver
}; };
struct ankr;
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
const char *get_name () { return "APPLY"; }
template <typename T>
return_t dispatch (const T &obj) { return obj.apply (this); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
const hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
const OT::GDEF *gdef_table;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
HB_INTERNAL ~hb_aat_apply_context_t ();
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
};
} /* namespace AAT */ } /* namespace AAT */

View file

@ -350,7 +350,7 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
driver.drive (&dc); driver.drive (&dc, c);
return_trace (true); return_trace (true);
} }
@ -594,7 +594,7 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
driver.drive (&dc); driver.drive (&dc, c);
return_trace (true); return_trace (true);
} }
@ -869,6 +869,8 @@ struct KerxTable
bool apply (AAT::hb_aat_apply_context_t *c) const bool apply (AAT::hb_aat_apply_context_t *c) const
{ {
c->buffer->unsafe_to_concat ();
typedef typename T::SubTable SubTable; typedef typename T::SubTable SubTable;
bool ret = false; bool ret = false;
@ -889,7 +891,7 @@ struct KerxTable
reverse = bool (st->u.header.coverage & st->u.header.Backwards) != reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index)) if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
goto skip; goto skip;
if (!seenCrossStream && if (!seenCrossStream &&
@ -921,7 +923,7 @@ struct KerxTable
if (reverse) if (reverse)
c->buffer->reverse (); c->buffer->reverse ();
(void) c->buffer->message (c->font, "end subtable %d", c->lookup_index); (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
skip: skip:
st = &StructAfter<SubTable> (*st); st = &StructAfter<SubTable> (*st);

View file

@ -169,7 +169,7 @@ struct RearrangementSubtable
driver_context_t dc (this); driver_context_t dc (this);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
} }
@ -325,7 +325,7 @@ struct ContextualSubtable
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
} }
@ -525,7 +525,7 @@ struct LigatureSubtable
if (unlikely (!componentData.sanitize (&c->sanitizer))) break; if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
ligature_idx += componentData; ligature_idx += componentData;
DEBUG_MSG (APPLY, nullptr, "Action store %u last %u", DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
bool (action & LigActionStore), bool (action & LigActionStore),
bool (action & LigActionLast)); bool (action & LigActionLast));
if (action & (LigActionStore | LigActionLast)) if (action & (LigActionStore | LigActionLast))
@ -577,7 +577,7 @@ struct LigatureSubtable
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
} }
@ -618,8 +618,27 @@ struct NoncontextualSubtable
hb_glyph_info_t *info = c->buffer->info; hb_glyph_info_t *info = c->buffer->info;
unsigned int count = c->buffer->len; unsigned int count = c->buffer->len;
// If there's only one range, we already checked the flag.
auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
/* This block copied from StateTableDriver::drive. Keep in sync. */
if (last_range)
{
auto *range = last_range;
{
unsigned cluster = info[i].cluster;
while (cluster < range->cluster_first)
range--;
while (cluster > range->cluster_last)
range++;
last_range = range;
}
if (!(range->flags & c->subtable_flags))
continue;
}
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
if (replacement) if (replacement)
{ {
@ -820,7 +839,7 @@ struct InsertionSubtable
driver_context_t dc (this, c); driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc); driver.drive (&dc, c);
return_trace (dc.ret); return_trace (dc.ret);
} }
@ -968,7 +987,7 @@ struct Chain
// Check whether this type/setting pair was requested in the map, and if so, apply its flags. // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
// (The search here only looks at the type and setting fields of feature_info_t.) // (The search here only looks at the type and setting fields of feature_info_t.)
hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
if (map->features.bsearch (info)) if (map->current_features.bsearch (info))
{ {
flags &= feature.disableFlags; flags &= feature.disableFlags;
flags |= feature.enableFlags; flags |= feature.enableFlags;
@ -994,8 +1013,7 @@ struct Chain
return flags; return flags;
} }
void apply (hb_aat_apply_context_t *c, void apply (hb_aat_apply_context_t *c) const
hb_mask_t flags) const
{ {
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
unsigned int count = subtableCount; unsigned int count = subtableCount;
@ -1003,8 +1021,10 @@ struct Chain
{ {
bool reverse; bool reverse;
if (!(subtable->subFeatureFlags & flags)) if (hb_none (hb_iter (c->range_flags) |
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
goto skip; goto skip;
c->subtable_flags = subtable->subFeatureFlags;
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) && if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@ -1043,7 +1063,7 @@ struct Chain
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) != bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index)) if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
goto skip; goto skip;
if (reverse) if (reverse)
@ -1054,7 +1074,7 @@ struct Chain
if (reverse) if (reverse)
c->buffer->reverse (); c->buffer->reverse ();
(void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
if (unlikely (!c->buffer->successful)) return; if (unlikely (!c->buffer->successful)) return;
@ -1120,22 +1140,31 @@ struct mortmorx
{ {
const Chain<Types> *chain = &firstChain; const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount; unsigned int count = chainCount;
if (unlikely (!map->chain_flags.resize (count)))
return;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
map->chain_flags.push (chain->compile_flags (mapper)); map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
mapper->range_first,
mapper->range_last});
chain = &StructAfter<Chain<Types>> (*chain); chain = &StructAfter<Chain<Types>> (*chain);
} }
} }
void apply (hb_aat_apply_context_t *c) const void apply (hb_aat_apply_context_t *c,
const hb_aat_map_t &map) const
{ {
if (unlikely (!c->buffer->successful)) return; if (unlikely (!c->buffer->successful)) return;
c->buffer->unsafe_to_concat ();
c->set_lookup_index (0); c->set_lookup_index (0);
const Chain<Types> *chain = &firstChain; const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount; unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
chain->apply (c, c->plan->aat_map.chain_flags[i]); c->range_flags = &map.chain_flags[i];
chain->apply (c);
if (unlikely (!c->buffer->successful)) return; if (unlikely (!c->buffer->successful)) return;
chain = &StructAfter<Chain<Types>> (*chain); chain = &StructAfter<Chain<Types>> (*chain);
} }

View file

@ -244,15 +244,23 @@ hb_aat_layout_has_substitution (hb_face_t *face)
void void
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
hb_buffer_t *buffer) hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned num_features)
{ {
hb_aat_map_builder_t builder (font->face, plan->props);
for (unsigned i = 0; i < num_features; i++)
builder.add_feature (features[i]);
hb_aat_map_t map;
builder.compile (map);
hb_blob_t *morx_blob = font->face->table.morx.get_blob (); hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
const AAT::morx& morx = *morx_blob->as<AAT::morx> (); const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
if (morx.has_data ()) if (morx.has_data ())
{ {
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
if (!buffer->message (font, "start table morx")) return; if (!buffer->message (font, "start table morx")) return;
morx.apply (&c); morx.apply (&c, map);
(void) buffer->message (font, "end table morx"); (void) buffer->message (font, "end table morx");
return; return;
} }
@ -263,7 +271,7 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
{ {
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
if (!buffer->message (font, "start table mort")) return; if (!buffer->message (font, "start table mort")) return;
mort.apply (&c); mort.apply (&c, map);
(void) buffer->message (font, "end table mort"); (void) buffer->message (font, "end table mort");
return; return;
} }

View file

@ -53,7 +53,9 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
HB_INTERNAL void HB_INTERNAL void
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
hb_buffer_t *buffer); hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned num_features);
HB_INTERNAL void HB_INTERNAL void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer); hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);

View file

@ -36,27 +36,29 @@
#include "hb-aat-layout-feat-table.hh" #include "hb-aat-layout-feat-table.hh"
void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature)
{ {
if (!face->table.feat->has_data ()) return; if (!face->table.feat->has_data ()) return;
if (tag == HB_TAG ('a','a','l','t')) if (feature.tag == HB_TAG ('a','a','l','t'))
{ {
if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES)) if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
return; return;
feature_info_t *info = features.push(); feature_range_t *range = features.push();
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; range->start = feature.start;
info->setting = (hb_aat_layout_feature_selector_t) value; range->end = feature.end;
info->seq = features.length; range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
info->is_exclusive = true; range->info.setting = (hb_aat_layout_feature_selector_t) feature.value;
range->info.seq = features.length;
range->info.is_exclusive = true;
return; return;
} }
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag);
if (!mapping) return; if (!mapping) return;
const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType); const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType);
if (!feature->has_data ()) if (!feature_name->has_data ())
{ {
/* Special case: Chain::compile_flags will fall back to the deprecated version of /* Special case: Chain::compile_flags will fall back to the deprecated version of
* small-caps if necessary, so we need to check for that possibility. * small-caps if necessary, so we need to check for that possibility.
@ -64,38 +66,106 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE && if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
{ {
feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
if (!feature->has_data ()) return; if (!feature_name->has_data ()) return;
} }
else return; else return;
} }
feature_info_t *info = features.push(); feature_range_t *range = features.push();
info->type = mapping->aatFeatureType; range->start = feature.start;
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; range->end = feature.end;
info->seq = features.length; range->info.type = mapping->aatFeatureType;
info->is_exclusive = feature->is_exclusive (); range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable;
range->info.seq = features.length;
range->info.is_exclusive = feature_name->is_exclusive ();
} }
void void
hb_aat_map_builder_t::compile (hb_aat_map_t &m) hb_aat_map_builder_t::compile (hb_aat_map_t &m)
{ {
/* Sort features and merge duplicates */ /* Compute active features per range, and compile each. */
if (features.length)
/* Sort features by start/end events. */
hb_vector_t<feature_event_t> feature_events;
for (unsigned int i = 0; i < features.length; i++)
{ {
features.qsort (); auto &feature = features[i];
if (features[i].start == features[i].end)
continue;
feature_event_t *event;
event = feature_events.push ();
event->index = features[i].start;
event->start = true;
event->feature = feature.info;
event = feature_events.push ();
event->index = features[i].end;
event->start = false;
event->feature = feature.info;
}
feature_events.qsort ();
/* Add a strategic final event. */
{
feature_info_t feature;
feature.seq = features.length + 1;
feature_event_t *event = feature_events.push ();
event->index = -1; /* This value does magic. */
event->start = false;
event->feature = feature;
}
/* Scan events and save features for each range. */
hb_sorted_vector_t<feature_info_t> active_features;
unsigned int last_index = 0;
for (unsigned int i = 0; i < feature_events.length; i++)
{
feature_event_t *event = &feature_events[i];
if (event->index != last_index)
{
/* Save a snapshot of active features and the range. */
/* Sort features and merge duplicates */
current_features = active_features;
range_first = last_index;
range_last = event->index - 1;
if (current_features.length)
{
current_features.qsort ();
unsigned int j = 0; unsigned int j = 0;
for (unsigned int i = 1; i < features.length; i++) for (unsigned int i = 1; i < current_features.length; i++)
if (features[i].type != features[j].type || if (current_features[i].type != current_features[j].type ||
/* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
* respectively, so we mask out the low-order bit when checking for "duplicates" * respectively, so we mask out the low-order bit when checking for "duplicates"
* (selectors referring to the same feature setting) here. */ * (selectors referring to the same feature setting) here. */
(!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1)))) (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1))))
features[++j] = features[i]; current_features[++j] = current_features[i];
features.shrink (j + 1); current_features.shrink (j + 1);
} }
hb_aat_layout_compile_map (this, &m); hb_aat_layout_compile_map (this, &m);
last_index = event->index;
}
if (event->start)
{
active_features.push (event->feature);
} else {
feature_info_t *feature = active_features.lsearch (event->feature);
if (feature)
active_features.remove_ordered (feature - active_features.arrayZ);
}
}
for (auto &chain_flags : m.chain_flags)
// With our above setup this value is one less than desired; adjust it.
chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END;
} }

View file

@ -35,16 +35,15 @@ struct hb_aat_map_t
friend struct hb_aat_map_builder_t; friend struct hb_aat_map_builder_t;
public: public:
struct range_flags_t
void init ()
{ {
hb_memset (this, 0, sizeof (*this)); hb_mask_t flags;
chain_flags.init (); unsigned cluster_first;
} unsigned cluster_last; // end - 1
void fini () { chain_flags.fini (); } };
public: public:
hb_vector_t<hb_mask_t> chain_flags; hb_vector_t<hb_sorted_vector_t<range_flags_t>> chain_flags;
}; };
struct hb_aat_map_builder_t struct hb_aat_map_builder_t
@ -56,7 +55,7 @@ struct hb_aat_map_builder_t
face (face_), face (face_),
props (props_) {} props (props_) {}
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); HB_INTERNAL void add_feature (const hb_feature_t &feature);
HB_INTERNAL void compile (hb_aat_map_t &m); HB_INTERNAL void compile (hb_aat_map_t &m);
@ -78,7 +77,7 @@ struct hb_aat_map_builder_t
return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
} }
/* compares type & setting only, not is_exclusive flag or seq number */ /* compares type & setting only */
int cmp (const feature_info_t& f) const int cmp (const feature_info_t& f) const
{ {
return (f.type != type) ? (f.type < type ? -1 : 1) : return (f.type != type) ? (f.type < type ? -1 : 1) :
@ -86,12 +85,38 @@ struct hb_aat_map_builder_t
} }
}; };
struct feature_range_t
{
feature_info_t info;
unsigned start;
unsigned end;
};
private:
struct feature_event_t
{
unsigned int index;
bool start;
feature_info_t feature;
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
const feature_event_t *a = (const feature_event_t *) pa;
const feature_event_t *b = (const feature_event_t *) pb;
return a->index < b->index ? -1 : a->index > b->index ? 1 :
a->start < b->start ? -1 : a->start > b->start ? 1 :
feature_info_t::cmp (&a->feature, &b->feature);
}
};
public: public:
hb_face_t *face; hb_face_t *face;
hb_segment_properties_t props; hb_segment_properties_t props;
public: public:
hb_sorted_vector_t<feature_info_t> features; hb_sorted_vector_t<feature_range_t> features;
hb_sorted_vector_t<feature_info_t> current_features;
unsigned range_first = HB_FEATURE_GLOBAL_START;
unsigned range_last = HB_FEATURE_GLOBAL_END;
}; };

View file

@ -110,9 +110,10 @@ struct BEInt<Type, 2>
constexpr operator Type () const constexpr operator Type () const
{ {
#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
defined(__BYTE_ORDER) && \ defined(__BYTE_ORDER) && \
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) (__BYTE_ORDER == __BIG_ENDIAN || \
(__BYTE_ORDER == __LITTLE_ENDIAN && \
hb_has_builtin(__builtin_bswap16)))
/* Spoon-feed the compiler a big-endian integer with alignment 1. /* Spoon-feed the compiler a big-endian integer with alignment 1.
* https://github.com/harfbuzz/harfbuzz/pull/1398 */ * https://github.com/harfbuzz/harfbuzz/pull/1398 */
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
@ -155,9 +156,10 @@ struct BEInt<Type, 4>
struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
constexpr operator Type () const { constexpr operator Type () const {
#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
defined(__BYTE_ORDER) && \ defined(__BYTE_ORDER) && \
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) (__BYTE_ORDER == __BIG_ENDIAN || \
(__BYTE_ORDER == __LITTLE_ENDIAN && \
hb_has_builtin(__builtin_bswap32)))
/* Spoon-feed the compiler a big-endian integer with alignment 1. /* Spoon-feed the compiler a big-endian integer with alignment 1.
* https://github.com/harfbuzz/harfbuzz/pull/1398 */ * https://github.com/harfbuzz/harfbuzz/pull/1398 */
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
@ -598,13 +600,17 @@ template <typename T>
static inline unsigned int static inline unsigned int
hb_popcount (T v) hb_popcount (T v)
{ {
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) #if hb_has_builtin(__builtin_popcount)
if (sizeof (T) <= sizeof (unsigned int)) if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (v); return __builtin_popcount (v);
#endif
#if hb_has_builtin(__builtin_popcountl)
if (sizeof (T) <= sizeof (unsigned long)) if (sizeof (T) <= sizeof (unsigned long))
return __builtin_popcountl (v); return __builtin_popcountl (v);
#endif
#if hb_has_builtin(__builtin_popcountll)
if (sizeof (T) <= sizeof (unsigned long long)) if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_popcountll (v); return __builtin_popcountll (v);
#endif #endif
@ -641,13 +647,17 @@ hb_bit_storage (T v)
{ {
if (unlikely (!v)) return 0; if (unlikely (!v)) return 0;
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) #if hb_has_builtin(__builtin_clz)
if (sizeof (T) <= sizeof (unsigned int)) if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v); return sizeof (unsigned int) * 8 - __builtin_clz (v);
#endif
#if hb_has_builtin(__builtin_clzl)
if (sizeof (T) <= sizeof (unsigned long)) if (sizeof (T) <= sizeof (unsigned long))
return sizeof (unsigned long) * 8 - __builtin_clzl (v); return sizeof (unsigned long) * 8 - __builtin_clzl (v);
#endif
#if hb_has_builtin(__builtin_clzll)
if (sizeof (T) <= sizeof (unsigned long long)) if (sizeof (T) <= sizeof (unsigned long long))
return sizeof (unsigned long long) * 8 - __builtin_clzll (v); return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif #endif
@ -715,13 +725,17 @@ hb_ctz (T v)
{ {
if (unlikely (!v)) return 8 * sizeof (T); if (unlikely (!v)) return 8 * sizeof (T);
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) #if hb_has_builtin(__builtin_ctz)
if (sizeof (T) <= sizeof (unsigned int)) if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v); return __builtin_ctz (v);
#endif
#if hb_has_builtin(__builtin_ctzl)
if (sizeof (T) <= sizeof (unsigned long)) if (sizeof (T) <= sizeof (unsigned long))
return __builtin_ctzl (v); return __builtin_ctzl (v);
#endif
#if hb_has_builtin(__builtin_ctzll)
if (sizeof (T) <= sizeof (unsigned long long)) if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_ctzll (v); return __builtin_ctzll (v);
#endif #endif
@ -875,7 +889,7 @@ hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
static inline bool static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr) hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
{ {
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) #if hb_has_builtin(__builtin_mul_overflow)
unsigned stack_result; unsigned stack_result;
if (!result) if (!result)
result = &stack_result; result = &stack_result;
@ -1330,4 +1344,62 @@ struct
HB_FUNCOBJ (hb_dec); HB_FUNCOBJ (hb_dec);
/* Adapted from kurbo implementation with extra parameters added,
* and finding for a particular range instead of 0.
*
* For documentation and implementation see:
*
* [ITP method]: https://en.wikipedia.org/wiki/ITP_Method
* [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597
* https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html
* https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248
*/
template <typename func_t>
double solve_itp (func_t f,
double a, double b,
double epsilon,
double min_y, double max_y,
double &ya, double &yb, double &y)
{
unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0));
const unsigned n0 = 1; // Hardwired
const double k1 = 0.2 / (b - a); // Hardwired.
unsigned nmax = n0 + n1_2;
double scaled_epsilon = epsilon * double (1llu << nmax);
double _2_epsilon = 2.0 * epsilon;
while (b - a > _2_epsilon)
{
double x1_2 = 0.5 * (a + b);
double r = scaled_epsilon - 0.5 * (b - a);
double xf = (yb * a - ya * b) / (yb - ya);
double sigma = x1_2 - xf;
double b_a = b - a;
// This has k2 = 2 hardwired for efficiency.
double b_a_k2 = b_a * b_a;
double delta = k1 * b_a_k2;
int sigma_sign = sigma >= 0 ? +1 : -1;
double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2;
double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign;
double yitp = f (xitp);
if (yitp > max_y)
{
b = xitp;
yb = yitp;
}
else if (yitp < min_y)
{
a = xitp;
ya = yitp;
}
else
{
y = yitp;
return xitp;
}
scaled_epsilon *= 0.5;
}
return 0.5 * (a + b);
}
#endif /* HB_ALGS_HH */ #endif /* HB_ALGS_HH */

View file

@ -304,6 +304,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
unsigned int backwards_length = 0; unsigned int backwards_length = 0;
}; };
template <typename T> inline hb_array_t<T> template <typename T> inline hb_array_t<T>
hb_array ()
{ return hb_array_t<T> (); }
template <typename T> inline hb_array_t<T>
hb_array (T *array, unsigned int length) hb_array (T *array, unsigned int length)
{ return hb_array_t<T> (array, length); } { return hb_array_t<T> (array, length); }
template <typename T, unsigned int length_> inline hb_array_t<T> template <typename T, unsigned int length_> inline hb_array_t<T>

View file

@ -84,11 +84,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) #define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) #define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) #define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed)) #define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release)) #define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed)) #define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire)) #define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed)) #define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
@ -111,10 +111,15 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#endif #endif
/* This should never be disabled, even under HB_NO_MT.
* except that MSVC gives me an internal compiler error, so disabled there.
*
* https://github.com/harfbuzz/harfbuzz/pull/4119
*/
#ifndef _hb_compiler_memory_r_barrier #ifndef _hb_compiler_memory_r_barrier
/* This we always use std::atomic for; and should never be disabled... #if defined(__ATOMIC_ACQUIRE) // gcc-like
* except that MSVC gives me an internal compiler error on it. */ #define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
#if !defined(_MSC_VER) #elif !defined(_MSC_VER)
#include <atomic> #include <atomic>
#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire) #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
#else #else
@ -145,15 +150,35 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#endif #endif
#ifndef hb_atomic_int_impl_set #ifndef hb_atomic_int_impl_set
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; }
#endif #endif
#ifndef hb_atomic_int_impl_get #ifndef hb_atomic_int_impl_get
inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; }
#endif #endif
#ifndef hb_atomic_ptr_impl_get #ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif #endif
struct hb_atomic_short_t
{
hb_atomic_short_t () = default;
constexpr hb_atomic_short_t (short v) : v (v) {}
hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
operator short () const { return get_relaxed (); }
void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
short get_acquire () const { return hb_atomic_int_impl_get (&v); }
short inc () { return hb_atomic_int_impl_add (&v, 1); }
short dec () { return hb_atomic_int_impl_add (&v, -1); }
short v = 0;
};
struct hb_atomic_int_t struct hb_atomic_int_t
{ {
hb_atomic_int_t () = default; hb_atomic_int_t () = default;

View file

@ -34,14 +34,24 @@
/* Compiler-assisted vectorization. */ /* Compiler-assisted vectorization. */
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
* basically a fixed-size bitset. */ * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot
* guarantee alignment requirements. */
template <typename elt_t, unsigned int byte_size> template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t struct hb_vector_size_t
{ {
elt_t& operator [] (unsigned int i) { return v[i]; } elt_t& operator [] (unsigned int i) { return v[i]; }
const elt_t& operator [] (unsigned int i) const { return v[i]; } const elt_t& operator [] (unsigned int i) const { return v[i]; }
void clear (unsigned char v = 0) { hb_memset (this, v, sizeof (*this)); } void init0 ()
{
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
v[i] = 0;
}
void init1 ()
{
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
v[i] = (elt_t) -1;
}
template <typename Op> template <typename Op>
hb_vector_size_t process (const Op& op) const hb_vector_size_t process (const Op& op) const
@ -79,10 +89,10 @@ struct hb_vector_size_t
struct hb_bit_page_t struct hb_bit_page_t
{ {
void init0 () { v.clear (); } void init0 () { v.init0 (); }
void init1 () { v.clear (0xFF); } void init1 () { v.init1 (); }
constexpr unsigned len () const static inline constexpr unsigned len ()
{ return ARRAY_LENGTH_CONST (v); } { return ARRAY_LENGTH_CONST (v); }
bool is_empty () const bool is_empty () const
@ -300,10 +310,10 @@ struct hb_bit_page_t
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
typedef unsigned long long elt_t; typedef unsigned long long elt_t;
static constexpr unsigned PAGE_BITS = 512; static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2;
static constexpr unsigned PAGE_BITS_LOG_2 = 9;
static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, ""); static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1; static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }

View file

@ -74,6 +74,11 @@ struct hb_bit_set_invertible_t
inverted = !inverted; inverted = !inverted;
} }
bool is_inverted () const
{
return inverted;
}
bool is_empty () const bool is_empty () const
{ {
hb_codepoint_t v = INVALID; hb_codepoint_t v = INVALID;

View file

@ -38,7 +38,7 @@ struct hb_bit_set_t
hb_bit_set_t () = default; hb_bit_set_t () = default;
~hb_bit_set_t () = default; ~hb_bit_set_t () = default;
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); } hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); } hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; } hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; } hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
@ -85,12 +85,16 @@ struct hb_bit_set_t
void err () { if (successful) successful = false; } /* TODO Remove */ void err () { if (successful) successful = false; } /* TODO Remove */
bool in_error () const { return !successful; } bool in_error () const { return !successful; }
bool resize (unsigned int count, bool clear = true) bool resize (unsigned int count, bool clear = true, bool exact_size = false)
{ {
if (unlikely (!successful)) return false; if (unlikely (!successful)) return false;
if (unlikely (!pages.resize (count, clear) || !page_map.resize (count, clear)))
if (pages.length == 0 && count == 1)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size)))
{ {
pages.resize (page_map.length); pages.resize (page_map.length, clear, exact_size);
successful = false; successful = false;
return false; return false;
} }
@ -346,11 +350,11 @@ struct hb_bit_set_t
hb_codepoint_t c = first - 1; hb_codepoint_t c = first - 1;
return next (&c) && c <= last; return next (&c) && c <= last;
} }
void set (const hb_bit_set_t &other) void set (const hb_bit_set_t &other, bool exact_size = false)
{ {
if (unlikely (!successful)) return; if (unlikely (!successful)) return;
unsigned int count = other.pages.length; unsigned int count = other.pages.length;
if (unlikely (!resize (count, false))) if (unlikely (!resize (count, false, exact_size)))
return; return;
population = other.population; population = other.population;
@ -422,7 +426,7 @@ struct hb_bit_set_t
private: private:
bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace) bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
{ {
if (unlikely (!workspace.resize (pages.length))) if (unlikely (!workspace.resize_exact (pages.length)))
{ {
successful = false; successful = false;
return false; return false;

View file

@ -676,7 +676,7 @@ fail_without_close:
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
if (unlikely (!wchar_file_name)) goto fail_without_close; if (unlikely (!wchar_file_name)) goto fail_without_close;
mbstowcs (wchar_file_name, file_name, size); mbstowcs (wchar_file_name, file_name, size);
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
{ {
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
@ -697,7 +697,7 @@ fail_without_close:
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
{ {
LARGE_INTEGER length; LARGE_INTEGER length;
GetFileSizeEx (fd, &length); GetFileSizeEx (fd, &length);
@ -710,7 +710,7 @@ fail_without_close:
#endif #endif
if (unlikely (!file->mapping)) goto fail; if (unlikely (!file->mapping)) goto fail;
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
#else #else
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);

View file

@ -63,7 +63,7 @@ HB_BEGIN_DECLS
* HarfBuzz and doing that just once (no reuse!), * HarfBuzz and doing that just once (no reuse!),
* *
* - If the font is mmap()ed, it's okay to use * - If the font is mmap()ed, it's okay to use
* @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, however, using that mode
* correctly is very tricky. Use @HB_MEMORY_MODE_READONLY instead. * correctly is very tricky. Use @HB_MEMORY_MODE_READONLY instead.
**/ **/
typedef enum { typedef enum {

View file

@ -35,34 +35,34 @@
#line 33 "hb-buffer-deserialize-json.hh" #line 33 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = { static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u,
120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u,
9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u,
9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u,
34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u,
9u, 123u, 0u, 0u, 0 9u, 123u, 0u, 0u, 0
}; };
static const char _deserialize_json_key_spans[] = { static const char _deserialize_json_key_spans[] = {
0, 115, 26, 21, 2, 1, 50, 49, 0, 115, 26, 21, 2, 1, 50, 49,
10, 117, 117, 117, 1, 50, 49, 10, 10, 117, 117, 85, 117, 1, 50, 49,
117, 117, 1, 1, 50, 49, 117, 117, 10, 117, 117, 1, 1, 50, 49, 117,
2, 1, 50, 49, 10, 117, 117, 1, 117, 2, 1, 50, 49, 10, 117, 117,
50, 49, 10, 117, 117, 1, 1, 50, 1, 50, 49, 10, 117, 117, 1, 1,
49, 117, 117, 1, 50, 49, 59, 117, 50, 49, 117, 117, 1, 50, 49, 59,
59, 117, 117, 1, 50, 49, 117, 85, 117, 59, 117, 117, 1, 50, 49, 117,
115, 0 115, 0
}; };
static const short _deserialize_json_index_offsets[] = { static const short _deserialize_json_index_offsets[] = {
0, 0, 116, 143, 165, 168, 170, 221, 0, 0, 116, 143, 165, 168, 170, 221,
271, 282, 400, 518, 636, 638, 689, 739, 271, 282, 400, 518, 604, 722, 724, 775,
750, 868, 986, 988, 990, 1041, 1091, 1209, 825, 836, 954, 1072, 1074, 1076, 1127, 1177,
1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, 1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648,
1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034, 1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118,
2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534, 2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560,
2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169, 2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137,
3255, 3371 3255, 3371
}; };
@ -131,41 +131,52 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 24, 1, 20, 1, 1, 1, 1, 1, 24, 1, 25,
20, 20, 20, 20, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 20, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 21, 1, 1, 1, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 22, 1, 25, 1, 25,
25, 25, 25, 25, 1, 1, 1, 1, 25, 25, 25, 25, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, 25, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 26, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
26, 1, 26, 26, 26, 26, 26, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 26, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 27, 1,
1, 28, 29, 29, 29, 29, 29, 29,
29, 29, 29, 1, 30, 31, 31, 31,
31, 31, 31, 31, 31, 31, 1, 32,
32, 32, 32, 32, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 32, 1, 1, 1, 1, 27, 1, 20, 20, 20,
20, 20, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
21, 1, 1, 1, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 22, 1, 28, 1, 28, 28, 28,
28, 28, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 28, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 29, 1,
29, 29, 29, 29, 29, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 29,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 30, 1, 1, 31,
32, 32, 32, 32, 32, 32, 32, 32,
32, 1, 33, 34, 34, 34, 34, 34,
34, 34, 34, 34, 1, 35, 35, 35,
35, 35, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 35, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
36, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -175,39 +186,39 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 34, 1, 32, 32, 32, 1, 37, 1, 35, 35, 35, 35, 35,
32, 32, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 32, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
33, 1, 1, 1, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 34, 1, 35, 1, 36, 1, 36,
36, 36, 36, 36, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 36, 1, 1, 1, 1, 1, 1, 1, 36, 1,
1, 1, 34, 34, 34, 34, 34, 34,
34, 34, 34, 34, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
37, 1, 37, 37, 37, 37, 37, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 37, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 38, 39, 39, 39, 39, 39, 39,
39, 39, 39, 1, 40, 40, 40, 40,
40, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37,
1, 38, 1, 39, 1, 39, 39, 39,
39, 39, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 39, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 40, 1,
40, 40, 40, 40, 40, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 40,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 41, 1, 1, 1, 1, 1, 1, 1, 41,
42, 42, 42, 42, 42, 42, 42, 42,
42, 1, 43, 43, 43, 43, 43, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 43, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 44, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -217,14 +228,14 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 45, 1,
43, 43, 43, 43, 43, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
42, 1, 40, 40, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 43,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 44, 1, 1, 1, 46,
1, 40, 1, 1, 1, 1, 1, 1, 46, 46, 46, 46, 46, 46, 46, 46,
1, 1, 1, 1, 1, 41, 1, 1, 46, 1, 1, 1, 1, 1, 1, 1,
1, 43, 43, 43, 43, 43, 43, 43,
43, 43, 43, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -232,186 +243,163 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 42, 1, 1, 1, 1, 1, 45, 1, 47, 48,
44, 45, 1, 46, 1, 46, 46, 46, 1, 49, 1, 49, 49, 49, 49, 49,
46, 46, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 46, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 47, 1, 1, 1, 49, 1, 1, 1, 1, 1,
47, 47, 47, 47, 47, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 47,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 48, 1, 1, 49,
50, 50, 50, 50, 50, 50, 50, 50,
50, 1, 51, 52, 52, 52, 52, 52,
52, 52, 52, 52, 1, 53, 53, 53,
53, 53, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 53, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
54, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 50, 1, 50, 50,
50, 50, 50, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 50, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 51, 1, 1, 52, 53, 53,
1, 1, 1, 1, 1, 1, 1, 1, 53, 53, 53, 53, 53, 53, 53, 1,
1, 1, 1, 1, 1, 1, 1, 1, 54, 55, 55, 55, 55, 55, 55, 55,
1, 1, 1, 1, 1, 1, 1, 1, 55, 55, 1, 56, 56, 56, 56, 56,
1, 1, 1, 1, 1, 1, 1, 1,
1, 55, 1, 53, 53, 53, 53, 53,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 53, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 54, 1,
1, 1, 52, 52, 52, 52, 52, 52,
52, 52, 52, 52, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 55,
1, 56, 1, 56, 56, 56, 56, 56,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 56, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 57, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 57, 1, 57, 57,
57, 57, 57, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 57, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 58, 1, 1, 59, 60, 60,
60, 60, 60, 60, 60, 60, 60, 1,
61, 62, 62, 62, 62, 62, 62, 62,
62, 62, 1, 63, 63, 63, 63, 63,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 63, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 64, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 58,
1, 56, 56, 56, 56, 56, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 57, 1, 1, 1,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 65,
1, 63, 63, 63, 63, 63, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
63, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 64, 1, 1, 1,
62, 62, 62, 62, 62, 62, 62, 62,
62, 62, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 58, 1, 59,
1, 59, 59, 59, 59, 59, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
59, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 60, 1, 60, 60, 60, 60,
60, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 60, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 65, 1, 66, 61, 1, 1, 62, 63, 63, 63, 63,
1, 67, 1, 67, 67, 67, 67, 67, 63, 63, 63, 63, 63, 1, 64, 65,
65, 65, 65, 65, 65, 65, 65, 65,
1, 66, 66, 66, 66, 66, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 67, 1, 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 67, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 68, 1, 68, 68,
68, 68, 68, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 68, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 69, 70, 70,
70, 70, 70, 70, 70, 70, 70, 1,
71, 71, 71, 71, 71, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 71,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 72, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 68, 1, 66,
66, 66, 66, 66, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 66, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 67, 1, 1, 1, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 73, 1, 71, 71,
71, 71, 71, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 71, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 72, 1, 1, 1, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 68, 1, 69, 1, 70,
1, 70, 70, 70, 70, 70, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 71, 1, 71, 71, 71, 71,
71, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 71, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 73, 1, 75, 1, 75, 75, 1, 1, 1, 72, 73, 73, 73, 73,
75, 75, 75, 1, 1, 1, 1, 1, 73, 73, 73, 73, 73, 1, 74, 74,
74, 74, 74, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 75, 1, 1, 1, 1, 1, 1, 1, 74, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 75, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 76,
1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76, 1, 77, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78, 79, 79, 79, 79, 79, 79, 79,
79, 79, 1, 81, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 82, 80, 83,
83, 83, 83, 83, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 83, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 84, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 76, 1, 74, 74, 74, 74,
74, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 74, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 75,
1, 1, 1, 77, 77, 77, 77, 77,
77, 77, 77, 77, 77, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 85, 1, 80, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76, 1, 78, 1, 78, 78, 78, 78,
78, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 78, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 80, 1, 1, 1, 1, 1, 79, 1, 79,
1, 86, 86, 86, 86, 86, 1, 1, 79, 79, 79, 79, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 79, 1,
80, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 81, 82,
82, 82, 82, 82, 82, 82, 82, 82,
1, 84, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 85, 83, 86, 86, 86,
86, 86, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 86, 1, 1, 1,
1, 1, 1, 1, 87, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
87, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -420,42 +408,64 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 88, 1, 86,
86, 86, 86, 86, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 86, 1, 1, 88, 1, 83, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 87, 1, 1, 1, 89, 89,
89, 89, 89, 89, 89, 89, 89, 89,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 83, 1, 89,
89, 89, 89, 89, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 89, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 90, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 88, 1, 90, 1, 90,
90, 90, 90, 90, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 90, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
91, 1, 91, 91, 91, 91, 91, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 91, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 92, 93, 93, 93, 93, 93, 93,
93, 93, 93, 1, 86, 86, 86, 86,
86, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 86, 1, 1, 1, 1, 1, 1, 1, 91, 1, 89, 89, 89,
1, 1, 1, 1, 1, 1, 1, 87, 89, 89, 1, 1, 1, 1, 1, 1,
1, 1, 1, 94, 94, 94, 94, 94, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 89, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
90, 1, 1, 1, 92, 92, 92, 92,
92, 92, 92, 92, 92, 92, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 91, 1, 93, 1, 93, 93, 93,
93, 93, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 93, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 94, 1,
94, 94, 94, 94, 94, 1, 1, 1, 94, 94, 94, 94, 94, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 94,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 95,
96, 96, 96, 96, 96, 96, 96, 96,
96, 1, 89, 89, 89, 89, 89, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 89, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 90, 1, 1,
1, 97, 97, 97, 97, 97, 97, 97,
97, 97, 97, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -463,17 +473,7 @@ static const char _deserialize_json_indicies[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
88, 1, 95, 95, 95, 95, 95, 1, 1, 1, 1, 1, 1, 1, 91, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 95, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 96, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 97, 1,
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
@ -492,39 +492,39 @@ static const char _deserialize_json_indicies[] = {
}; };
static const char _deserialize_json_trans_targs[] = { static const char _deserialize_json_trans_targs[] = {
1, 0, 2, 2, 3, 4, 18, 24, 1, 0, 2, 2, 3, 4, 19, 25,
37, 43, 51, 5, 12, 6, 7, 8, 38, 44, 52, 5, 13, 6, 7, 8,
9, 11, 9, 11, 10, 2, 55, 10, 9, 12, 9, 12, 10, 2, 11, 10,
55, 13, 14, 15, 16, 17, 16, 17, 11, 11, 56, 57, 14, 15, 16, 17,
10, 2, 55, 19, 20, 21, 22, 23, 18, 17, 18, 10, 2, 11, 20, 21,
10, 2, 55, 23, 25, 31, 26, 27, 22, 23, 24, 10, 2, 11, 24, 26,
28, 29, 30, 29, 30, 10, 2, 55, 32, 27, 28, 29, 30, 31, 30, 31,
32, 33, 34, 35, 36, 35, 36, 10, 10, 2, 11, 33, 34, 35, 36, 37,
2, 55, 38, 39, 40, 41, 42, 10, 36, 37, 10, 2, 11, 39, 40, 41,
2, 55, 42, 44, 45, 46, 49, 50, 42, 43, 10, 2, 11, 43, 45, 46,
46, 47, 48, 10, 2, 55, 10, 2, 47, 50, 51, 47, 48, 49, 10, 2,
55, 50, 52, 53, 49, 54, 54, 55, 11, 10, 2, 11, 51, 53, 54, 50,
56, 57 55, 55
}; };
static const char _deserialize_json_trans_actions[] = { static const char _deserialize_json_trans_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2,
2, 2, 0, 0, 3, 3, 4, 0, 2, 2, 0, 0, 3, 3, 4, 0,
5, 0, 0, 2, 2, 2, 0, 0, 5, 0, 0, 0, 0, 0, 2, 2,
6, 6, 7, 0, 0, 0, 2, 2, 2, 0, 0, 6, 6, 7, 0, 0,
8, 8, 9, 0, 0, 0, 0, 0, 0, 2, 2, 8, 8, 9, 0, 0,
2, 2, 2, 0, 0, 10, 10, 11, 0, 0, 0, 2, 2, 2, 0, 0,
0, 0, 2, 2, 2, 0, 0, 12, 10, 10, 11, 0, 0, 2, 2, 2,
12, 13, 0, 0, 0, 2, 2, 14, 0, 0, 12, 12, 13, 0, 0, 0,
14, 15, 0, 0, 0, 2, 16, 16, 2, 2, 14, 14, 15, 0, 0, 0,
0, 17, 0, 18, 18, 19, 20, 20, 2, 16, 16, 0, 17, 0, 18, 18,
21, 17, 0, 0, 22, 22, 23, 0, 19, 20, 20, 21, 17, 0, 0, 22,
0, 0 22, 23
}; };
static const int deserialize_json_start = 1; static const int deserialize_json_start = 1;
static const int deserialize_json_first_final = 55; static const int deserialize_json_first_final = 56;
static const int deserialize_json_error = 0; static const int deserialize_json_error = 0;
static const int deserialize_json_en_main = 1; static const int deserialize_json_en_main = 1;
@ -548,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
while (p < pe && ISSPACE (*p)) while (p < pe && ISSPACE (*p))
p++; p++;
if (p < pe && *p == (buffer->len ? ',' : '[')) if (p < pe && *p == (buffer->len ? ',' : '['))
{
*end_ptr = ++p; *end_ptr = ++p;
}
const char *tok = nullptr; const char *tok = nullptr;
int cs; int cs;
hb_glyph_info_t info = {0}; hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0}; hb_glyph_position_t pos = {0};
#line 554 "hb-buffer-deserialize-json.hh" #line 552 "hb-buffer-deserialize-json.hh"
{ {
cs = deserialize_json_start; cs = deserialize_json_start;
} }
#line 557 "hb-buffer-deserialize-json.hh" #line 555 "hb-buffer-deserialize-json.hh"
{ {
int _slen; int _slen;
int _trans; int _trans;
@ -774,7 +772,7 @@ _resume:
*end_ptr = p; *end_ptr = p;
} }
break; break;
#line 735 "hb-buffer-deserialize-json.hh" #line 733 "hb-buffer-deserialize-json.hh"
} }
_again: _again:
@ -786,7 +784,7 @@ _again:
_out: {} _out: {}
} }
#line 139 "hb-buffer-deserialize-json.rl" #line 137 "hb-buffer-deserialize-json.rl"
*end_ptr = p; *end_ptr = p;

View file

@ -0,0 +1,692 @@
#line 1 "hb-buffer-deserialize-text-glyphs.rl"
/*
* Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
#include "hb.hh"
#line 33 "hb-buffer-deserialize-text-glyphs.hh"
static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 9u, 124u, 9u, 124u, 0
};
static const char _deserialize_text_glyphs_key_spans[] = {
0, 10, 13, 10, 13, 10, 10, 13,
10, 1, 13, 10, 14, 82, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116
};
static const short _deserialize_text_glyphs_index_offsets[] = {
0, 0, 11, 25, 36, 50, 61, 72,
86, 97, 99, 113, 124, 139, 222, 339,
456, 573, 690, 807, 924, 1041, 1158, 1275,
1392, 1509, 1626
};
static const char _deserialize_text_glyphs_indicies[] = {
0, 2, 2, 2, 2, 2, 2,
2, 2, 2, 1, 3, 1, 1, 4,
5, 5, 5, 5, 5, 5, 5, 5,
5, 1, 6, 7, 7, 7, 7, 7,
7, 7, 7, 7, 1, 8, 1, 1,
9, 10, 10, 10, 10, 10, 10, 10,
10, 10, 1, 11, 12, 12, 12, 12,
12, 12, 12, 12, 12, 1, 13, 14,
14, 14, 14, 14, 14, 14, 14, 14,
1, 15, 1, 1, 16, 17, 17, 17,
17, 17, 17, 17, 17, 17, 1, 18,
19, 19, 19, 19, 19, 19, 19, 19,
19, 1, 20, 1, 21, 1, 1, 22,
23, 23, 23, 23, 23, 23, 23, 23,
23, 1, 24, 25, 25, 25, 25, 25,
25, 25, 25, 25, 1, 20, 1, 1,
1, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 1, 26, 26, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 26, 1,
1, 26, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 26, 26, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 26, 1, 28,
28, 28, 28, 28, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 28, 27,
27, 29, 27, 27, 27, 27, 27, 27,
27, 30, 1, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 31, 27, 27, 32, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 33, 1, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 28, 27, 34, 34, 34, 34,
34, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 34, 26, 26, 35, 26,
26, 26, 26, 26, 26, 26, 36, 1,
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26,
37, 26, 26, 38, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 39,
1, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 40,
26, 41, 41, 41, 41, 41, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
41, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 42, 1, 43, 43,
43, 43, 43, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 43, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 44, 1, 41, 41, 41, 41, 41,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 41, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 42, 1,
46, 46, 46, 46, 46, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 46,
1, 1, 47, 1, 1, 1, 1, 1,
1, 1, 1, 48, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 49, 1, 50, 50, 50,
50, 50, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 50, 1, 1, 51,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
52, 1, 50, 50, 50, 50, 50, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 50, 1, 1, 51, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 52, 1, 46,
46, 46, 46, 46, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 46, 1,
1, 47, 1, 1, 1, 1, 1, 1,
1, 1, 48, 1, 1, 1, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 49, 1, 53, 53, 53, 53,
53, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 53, 1, 1, 54, 1,
1, 1, 1, 1, 1, 1, 55, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 56, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 57,
1, 58, 58, 58, 58, 58, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
58, 1, 1, 59, 1, 1, 1, 1,
1, 1, 1, 60, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 61, 1, 58, 58,
58, 58, 58, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 58, 1, 1,
59, 1, 1, 1, 1, 1, 1, 1,
60, 1, 1, 1, 1, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 61, 1, 53, 53, 53, 53, 53,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 53, 1, 1, 54, 1, 1,
1, 1, 1, 1, 1, 55, 1, 1,
1, 1, 62, 62, 62, 62, 62, 62,
62, 62, 62, 62, 1, 1, 1, 1,
1, 1, 56, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 57, 1,
0
};
static const char _deserialize_text_glyphs_trans_targs[] = {
16, 0, 18, 3, 19, 22, 19, 22,
5, 20, 21, 20, 21, 23, 26, 8,
9, 12, 9, 12, 10, 11, 24, 25,
24, 25, 15, 15, 14, 1, 2, 6,
7, 13, 15, 1, 2, 6, 7, 13,
14, 17, 14, 17, 14, 18, 17, 1,
4, 14, 17, 1, 14, 17, 1, 2,
7, 14, 17, 1, 2, 14, 26
};
static const char _deserialize_text_glyphs_trans_actions[] = {
1, 0, 1, 1, 1, 1, 0, 0,
1, 1, 1, 0, 0, 1, 1, 1,
1, 1, 0, 0, 2, 1, 1, 1,
0, 0, 0, 4, 3, 5, 5, 5,
5, 4, 6, 7, 7, 7, 7, 0,
6, 8, 8, 0, 0, 0, 9, 10,
10, 9, 11, 12, 11, 13, 14, 14,
14, 13, 15, 16, 16, 15, 0
};
static const char _deserialize_text_glyphs_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 3, 6,
8, 0, 8, 9, 11, 11, 9, 13,
15, 15, 13
};
static const int deserialize_text_glyphs_start = 14;
static const int deserialize_text_glyphs_first_final = 14;
static const int deserialize_text_glyphs_error = 0;
static const int deserialize_text_glyphs_en_main = 14;
#line 98 "hb-buffer-deserialize-text-glyphs.rl"
static hb_bool_t
_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '['))
*end_ptr = ++p;
const char *end = strchr ((char *) p, ']');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
#line 346 "hb-buffer-deserialize-text-glyphs.hh"
{
cs = deserialize_text_glyphs_start;
}
#line 349 "hb-buffer-deserialize-text-glyphs.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_text_glyphs_trans_keys + (cs<<1);
_inds = _deserialize_text_glyphs_indicies + _deserialize_text_glyphs_index_offsets[cs];
_slen = _deserialize_text_glyphs_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_text_glyphs_trans_targs[_trans];
if ( _deserialize_text_glyphs_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_text_glyphs_trans_actions[_trans] ) {
case 1:
#line 51 "hb-buffer-deserialize-text-glyphs.rl"
{
tok = p;
}
break;
case 7:
#line 55 "hb-buffer-deserialize-text-glyphs.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 14:
#line 63 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 2:
#line 64 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 16:
#line 65 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 10:
#line 66 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 12:
#line 67 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
break;
case 4:
#line 38 "hb-buffer-deserialize-text-glyphs.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text-glyphs.rl"
{
tok = p;
}
break;
case 6:
#line 55 "hb-buffer-deserialize-text-glyphs.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 13:
#line 63 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 15:
#line 65 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 66 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 67 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 8:
#line 68 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_uint (tok, p, &info.mask )) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 5:
#line 38 "hb-buffer-deserialize-text-glyphs.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text-glyphs.rl"
{
tok = p;
}
#line 55 "hb-buffer-deserialize-text-glyphs.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 3:
#line 38 "hb-buffer-deserialize-text-glyphs.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text-glyphs.rl"
{
tok = p;
}
#line 55 "hb-buffer-deserialize-text-glyphs.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 516 "hb-buffer-deserialize-text-glyphs.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
switch ( _deserialize_text_glyphs_eof_actions[cs] ) {
case 6:
#line 55 "hb-buffer-deserialize-text-glyphs.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 13:
#line 63 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 15:
#line 65 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 66 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 67 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 8:
#line 68 "hb-buffer-deserialize-text-glyphs.rl"
{ if (!parse_uint (tok, p, &info.mask )) return false; }
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 3:
#line 38 "hb-buffer-deserialize-text-glyphs.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text-glyphs.rl"
{
tok = p;
}
#line 55 "hb-buffer-deserialize-text-glyphs.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text-glyphs.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 616 "hb-buffer-deserialize-text-glyphs.hh"
}
}
_out: {}
}
#line 136 "hb-buffer-deserialize-text-glyphs.rl"
if (pe < orig_pe && *pe == ']')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;
}
#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */

View file

@ -0,0 +1,332 @@
#line 1 "hb-buffer-deserialize-text-unicode.rl"
/*
* Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
#include "hb.hh"
#line 33 "hb-buffer-deserialize-text-unicode.hh"
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 0
};
static const char _deserialize_text_unicode_key_spans[] = {
0, 109, 60, 55, 10, 116, 116, 116,
116
};
static const short _deserialize_text_unicode_index_offsets[] = {
0, 0, 110, 171, 227, 238, 355, 472,
589
};
static const char _deserialize_text_unicode_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 3,
1, 1, 1, 1, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 5, 6, 6, 6,
6, 6, 6, 6, 6, 6, 1, 7,
7, 7, 7, 7, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 7, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
1, 1, 1, 9, 1, 1, 1, 8,
8, 8, 8, 8, 8, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 8,
8, 8, 8, 8, 8, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 10, 1, 11, 11, 11, 11,
11, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 11, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0,
1, 12, 12, 12, 12, 12, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
12, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 13, 1, 12, 12,
12, 12, 12, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 12, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 13, 1, 0
};
static const char _deserialize_text_unicode_trans_targs[] = {
1, 0, 2, 3, 5, 7, 8, 6,
5, 4, 1, 6, 6, 1, 8
};
static const char _deserialize_text_unicode_trans_actions[] = {
0, 0, 1, 0, 2, 2, 2, 3,
0, 4, 3, 0, 5, 5, 0
};
static const char _deserialize_text_unicode_eof_actions[] = {
0, 0, 0, 0, 0, 3, 0, 5,
5
};
static const int deserialize_text_unicode_start = 1;
static const int deserialize_text_unicode_first_final = 5;
static const int deserialize_text_unicode_error = 0;
static const int deserialize_text_unicode_en_main = 1;
#line 79 "hb-buffer-deserialize-text-unicode.rl"
static hb_bool_t
_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '<'))
*end_ptr = ++p;
const char *end = strchr ((char *) p, '>');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
const hb_glyph_position_t pos = {0};
#line 194 "hb-buffer-deserialize-text-unicode.hh"
{
cs = deserialize_text_unicode_start;
}
#line 197 "hb-buffer-deserialize-text-unicode.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_text_unicode_trans_keys + (cs<<1);
_inds = _deserialize_text_unicode_indicies + _deserialize_text_unicode_index_offsets[cs];
_slen = _deserialize_text_unicode_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_text_unicode_trans_targs[_trans];
if ( _deserialize_text_unicode_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
case 1:
#line 38 "hb-buffer-deserialize-text-unicode.rl"
{
hb_memset (&info, 0, sizeof (info));
}
break;
case 2:
#line 51 "hb-buffer-deserialize-text-unicode.rl"
{
tok = p;
}
break;
case 4:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
break;
case 3:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 5:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 256 "hb-buffer-deserialize-text-unicode.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
switch ( _deserialize_text_unicode_eof_actions[cs] ) {
case 3:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 5:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 289 "hb-buffer-deserialize-text-unicode.hh"
}
}
_out: {}
}
#line 115 "hb-buffer-deserialize-text-unicode.rl"
if (pe < orig_pe && *pe == '>')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;
}
#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */

View file

@ -1,917 +0,0 @@
#line 1 "hb-buffer-deserialize-text.rl"
/*
* Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
#define HB_BUFFER_DESERIALIZE_TEXT_HH
#include "hb.hh"
#line 33 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 48u, 57u,
45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u,
45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u,
9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
0
};
static const char _deserialize_text_key_spans[] = {
0, 83, 1, 1, 55, 77, 10, 10,
13, 10, 13, 10, 10, 13, 10, 1,
13, 10, 14, 82, 116, 116, 0, 77,
116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116
};
static const short _deserialize_text_index_offsets[] = {
0, 0, 84, 86, 88, 144, 222, 233,
244, 258, 269, 283, 294, 305, 319, 330,
332, 346, 357, 372, 455, 572, 689, 690,
768, 885, 1002, 1119, 1236, 1353, 1470, 1587,
1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523
};
static const char _deserialize_text_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 3, 1, 4, 1, 5,
1, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 1, 1, 1, 1, 1,
1, 1, 6, 6, 6, 6, 6, 6,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 6, 6, 6, 6, 6, 6,
1, 7, 7, 7, 7, 7, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
7, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 1, 8,
9, 9, 9, 9, 9, 9, 9, 9,
9, 1, 10, 11, 11, 11, 11, 11,
11, 11, 11, 11, 1, 12, 1, 1,
13, 14, 14, 14, 14, 14, 14, 14,
14, 14, 1, 15, 16, 16, 16, 16,
16, 16, 16, 16, 16, 1, 17, 1,
1, 18, 19, 19, 19, 19, 19, 19,
19, 19, 19, 1, 20, 21, 21, 21,
21, 21, 21, 21, 21, 21, 1, 22,
23, 23, 23, 23, 23, 23, 23, 23,
23, 1, 24, 1, 1, 25, 26, 26,
26, 26, 26, 26, 26, 26, 26, 1,
27, 28, 28, 28, 28, 28, 28, 28,
28, 28, 1, 29, 1, 30, 1, 1,
31, 32, 32, 32, 32, 32, 32, 32,
32, 32, 1, 33, 34, 34, 34, 34,
34, 34, 34, 34, 34, 1, 29, 1,
1, 1, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 1, 35, 35, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 35,
1, 1, 35, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 35, 35,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 35, 1,
36, 36, 36, 36, 36, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 36,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 37,
37, 37, 37, 37, 37, 37, 37, 37,
37, 1, 1, 1, 38, 39, 1, 1,
37, 37, 37, 37, 37, 37, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
37, 37, 37, 37, 37, 37, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 40, 1, 41, 41, 41,
41, 41, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 41, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 42, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
43, 1, 1, 7, 7, 7, 7, 7,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 7, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 4,
1, 44, 44, 44, 44, 44, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
44, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 46, 1, 44, 44,
44, 44, 44, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 44, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 1,
1, 1, 1, 45, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 46, 1, 49, 49, 49, 49, 49,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 49, 48, 48, 50, 48, 48,
48, 48, 48, 48, 48, 51, 1, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 52,
48, 48, 53, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 54, 55,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 56, 48,
57, 57, 57, 57, 57, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 57,
35, 35, 58, 35, 35, 35, 35, 35,
35, 35, 59, 1, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 60, 35, 35, 61,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 62, 63, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 64, 35, 65, 65, 65,
65, 65, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 65, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 66, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
67, 1, 68, 68, 68, 68, 68, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 68, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 42, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 69, 1, 70,
70, 70, 70, 70, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 70, 48,
48, 50, 48, 48, 48, 48, 48, 48,
48, 51, 1, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 52, 48, 48, 53, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 54, 55, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 56, 48, 71, 71, 71, 71,
71, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 71, 1, 1, 72, 1,
1, 1, 1, 1, 1, 1, 1, 73,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
74, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 75,
1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
76, 1, 1, 77, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 78, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 79, 1, 76, 76,
76, 76, 76, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 76, 1, 1,
77, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 78, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 79, 1, 71, 71, 71, 71, 71,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 71, 1, 1, 72, 1, 1,
1, 1, 1, 1, 1, 1, 73, 1,
1, 1, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 74,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 75, 1,
80, 80, 80, 80, 80, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 80,
1, 1, 81, 1, 1, 1, 1, 1,
1, 1, 82, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 83,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 45, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 84, 1, 85, 85, 85,
85, 85, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 85, 1, 1, 86,
1, 1, 1, 1, 1, 1, 1, 87,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 88, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
89, 1, 85, 85, 85, 85, 85, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 85, 1, 1, 86, 1, 1, 1,
1, 1, 1, 1, 87, 1, 1, 1,
1, 34, 34, 34, 34, 34, 34, 34,
34, 34, 34, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 88, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 89, 1, 80,
80, 80, 80, 80, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 80, 1,
1, 81, 1, 1, 1, 1, 1, 1,
1, 82, 1, 1, 1, 1, 90, 90,
90, 90, 90, 90, 90, 90, 90, 90,
1, 1, 1, 1, 1, 1, 83, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 45, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 84, 1, 65, 65, 65, 65,
65, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 65, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 91, 91, 91, 91, 91,
91, 91, 91, 91, 91, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
66, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 67,
1, 0
};
static const char _deserialize_text_trans_targs[] = {
1, 0, 2, 26, 3, 4, 20, 5,
24, 25, 28, 39, 9, 31, 34, 31,
34, 11, 32, 33, 32, 33, 35, 38,
14, 15, 18, 15, 18, 16, 17, 36,
37, 36, 37, 27, 21, 20, 6, 22,
23, 21, 22, 23, 21, 22, 23, 25,
27, 27, 7, 8, 12, 13, 19, 22,
30, 27, 7, 8, 12, 13, 19, 22,
30, 29, 22, 30, 29, 30, 30, 29,
7, 10, 22, 30, 29, 7, 22, 30,
29, 7, 8, 13, 30, 29, 7, 8,
22, 30, 38, 39
};
static const char _deserialize_text_trans_actions[] = {
0, 0, 0, 0, 1, 0, 2, 0,
2, 2, 3, 3, 4, 3, 3, 5,
5, 4, 3, 3, 5, 5, 3, 3,
4, 4, 4, 0, 0, 6, 4, 3,
3, 5, 5, 5, 7, 8, 9, 7,
7, 0, 0, 0, 10, 10, 10, 8,
12, 13, 14, 14, 14, 14, 15, 11,
11, 17, 18, 18, 18, 18, 0, 16,
16, 19, 19, 19, 0, 0, 13, 20,
21, 21, 20, 20, 22, 23, 22, 22,
10, 24, 24, 24, 10, 25, 26, 26,
25, 25, 5, 5
};
static const char _deserialize_text_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0,
10, 10, 11, 16, 19, 0, 11, 20,
22, 22, 20, 10, 25, 25, 10, 19
};
static const int deserialize_text_start = 1;
static const int deserialize_text_first_final = 20;
static const int deserialize_text_error = 0;
static const int deserialize_text_en_main = 1;
#line 117 "hb-buffer-deserialize-text.rl"
static hb_bool_t
_hb_buffer_deserialize_text (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
const char *eof = pe, *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
#line 457 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
#line 460 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_text_trans_keys + (cs<<1);
_inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs];
_slen = _deserialize_text_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_text_trans_targs[_trans];
if ( _deserialize_text_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_text_trans_actions[_trans] ) {
case 1:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
break;
case 4:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 5:
#line 55 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
break;
case 8:
#line 56 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_unicode ())) return false; }
break;
case 18:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 9:
#line 66 "hb-buffer-deserialize-text.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
break;
case 24:
#line 68 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 6:
#line 69 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 26:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 21:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 23:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
break;
case 15:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 3:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 55 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
break;
case 2:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 56 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_unicode ())) return false; }
break;
case 16:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 7:
#line 66 "hb-buffer-deserialize-text.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 10:
#line 68 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 25:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 20:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 22:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 19:
#line 73 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.mask )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 12:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 55 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
break;
case 14:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 17:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 55 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 13:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 55 "hb-buffer-deserialize-text.rl"
{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 715 "hb-buffer-deserialize-text.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
switch ( _deserialize_text_eof_actions[cs] ) {
case 16:
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 7:
#line 66 "hb-buffer-deserialize-text.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 10:
#line 68 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 25:
#line 70 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 20:
#line 71 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 22:
#line 72 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 19:
#line 73 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.mask )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 38 "hb-buffer-deserialize-text.rl"
{
hb_memset (&info, 0, sizeof (info));
hb_memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
#line 58 "hb-buffer-deserialize-text.rl"
{
/* TODO Unescape delimiters. */
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 825 "hb-buffer-deserialize-text.hh"
}
}
_out: {}
}
#line 141 "hb-buffer-deserialize-text.rl"
*end_ptr = p;
return p == pe && *(p-1) != ']';
}
#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */

View file

@ -721,7 +721,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
} }
#include "hb-buffer-deserialize-json.hh" #include "hb-buffer-deserialize-json.hh"
#include "hb-buffer-deserialize-text.hh" #include "hb-buffer-deserialize-text-glyphs.hh"
#include "hb-buffer-deserialize-text-unicode.hh"
/** /**
* hb_buffer_deserialize_glyphs: * hb_buffer_deserialize_glyphs:
@ -736,7 +737,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
* Deserializes glyphs @buffer from textual representation in the format * Deserializes glyphs @buffer from textual representation in the format
* produced by hb_buffer_serialize_glyphs(). * produced by hb_buffer_serialize_glyphs().
* *
* Return value: `true` if @buf is not fully consumed, `false` otherwise. * Return value: `true` if parse was successful, `false` if an error
* occurred.
* *
* Since: 0.9.7 * Since: 0.9.7
**/ **/
@ -779,7 +781,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
switch (format) switch (format)
{ {
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_deserialize_text (buffer, return _hb_buffer_deserialize_text_glyphs (buffer,
buf, buf_len, end_ptr, buf, buf_len, end_ptr,
font); font);
@ -808,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
* Deserializes Unicode @buffer from textual representation in the format * Deserializes Unicode @buffer from textual representation in the format
* produced by hb_buffer_serialize_unicode(). * produced by hb_buffer_serialize_unicode().
* *
* Return value: `true` if @buf is not fully consumed, `false` otherwise. * Return value: `true` if parse was successful, `false` if an error
* occurred.
* *
* Since: 2.7.3 * Since: 2.7.3
**/ **/
@ -849,7 +852,7 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
switch (format) switch (format)
{ {
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_deserialize_text (buffer, return _hb_buffer_deserialize_text_unicode (buffer,
buf, buf_len, end_ptr, buf, buf_len, end_ptr,
font); font);

View file

@ -150,7 +150,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
assert (text_start < text_end); assert (text_start < text_end);
if (0) if (0)
printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
hb_buffer_clear_contents (fragment); hb_buffer_clear_contents (fragment);
@ -292,7 +292,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
assert (text_start < text_end); assert (text_start < text_end);
if (0) if (0)
printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
#if 0 #if 0
hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);

View file

@ -522,15 +522,17 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
cluster = hb_min (cluster, info[i].cluster); cluster = hb_min (cluster, info[i].cluster);
/* Extend end */ /* Extend end */
if (cluster != info[end - 1].cluster)
while (end < len && info[end - 1].cluster == info[end].cluster) while (end < len && info[end - 1].cluster == info[end].cluster)
end++; end++;
/* Extend start */ /* Extend start */
if (cluster != info[start].cluster)
while (idx < start && info[start - 1].cluster == info[start].cluster) while (idx < start && info[start - 1].cluster == info[start].cluster)
start--; start--;
/* If we hit the start of buffer, continue in out-buffer. */ /* If we hit the start of buffer, continue in out-buffer. */
if (idx == start) if (idx == start && info[start].cluster != cluster)
for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
set_cluster (out_info[i - 1], cluster); set_cluster (out_info[i - 1], cluster);
@ -893,6 +895,32 @@ hb_buffer_get_user_data (const hb_buffer_t *buffer,
* Sets the type of @buffer contents. Buffers are either empty, contain * Sets the type of @buffer contents. Buffers are either empty, contain
* characters (before shaping), or contain glyphs (the result of shaping). * characters (before shaping), or contain glyphs (the result of shaping).
* *
* You rarely need to call this function, since a number of other
* functions transition the content type for you. Namely:
*
* - A newly created buffer starts with content type
* %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(),
* hb_buffer_clear_contents(), as well as calling hb_buffer_set_length()
* with an argument of zero all set the buffer content type to invalid
* as well.
*
* - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(),
* hb_buffer_add_utf32(), hb_buffer_add_codepoints() and
* hb_buffer_add_latin1() expect that buffer is either empty and
* have a content type of invalid, or that buffer content type is
* %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content
* type to Unicode if they added anything to an empty buffer.
*
* - Finally hb_shape() and hb_shape_full() expect that the buffer
* is either empty and have content type of invalid, or that buffer
* content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon
* success they set the buffer content type to
* %HB_BUFFER_CONTENT_TYPE_GLYPHS.
*
* The above transitions are designed such that one can use a buffer
* in a loop of "reset : add-text : shape" without needing to ever
* modify the content type manually.
*
* Since: 0.9.5 * Since: 0.9.5
**/ **/
void void

View file

@ -763,7 +763,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
/* /*
* Debugging. * Tracing.
*/ */
/** /**

View file

@ -35,26 +35,6 @@
#include "hb-set-digest.hh" #include "hb-set-digest.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
#define HB_BUFFER_MAX_LEN_FACTOR 64
#endif
#ifndef HB_BUFFER_MAX_LEN_MIN
#define HB_BUFFER_MAX_LEN_MIN 16384
#endif
#ifndef HB_BUFFER_MAX_LEN_DEFAULT
#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
#endif
#ifndef HB_BUFFER_MAX_OPS_FACTOR
#define HB_BUFFER_MAX_OPS_FACTOR 1024
#endif
#ifndef HB_BUFFER_MAX_OPS_MIN
#define HB_BUFFER_MAX_OPS_MIN 16384
#endif
#ifndef HB_BUFFER_MAX_OPS_DEFAULT
#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
#endif
static_assert ((sizeof (hb_glyph_info_t) == 20), ""); static_assert ((sizeof (hb_glyph_info_t) == 20), "");
static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), ""); static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
@ -600,6 +580,15 @@ struct hb_buffer_t
unsigned int start, unsigned int end, unsigned int start, unsigned int end,
unsigned int cluster, unsigned int cluster,
hb_mask_t mask) hb_mask_t mask)
{
if (unlikely (start == end))
return;
unsigned cluster_first = infos[start].cluster;
unsigned cluster_last = infos[end - 1].cluster;
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS ||
(cluster != cluster_first && cluster != cluster_last))
{ {
for (unsigned int i = start; i < end; i++) for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster) if (cluster != infos[i].cluster)
@ -607,17 +596,46 @@ struct hb_buffer_t
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask; infos[i].mask |= mask;
} }
return;
} }
static unsigned
/* Monotone clusters */
if (cluster == cluster_first)
{
for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i - 1].mask |= mask;
}
}
else /* cluster == cluster_last */
{
for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask;
}
}
}
unsigned
_infos_find_min_cluster (const hb_glyph_info_t *infos, _infos_find_min_cluster (const hb_glyph_info_t *infos,
unsigned start, unsigned end, unsigned start, unsigned end,
unsigned cluster = UINT_MAX) unsigned cluster = UINT_MAX)
{
if (unlikely (start == end))
return cluster;
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{ {
for (unsigned int i = start; i < end; i++) for (unsigned int i = start; i < end; i++)
cluster = hb_min (cluster, infos[i].cluster); cluster = hb_min (cluster, infos[i].cluster);
return cluster; return cluster;
} }
return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster));
}
void clear_glyph_flags (hb_mask_t mask = 0) void clear_glyph_flags (hb_mask_t mask = 0)
{ {
for (unsigned int i = 0; i < len; i++) for (unsigned int i = 0; i < len; i++)

View file

@ -39,7 +39,9 @@ template <unsigned int key_bits=16,
struct hb_cache_t struct hb_cache_t
{ {
using item_t = typename std::conditional<thread_safe, using item_t = typename std::conditional<thread_safe,
hb_atomic_int_t, typename std::conditional<key_bits + value_bits - cache_bits <= 16,
hb_atomic_short_t,
hb_atomic_int_t>::type,
typename std::conditional<key_bits + value_bits - cache_bits <= 16, typename std::conditional<key_bits + value_bits - cache_bits <= 16,
short, short,
int>::type int>::type
@ -48,8 +50,9 @@ struct hb_cache_t
static_assert ((key_bits >= cache_bits), ""); static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
hb_cache_t () { init (); }
void init () { clear (); } void init () { clear (); }
void fini () {}
void clear () void clear ()
{ {

View file

@ -0,0 +1,869 @@
/*
* Copyright © 2022 Red Hat, 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): Matthias Clasen
*/
#include "hb.hh"
#ifdef HAVE_CAIRO
#include "hb-cairo-utils.hh"
#include <cairo.h>
#define PREALLOCATED_COLOR_STOPS 16
#define _2_M_PIf (2.f * float (M_PI))
typedef struct {
float r, g, b, a;
} hb_cairo_color_t;
static inline cairo_extend_t
hb_cairo_extend (hb_paint_extend_t extend)
{
switch (extend)
{
case HB_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD;
case HB_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT;
case HB_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT;
default: break;
}
return CAIRO_EXTEND_PAD;
}
#ifdef CAIRO_HAS_PNG_FUNCTIONS
typedef struct
{
hb_blob_t *blob;
unsigned int offset;
} hb_cairo_read_blob_data_t;
static cairo_status_t
hb_cairo_read_blob (void *closure,
unsigned char *data,
unsigned int length)
{
hb_cairo_read_blob_data_t *r = (hb_cairo_read_blob_data_t *) closure;
const char *d;
unsigned int size;
d = hb_blob_get_data (r->blob, &size);
if (r->offset + length > size)
return CAIRO_STATUS_READ_ERROR;
memcpy (data, d + r->offset, length);
r->offset += length;
return CAIRO_STATUS_SUCCESS;
}
#endif
static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0};
static void
_hb_cairo_destroy_blob (void *p)
{
hb_blob_destroy ((hb_blob_t *) p);
}
hb_bool_t
_hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
hb_blob_t *blob,
unsigned width,
unsigned height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents)
{
cairo_t *cr = c->cr;
if (!extents) /* SVG currently. */
return false;
cairo_surface_t *surface = nullptr;
#ifdef CAIRO_HAS_PNG_FUNCTIONS
if (format == HB_PAINT_IMAGE_FORMAT_PNG)
{
hb_cairo_read_blob_data_t r;
r.blob = blob;
r.offset = 0;
surface = cairo_image_surface_create_from_png_stream (hb_cairo_read_blob, &r);
/* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
* Just pull them out of the surface. */
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_width (surface);
}
else
#endif
if (format == HB_PAINT_IMAGE_FORMAT_BGRA)
{
/* Byte-endian conversion. */
unsigned data_size = hb_blob_get_length (blob);
if (data_size < width * height * 4)
return false;
unsigned char *data;
#ifdef __BYTE_ORDER
if (__BYTE_ORDER == __BIG_ENDIAN)
{
data = (unsigned char *) hb_blob_get_data_writable (blob, nullptr);
if (!data)
return false;
unsigned count = width * height * 4;
for (unsigned i = 0; i < count; i += 4)
{
unsigned char b;
b = data[i];
data[i] = data[i+3];
data[i+3] = b;
b = data[i+1];
data[i+1] = data[i+2];
data[i+2] = b;
}
}
else
#endif
data = (unsigned char *) hb_blob_get_data (blob, nullptr);
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
width, height,
width * 4);
cairo_surface_set_user_data (surface,
_hb_cairo_surface_blob_user_data_key,
hb_blob_reference (blob),
_hb_cairo_destroy_blob);
}
if (!surface)
return false;
cairo_save (cr);
/* this clip is here to work around recording surface limitations */
cairo_rectangle (cr,
extents->x_bearing,
extents->y_bearing,
extents->width,
extents->height);
cairo_clip (cr);
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
cairo_pattern_set_matrix (pattern, &matrix);
/* Undo slant in the extents and apply it in the context. */
extents->width -= extents->height * slant;
extents->x_bearing -= extents->y_bearing * slant;
cairo_matrix_t cairo_matrix = {1., 0., (double) slant, 1., 0., 0.};
cairo_transform (cr, &cairo_matrix);
cairo_translate (cr, extents->x_bearing, extents->y_bearing);
cairo_scale (cr, extents->width, extents->height);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
cairo_restore (cr);
return true;
}
static void
_hb_cairo_reduce_anchors (float x0, float y0,
float x1, float y1,
float x2, float y2,
float *xx0, float *yy0,
float *xx1, float *yy1)
{
float q1x, q1y, q2x, q2y;
float s;
float k;
q2x = x2 - x0;
q2y = y2 - y0;
q1x = x1 - x0;
q1y = y1 - y0;
s = q2x * q2x + q2y * q2y;
if (s < 0.000001f)
{
*xx0 = x0; *yy0 = y0;
*xx1 = x1; *yy1 = y1;
return;
}
k = (q2x * q1x + q2y * q1y) / s;
*xx0 = x0;
*yy0 = y0;
*xx1 = x1 - k * q2x;
*yy1 = y1 - k * q2y;
}
static int
_hb_cairo_cmp_color_stop (const void *p1,
const void *p2)
{
const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1;
const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2;
if (c1->offset < c2->offset)
return -1;
else if (c1->offset > c2->offset)
return 1;
else
return 0;
}
static void
_hb_cairo_normalize_color_line (hb_color_stop_t *stops,
unsigned int len,
float *omin,
float *omax)
{
float min, max;
hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop);
min = max = stops[0].offset;
for (unsigned int i = 0; i < len; i++)
{
min = hb_min (min, stops[i].offset);
max = hb_max (max, stops[i].offset);
}
if (min != max)
{
for (unsigned int i = 0; i < len; i++)
stops[i].offset = (stops[i].offset - min) / (max - min);
}
*omin = min;
*omax = max;
}
static bool
_hb_cairo_get_color_stops (hb_cairo_context_t *c,
hb_color_line_t *color_line,
unsigned *count,
hb_color_stop_t **stops)
{
unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr);
if (len > *count)
{
*stops = (hb_color_stop_t *) hb_malloc (len * sizeof (hb_color_stop_t));
if (unlikely (!stops))
return false;
}
hb_color_line_get_color_stops (color_line, 0, &len, *stops);
for (unsigned i = 0; i < len; i++)
if ((*stops)[i].is_foreground)
{
#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
double r, g, b, a;
cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
(*stops)[i].color = HB_COLOR (round (b * 255.), round (g * 255.), round (r * 255.),
round (a * hb_color_get_alpha ((*stops)[i].color)));
else
#endif
(*stops)[i].color = HB_COLOR (0, 0, 0, hb_color_get_alpha ((*stops)[i].color));
}
*count = len;
return true;
}
void
_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2)
{
cairo_t *cr = c->cr;
unsigned int len = PREALLOCATED_COLOR_STOPS;
hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
hb_color_stop_t *stops = stops_;
float xx0, yy0, xx1, yy1;
float xxx0, yyy0, xxx1, yyy1;
float min, max;
cairo_pattern_t *pattern;
if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
return;
_hb_cairo_normalize_color_line (stops, len, &min, &max);
_hb_cairo_reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1);
xxx0 = xx0 + min * (xx1 - xx0);
yyy0 = yy0 + min * (yy1 - yy0);
xxx1 = xx0 + max * (xx1 - xx0);
yyy1 = yy0 + max * (yy1 - yy0);
pattern = cairo_pattern_create_linear ((double) xxx0, (double) yyy0, (double) xxx1, (double) yyy1);
cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line)));
for (unsigned int i = 0; i < len; i++)
{
double r, g, b, a;
r = hb_color_get_red (stops[i].color) / 255.;
g = hb_color_get_green (stops[i].color) / 255.;
b = hb_color_get_blue (stops[i].color) / 255.;
a = hb_color_get_alpha (stops[i].color) / 255.;
cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a);
}
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
if (stops != stops_)
hb_free (stops);
}
void
_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1)
{
cairo_t *cr = c->cr;
unsigned int len = PREALLOCATED_COLOR_STOPS;
hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
hb_color_stop_t *stops = stops_;
float min, max;
float xx0, yy0, xx1, yy1;
float rr0, rr1;
cairo_pattern_t *pattern;
if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
return;
_hb_cairo_normalize_color_line (stops, len, &min, &max);
xx0 = x0 + min * (x1 - x0);
yy0 = y0 + min * (y1 - y0);
xx1 = x0 + max * (x1 - x0);
yy1 = y0 + max * (y1 - y0);
rr0 = r0 + min * (r1 - r0);
rr1 = r0 + max * (r1 - r0);
pattern = cairo_pattern_create_radial ((double) xx0, (double) yy0, (double) rr0, (double) xx1, (double) yy1, (double) rr1);
cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line)));
for (unsigned int i = 0; i < len; i++)
{
double r, g, b, a;
r = hb_color_get_red (stops[i].color) / 255.;
g = hb_color_get_green (stops[i].color) / 255.;
b = hb_color_get_blue (stops[i].color) / 255.;
a = hb_color_get_alpha (stops[i].color) / 255.;
cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a);
}
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
if (stops != stops_)
hb_free (stops);
}
typedef struct {
float x, y;
} hb_cairo_point_t;
static inline float
_hb_cairo_interpolate (float f0, float f1, float f)
{
return f0 + f * (f1 - f0);
}
static inline void
_hb_cairo_premultiply (hb_cairo_color_t *c)
{
c->r *= c->a;
c->g *= c->a;
c->b *= c->a;
}
static inline void
_hb_cairo_unpremultiply (hb_cairo_color_t *c)
{
if (c->a != 0.f)
{
c->r /= c->a;
c->g /= c->a;
c->b /= c->a;
}
}
static void
_hb_cairo_interpolate_colors (hb_cairo_color_t *c0, hb_cairo_color_t *c1, float k, hb_cairo_color_t *c)
{
// According to the COLR specification, gradients
// should be interpolated in premultiplied form
_hb_cairo_premultiply (c0);
_hb_cairo_premultiply (c1);
c->r = c0->r + k * (c1->r - c0->r);
c->g = c0->g + k * (c1->g - c0->g);
c->b = c0->b + k * (c1->b - c0->b);
c->a = c0->a + k * (c1->a - c0->a);
_hb_cairo_unpremultiply (c);
}
static inline float
_hb_cairo_dot (hb_cairo_point_t p, hb_cairo_point_t q)
{
return p.x * q.x + p.y * q.y;
}
static inline hb_cairo_point_t
_hb_cairo_normalize (hb_cairo_point_t p)
{
float len = sqrtf (_hb_cairo_dot (p, p));
return hb_cairo_point_t { p.x / len, p.y / len };
}
static inline hb_cairo_point_t
_hb_cairo_sum (hb_cairo_point_t p, hb_cairo_point_t q)
{
return hb_cairo_point_t { p.x + q.x, p.y + q.y };
}
static inline hb_cairo_point_t
_hb_cairo_difference (hb_cairo_point_t p, hb_cairo_point_t q)
{
return hb_cairo_point_t { p.x - q.x, p.y - q.y };
}
static inline hb_cairo_point_t
_hb_cairo_scale (hb_cairo_point_t p, float f)
{
return hb_cairo_point_t { p.x * f, p.y * f };
}
typedef struct {
hb_cairo_point_t center, p0, c0, c1, p1;
hb_cairo_color_t color0, color1;
} hb_cairo_patch_t;
static void
_hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cairo_patch_t *p)
{
cairo_mesh_pattern_begin_patch (pattern);
cairo_mesh_pattern_move_to (pattern, (double) center->x, (double) center->y);
cairo_mesh_pattern_line_to (pattern, (double) p->p0.x, (double) p->p0.y);
cairo_mesh_pattern_curve_to (pattern,
(double) p->c0.x, (double) p->c0.y,
(double) p->c1.x, (double) p->c1.y,
(double) p->p1.x, (double) p->p1.y);
cairo_mesh_pattern_line_to (pattern, (double) center->x, (double) center->y);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0,
(double) p->color0.r,
(double) p->color0.g,
(double) p->color0.b,
(double) p->color0.a);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1,
(double) p->color0.r,
(double) p->color0.g,
(double) p->color0.b,
(double) p->color0.a);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2,
(double) p->color1.r,
(double) p->color1.g,
(double) p->color1.b,
(double) p->color1.a);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3,
(double) p->color1.r,
(double) p->color1.g,
(double) p->color1.b,
(double) p->color1.a);
cairo_mesh_pattern_end_patch (pattern);
}
#define MAX_ANGLE ((float) M_PI / 8.f)
static void
_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius,
float a0, hb_cairo_color_t *c0,
float a1, hb_cairo_color_t *c1,
cairo_pattern_t *pattern)
{
hb_cairo_point_t center = hb_cairo_point_t { cx, cy };
int num_splits;
hb_cairo_point_t p0;
hb_cairo_color_t color0, color1;
num_splits = ceilf (fabsf (a1 - a0) / MAX_ANGLE);
p0 = hb_cairo_point_t { cosf (a0), sinf (a0) };
color0 = *c0;
for (int a = 0; a < num_splits; a++)
{
float k = (a + 1.) / num_splits;
float angle1;
hb_cairo_point_t p1;
hb_cairo_point_t A, U;
hb_cairo_point_t C0, C1;
hb_cairo_patch_t patch;
angle1 = _hb_cairo_interpolate (a0, a1, k);
_hb_cairo_interpolate_colors (c0, c1, k, &color1);
patch.color0 = color0;
patch.color1 = color1;
p1 = hb_cairo_point_t { cosf (angle1), sinf (angle1) };
patch.p0 = _hb_cairo_sum (center, _hb_cairo_scale (p0, radius));
patch.p1 = _hb_cairo_sum (center, _hb_cairo_scale (p1, radius));
A = _hb_cairo_normalize (_hb_cairo_sum (p0, p1));
U = hb_cairo_point_t { -A.y, A.x };
C0 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p0, A), p0) / _hb_cairo_dot (U, p0)));
C1 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p1, A), p1) / _hb_cairo_dot (U, p1)));
patch.c0 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C0, _hb_cairo_scale (_hb_cairo_difference (C0, p0), 0.33333f)), radius));
patch.c1 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C1, _hb_cairo_scale (_hb_cairo_difference (C1, p1), 0.33333f)), radius));
_hb_cairo_add_patch (pattern, &center, &patch);
p0 = p1;
color0 = color1;
}
}
static void
_hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
unsigned int n_stops,
cairo_extend_t extend,
float cx, float cy,
float radius,
float start_angle,
float end_angle,
cairo_pattern_t *pattern)
{
float angles_[PREALLOCATED_COLOR_STOPS];
float *angles = angles_;
hb_cairo_color_t colors_[PREALLOCATED_COLOR_STOPS];
hb_cairo_color_t *colors = colors_;
hb_cairo_color_t color0, color1;
if (start_angle == end_angle)
{
if (extend == CAIRO_EXTEND_PAD)
{
hb_cairo_color_t c;
if (start_angle > 0)
{
c.r = hb_color_get_red (stops[0].color) / 255.;
c.g = hb_color_get_green (stops[0].color) / 255.;
c.b = hb_color_get_blue (stops[0].color) / 255.;
c.a = hb_color_get_alpha (stops[0].color) / 255.;
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
0., &c,
start_angle, &c,
pattern);
}
if (end_angle < _2_M_PIf)
{
c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.;
c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.;
c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.;
c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.;
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
end_angle, &c,
_2_M_PIf, &c,
pattern);
}
}
return;
}
assert (start_angle != end_angle);
/* handle directions */
if (end_angle < start_angle)
{
hb_swap (start_angle, end_angle);
for (unsigned i = 0; i < n_stops - 1 - i; i++)
hb_swap (stops[i], stops[n_stops - 1 - i]);
for (unsigned i = 0; i < n_stops; i++)
stops[i].offset = 1 - stops[i].offset;
}
if (n_stops > PREALLOCATED_COLOR_STOPS)
{
angles = (float *) hb_malloc (sizeof (float) * n_stops);
colors = (hb_cairo_color_t *) hb_malloc (sizeof (hb_cairo_color_t) * n_stops);
if (unlikely (!angles || !colors))
{
hb_free (angles);
hb_free (colors);
return;
}
}
for (unsigned i = 0; i < n_stops; i++)
{
angles[i] = start_angle + stops[i].offset * (end_angle - start_angle);
colors[i].r = hb_color_get_red (stops[i].color) / 255.;
colors[i].g = hb_color_get_green (stops[i].color) / 255.;
colors[i].b = hb_color_get_blue (stops[i].color) / 255.;
colors[i].a = hb_color_get_alpha (stops[i].color) / 255.;
}
if (extend == CAIRO_EXTEND_PAD)
{
unsigned pos;
color0 = colors[0];
for (pos = 0; pos < n_stops; pos++)
{
if (angles[pos] >= 0)
{
if (pos > 0)
{
float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
_hb_cairo_interpolate_colors (&colors[pos-1], &colors[pos], k, &color0);
}
break;
}
}
if (pos == n_stops)
{
/* everything is below 0 */
color0 = colors[n_stops-1];
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
0., &color0,
_2_M_PIf, &color0,
pattern);
goto done;
}
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
0., &color0,
angles[pos], &colors[pos],
pattern);
for (pos++; pos < n_stops; pos++)
{
if (angles[pos] <= _2_M_PIf)
{
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos-1],
angles[pos], &colors[pos],
pattern);
}
else
{
float k = (_2_M_PIf - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
_hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos - 1],
_2_M_PIf, &color1,
pattern);
break;
}
}
if (pos == n_stops)
{
/* everything is below 2*M_PI */
color0 = colors[n_stops - 1];
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[n_stops - 1], &color0,
_2_M_PIf, &color0,
pattern);
goto done;
}
}
else
{
int k;
float span;
span = angles[n_stops - 1] - angles[0];
k = 0;
if (angles[0] >= 0)
{
float ss = angles[0];
while (ss > 0)
{
if (span > 0)
{
ss -= span;
k--;
}
else
{
ss += span;
k++;
}
}
}
else if (angles[0] < 0)
{
float ee = angles[n_stops - 1];
while (ee < 0)
{
if (span > 0)
{
ee += span;
k++;
}
else
{
ee -= span;
k--;
}
}
}
//assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span);
span = fabs (span);
for (signed l = k; l < 1000; l++)
{
for (unsigned i = 1; i < n_stops; i++)
{
float a0, a1;
hb_cairo_color_t *c0, *c1;
if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT))
{
a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span;
a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span;
c0 = &colors[n_stops - 1 - (i - 1)];
c1 = &colors[n_stops - 1 - i];
}
else
{
a0 = angles[i-1] + l * span;
a1 = angles[i] + l * span;
c0 = &colors[i-1];
c1 = &colors[i];
}
if (a1 < 0)
continue;
if (a0 < 0)
{
hb_cairo_color_t color;
float f = (0 - a0)/(a1 - a0);
_hb_cairo_interpolate_colors (c0, c1, f, &color);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
0, &color,
a1, c1,
pattern);
}
else if (a1 >= _2_M_PIf)
{
hb_cairo_color_t color;
float f = (_2_M_PIf - a0)/(a1 - a0);
_hb_cairo_interpolate_colors (c0, c1, f, &color);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
a0, c0,
_2_M_PIf, &color,
pattern);
goto done;
}
else
{
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
a0, c0,
a1, c1,
pattern);
}
}
}
}
done:
if (angles != angles_)
hb_free (angles);
if (colors != colors_)
hb_free (colors);
}
void
_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c,
hb_color_line_t *color_line,
float cx, float cy,
float start_angle,
float end_angle)
{
cairo_t *cr = c->cr;
unsigned int len = PREALLOCATED_COLOR_STOPS;
hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
hb_color_stop_t *stops = stops_;
cairo_extend_t extend;
double x1, y1, x2, y2;
float max_x, max_y, radius;
cairo_pattern_t *pattern;
if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
return;
hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop);
cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
max_x = (float) hb_max ((x1 - (double) cx) * (x1 - (double) cx), (x2 - (double) cx) * (x2 - (double) cx));
max_y = (float) hb_max ((y1 - (double) cy) * (y1 - (double) cy), (y2 - (double) cy) * (y2 - (double) cy));
radius = sqrtf (max_x + max_y);
extend = hb_cairo_extend (hb_color_line_get_extend (color_line));
pattern = cairo_pattern_create_mesh ();
_hb_cairo_add_sweep_gradient_patches (stops, len, extend, cx, cy,
radius, start_angle, end_angle, pattern);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
if (stops != stops_)
hb_free (stops);
}
#endif

View file

@ -0,0 +1,107 @@
/*
* Copyright © 2022 Red Hat, 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): Matthias Clasen
*/
#ifndef HB_CAIRO_UTILS_H
#define HB_CAIRO_UTILS_H
#include "hb.hh"
#include "hb-cairo.h"
typedef struct
{
cairo_scaled_font_t *scaled_font;
cairo_t *cr;
hb_map_t *color_cache;
} hb_cairo_context_t;
static inline cairo_operator_t
_hb_paint_composite_mode_to_cairo (hb_paint_composite_mode_t mode)
{
switch (mode)
{
case HB_PAINT_COMPOSITE_MODE_CLEAR: return CAIRO_OPERATOR_CLEAR;
case HB_PAINT_COMPOSITE_MODE_SRC: return CAIRO_OPERATOR_SOURCE;
case HB_PAINT_COMPOSITE_MODE_DEST: return CAIRO_OPERATOR_DEST;
case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return CAIRO_OPERATOR_OVER;
case HB_PAINT_COMPOSITE_MODE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER;
case HB_PAINT_COMPOSITE_MODE_SRC_IN: return CAIRO_OPERATOR_IN;
case HB_PAINT_COMPOSITE_MODE_DEST_IN: return CAIRO_OPERATOR_DEST_IN;
case HB_PAINT_COMPOSITE_MODE_SRC_OUT: return CAIRO_OPERATOR_OUT;
case HB_PAINT_COMPOSITE_MODE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT;
case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: return CAIRO_OPERATOR_ATOP;
case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP;
case HB_PAINT_COMPOSITE_MODE_XOR: return CAIRO_OPERATOR_XOR;
case HB_PAINT_COMPOSITE_MODE_PLUS: return CAIRO_OPERATOR_ADD;
case HB_PAINT_COMPOSITE_MODE_SCREEN: return CAIRO_OPERATOR_SCREEN;
case HB_PAINT_COMPOSITE_MODE_OVERLAY: return CAIRO_OPERATOR_OVERLAY;
case HB_PAINT_COMPOSITE_MODE_DARKEN: return CAIRO_OPERATOR_DARKEN;
case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN;
case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE;
case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN;
case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT;
case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT;
case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE;
case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION;
case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY;
case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE;
case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION;
case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR;
case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY;
default: return CAIRO_OPERATOR_CLEAR;
}
}
HB_INTERNAL hb_bool_t
_hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
hb_blob_t *blob,
unsigned width,
unsigned height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents);
HB_INTERNAL void
_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2);
HB_INTERNAL void
_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1);
HB_INTERNAL void
_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c,
hb_color_line_t *color_line,
float x0, float y0,
float start_angle, float end_angle);
#endif /* HB_CAIRO_UTILS_H */

1010
thirdparty/harfbuzz/src/hb-cairo.cc vendored Normal file

File diff suppressed because it is too large Load diff

99
thirdparty/harfbuzz/src/hb-cairo.h vendored Normal file
View file

@ -0,0 +1,99 @@
/*
* Copyright © 2022 Red Hat, 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.
*
* Red Hat Author(s): Matthias Clasen
*/
#ifndef HB_CAIRO_H
#define HB_CAIRO_H
#include "hb.h"
#include <cairo.h>
HB_BEGIN_DECLS
HB_EXTERN cairo_font_face_t *
hb_cairo_font_face_create_for_font (hb_font_t *font);
HB_EXTERN hb_font_t *
hb_cairo_font_face_get_font (cairo_font_face_t *font_face);
HB_EXTERN cairo_font_face_t *
hb_cairo_font_face_create_for_face (hb_face_t *face);
HB_EXTERN hb_face_t *
hb_cairo_font_face_get_face (cairo_font_face_t *font_face);
/**
* hb_cairo_font_init_func_t:
* @font: The #hb_font_t being created
* @scaled_font: The respective #cairo_scaled_font_t
* @user_data: User data accompanying this method
*
* The type of a virtual method to be called when a cairo
* face created using hb_cairo_font_face_create_for_face()
* creates an #hb_font_t for a #cairo_scaled_font_t.
*
* Return value: the #hb_font_t value to use; in most cases same as @font
*
* Since: 7.0.0
*/
typedef hb_font_t * (*hb_cairo_font_init_func_t) (hb_font_t *font,
cairo_scaled_font_t *scaled_font,
void *user_data);
HB_EXTERN void
hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
hb_cairo_font_init_func_t func,
void *user_data,
hb_destroy_func_t destroy);
HB_EXTERN hb_font_t *
hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font);
HB_EXTERN void
hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
unsigned int scale_factor);
HB_EXTERN unsigned int
hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face);
HB_EXTERN void
hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
hb_bool_t utf8_clusters,
double x_scale_factor,
double y_scale_factor,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
unsigned int *num_glyphs,
cairo_text_cluster_t **clusters,
unsigned int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags);
HB_END_DECLS
#endif /* HB_CAIRO_H */

View file

@ -488,7 +488,7 @@ struct op_str_t
const unsigned char *ptr = nullptr; const unsigned char *ptr = nullptr;
op_code_t op; op_code_t op = OpCode_Invalid;
uint8_t length = 0; uint8_t length = 0;
}; };
@ -522,20 +522,10 @@ struct parsed_values_t
void alloc (unsigned n) void alloc (unsigned n)
{ {
values.alloc (n); values.alloc (n, true);
} }
void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ())
{
VAL *val = values.push ();
val->op = op;
auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
val->ptr = arr.arrayZ;
val->length = arr.length;
opStart = str_ref.get_offset ();
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
{ {
VAL *val = values.push (v); VAL *val = values.push (v);
val->op = op; val->op = op;

View file

@ -57,7 +57,6 @@ struct call_context_t
/* call stack */ /* call stack */
const unsigned int kMaxCallLimit = 10; const unsigned int kMaxCallLimit = 10;
const unsigned int kMaxOps = 10000;
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {}; struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
template <typename SUBRS> template <typename SUBRS>
@ -882,7 +881,7 @@ struct cs_interpreter_t : interpreter_t<ENV>
{ {
SUPER::env.set_endchar (false); SUPER::env.set_endchar (false);
unsigned max_ops = kMaxOps; unsigned max_ops = HB_CFF_MAX_OPS;
for (;;) { for (;;) {
if (unlikely (!--max_ops)) if (unlikely (!--max_ops))
{ {

View file

@ -35,10 +35,8 @@ using namespace OT;
/* an opstr and the parsed out dict value(s) */ /* an opstr and the parsed out dict value(s) */
struct dict_val_t : op_str_t struct dict_val_t : op_str_t
{ {
void init () { single_val.set_int (0); } void init () {}
void fini () {} void fini () {}
number_t single_val;
}; };
typedef dict_val_t num_dict_val_t; typedef dict_val_t num_dict_val_t;

View file

@ -38,7 +38,8 @@ typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t;
struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs> struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
{ {
template <typename ACC> template <typename ACC>
cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
{ {
processed_width = false; processed_width = false;

View file

@ -45,7 +45,7 @@ struct blend_arg_t : number_t
numValues = numValues_; numValues = numValues_;
valueIndex = valueIndex_; valueIndex = valueIndex_;
unsigned numBlends = blends_.length; unsigned numBlends = blends_.length;
if (unlikely (!deltas.resize (numBlends))) if (unlikely (!deltas.resize_exact (numBlends)))
return; return;
for (unsigned int i = 0; i < numBlends; i++) for (unsigned int i = 0; i < numBlends; i++)
deltas.arrayZ[i] = blends_.arrayZ[i]; deltas.arrayZ[i] = blends_.arrayZ[i];
@ -55,7 +55,7 @@ struct blend_arg_t : number_t
void reset_blends () void reset_blends ()
{ {
numValues = valueIndex = 0; numValues = valueIndex = 0;
deltas.resize (0); deltas.shrink (0);
} }
unsigned int numValues; unsigned int numValues;
@ -118,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
region_count = varStore->varStore.get_region_index_count (get_ivs ()); region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend) if (do_blend)
{ {
if (unlikely (!scalars.resize (region_count))) if (unlikely (!scalars.resize_exact (region_count)))
SUPER::set_error (); SUPER::set_error ();
else else
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
@ -163,6 +163,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
return v; return v;
} }
bool have_coords () const { return num_coords; }
protected: protected:
const int *coords; const int *coords;
unsigned int num_coords; unsigned int num_coords;
@ -222,6 +224,9 @@ struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PAR
const hb_array_t<const ELEM> blends, const hb_array_t<const ELEM> blends,
unsigned n, unsigned i) unsigned n, unsigned i)
{ {
if (env.have_coords ())
arg.set_int (round (arg.to_real () + env.blend_deltas (blends)));
else
arg.set_blends (n, i, blends); arg.set_blends (n, i, blends);
} }
template <typename T = ELEM, template <typename T = ELEM,

View file

@ -29,32 +29,6 @@
#include "hb.hh" #include "hb.hh"
#include "hb-machinery.hh" #include "hb-machinery.hh"
#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
#define HB_NO_SETLOCALE 1
#endif
#ifndef HB_NO_SETLOCALE
#include <locale.h>
#ifdef HAVE_XLOCALE_H
#include <xlocale.h> // Needed on BSD/OS X for uselocale
#endif
#ifdef WIN32
#define hb_locale_t _locale_t
#else
#define hb_locale_t locale_t
#endif
#define hb_setlocale setlocale
#define hb_uselocale uselocale
#else
#define hb_locale_t void *
#define hb_setlocale(Category, Locale) "C"
#define hb_uselocale(Locale) ((hb_locale_t) 0)
#endif
/** /**
* SECTION:hb-common * SECTION:hb-common

View file

@ -897,6 +897,32 @@ HB_EXTERN uint8_t
hb_color_get_blue (hb_color_t color); hb_color_get_blue (hb_color_t color);
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF) #define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
/**
* hb_glyph_extents_t:
* @x_bearing: Distance from the x-origin to the left extremum of the glyph.
* @y_bearing: Distance from the top extremum of the glyph to the y-origin.
* @width: Distance from the left extremum of the glyph to the right extremum.
* @height: Distance from the top extremum of the glyph to the bottom extremum.
*
* Glyph extent values, measured in font units.
*
* Note that @height is negative, in coordinate systems that grow up.
**/
typedef struct hb_glyph_extents_t {
hb_position_t x_bearing;
hb_position_t y_bearing;
hb_position_t width;
hb_position_t height;
} hb_glyph_extents_t;
/**
* hb_font_t:
*
* Data type for holding fonts.
*
*/
typedef struct hb_font_t hb_font_t;
HB_END_DECLS HB_END_DECLS
#endif /* HB_COMMON_H */ #endif /* HB_COMMON_H */

View file

@ -37,6 +37,7 @@
#ifndef HB_EXPERIMENTAL_API #ifndef HB_EXPERIMENTAL_API
#define HB_NO_BEYOND_64K #define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES #define HB_NO_VAR_COMPOSITES
#endif #endif
@ -80,9 +81,10 @@
#define HB_NO_MMAP #define HB_NO_MMAP
#define HB_NO_NAME #define HB_NO_NAME
#define HB_NO_OPEN #define HB_NO_OPEN
#define HB_NO_SETLOCALE
#define HB_NO_OT_FONT_GLYPH_NAMES #define HB_NO_OT_FONT_GLYPH_NAMES
#define HB_NO_OT_SHAPE_FRACTIONS #define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_PAINT
#define HB_NO_SETLOCALE
#define HB_NO_STYLE #define HB_NO_STYLE
#define HB_NO_SUBSET_LAYOUT #define HB_NO_SUBSET_LAYOUT
#define HB_NO_VERTICAL #define HB_NO_VERTICAL
@ -134,6 +136,10 @@
#define HB_NO_SUBSET_CFF #define HB_NO_SUBSET_CFF
#endif #endif
#ifdef HB_NO_DRAW
#define HB_NO_OUTLINE
#endif
#ifdef HB_NO_GETENV #ifdef HB_NO_GETENV
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE #define HB_NO_UNISCRIBE_BUG_COMPATIBLE
#endif #endif

View file

@ -511,7 +511,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
buffer->merge_clusters (i - 1, i + 1); buffer->merge_clusters (i - 1, i + 1);
} }
hb_vector_t<feature_record_t> feature_records;
hb_vector_t<range_record_t> range_records; hb_vector_t<range_record_t> range_records;
/* /*

View file

@ -160,6 +160,8 @@ HB_DEFINE_VTABLE (map);
HB_DEFINE_VTABLE (set); HB_DEFINE_VTABLE (set);
HB_DEFINE_VTABLE (shape_plan); HB_DEFINE_VTABLE (shape_plan);
HB_DEFINE_VTABLE (unicode_funcs); HB_DEFINE_VTABLE (unicode_funcs);
HB_DEFINE_VTABLE (draw_funcs);
HB_DEFINE_VTABLE (paint_funcs);
#undef HB_DEFINE_VTABLE #undef HB_DEFINE_VTABLE

View file

@ -113,7 +113,7 @@ _hb_print_func (const char *func)
const char *paren = strchr (func, '('); const char *paren = strchr (func, '(');
if (paren) if (paren)
func_len = paren - func; func_len = paren - func;
fprintf (stderr, "%.*s", func_len, func); fprintf (stderr, "%.*s", (int) func_len, func);
} }
} }
@ -142,9 +142,9 @@ _hb_debug_msg_va (const char *what,
fprintf (stderr, "%-10s", what ? what : ""); fprintf (stderr, "%-10s", what ? what : "");
if (obj) if (obj)
fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj); fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj);
else else
fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), ""); fprintf (stderr, " %*s ", (int) (2 * sizeof (void *)), "");
if (indented) { if (indented) {
#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
@ -306,7 +306,7 @@ struct hb_auto_trace_t
} }
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1, _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
"return %s (line %d)", "return %s (line %u)",
hb_printer_t<hb_decay<decltype (v)>>().print (v), line); hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
if (plevel) --*plevel; if (plevel) --*plevel;
plevel = nullptr; plevel = nullptr;
@ -373,6 +373,10 @@ struct hb_no_trace_t {
#define HB_DEBUG_FT (HB_DEBUG+0) #define HB_DEBUG_FT (HB_DEBUG+0)
#endif #endif
#ifndef HB_DEBUG_JUSTIFY
#define HB_DEBUG_JUSTIFY (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_OBJECT #ifndef HB_DEBUG_OBJECT
#define HB_DEBUG_OBJECT (HB_DEBUG+0) #define HB_DEBUG_OBJECT (HB_DEBUG+0)
#endif #endif
@ -396,7 +400,7 @@ struct hb_no_trace_t {
#define TRACE_APPLY(this) \ #define TRACE_APPLY(this) \
hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
"idx %d gid %u lookup %d", \ "idx %u gid %u lookup %d", \
c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
#else #else
#define TRACE_APPLY(this) hb_no_trace_t<bool> trace #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
@ -454,7 +458,7 @@ struct hb_no_trace_t {
#define TRACE_DISPATCH(this, format) \ #define TRACE_DISPATCH(this, format) \
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
"format %d", (int) format) "format %u", (unsigned) format)
#else #else
#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
#endif #endif

View file

@ -102,7 +102,8 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t *glyph, hb_codepoint_t *glyph,
void *user_data); void *user_data);
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void HB_DEPRECATED_FOR (hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func)
HB_EXTERN void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func, hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy); void *user_data, hb_destroy_func_t destroy);

View file

@ -251,15 +251,11 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader); data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
data->dwriteFactory->Release (); data->dwriteFactory->Release ();
} }
if (data->fontFileLoader)
delete data->fontFileLoader; delete data->fontFileLoader;
if (data->fontFileStream)
delete data->fontFileStream; delete data->fontFileStream;
if (data->faceBlob)
hb_blob_destroy (data->faceBlob); hb_blob_destroy (data->faceBlob);
if (data->dwrite_dll) if (data->dwrite_dll)
FreeLibrary (data->dwrite_dll); FreeLibrary (data->dwrite_dll);
if (data)
delete data; delete data;
} }

View file

@ -35,6 +35,8 @@
* @include: hb.h * @include: hb.h
* *
* Functions for drawing (extracting) glyph shapes. * Functions for drawing (extracting) glyph shapes.
*
* The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph().
**/ **/
static void static void
@ -198,13 +200,29 @@ DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
} }
}; };
/**
* hb_draw_funcs_get_empty:
*
* Fetches the singleton empty draw-functions structure.
*
* Return value: (transfer full): The empty draw-functions structure
*
* Since: 7.0.0
**/
hb_draw_funcs_t *
hb_draw_funcs_get_empty ()
{
return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
}
/** /**
* hb_draw_funcs_reference: (skip) * hb_draw_funcs_reference: (skip)
* @dfuncs: draw functions * @dfuncs: draw functions
* *
* Increases the reference count on @dfuncs by one. This prevents @buffer from * Increases the reference count on @dfuncs by one.
* being destroyed until a matching call to hb_draw_funcs_destroy() is made. *
* This prevents @dfuncs from being destroyed until a matching
* call to hb_draw_funcs_destroy() is made.
* *
* Return value: (transfer full): * Return value: (transfer full):
* The referenced #hb_draw_funcs_t. * The referenced #hb_draw_funcs_t.
@ -246,6 +264,49 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
hb_free (dfuncs); hb_free (dfuncs);
} }
/**
* hb_draw_funcs_set_user_data: (skip)
* @dfuncs: The draw-functions structure
* @key: The user-data key
* @data: A pointer to the user data
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified draw-functions structure.
*
* Return value: `true` if success, `false` otherwise
*
* Since: 7.0.0
**/
hb_bool_t
hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (dfuncs, key, data, destroy, replace);
}
/**
* hb_draw_funcs_get_user_data: (skip)
* @dfuncs: The draw-functions structure
* @key: The user-data key to query
*
* Fetches the user-data associated with the specified key,
* attached to the specified draw-functions structure.
*
* Return value: (transfer none): A pointer to the user data
*
* Since: 7.0.0
**/
void *
hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (dfuncs, key);
}
/** /**
* hb_draw_funcs_make_immutable: * hb_draw_funcs_make_immutable:
* @dfuncs: draw functions * @dfuncs: draw functions

View file

@ -92,11 +92,11 @@ typedef struct hb_draw_funcs_t hb_draw_funcs_t;
/** /**
* hb_draw_move_to_func_t: * hb_draw_move_to_func_t:
* @dfuncs: draw functions object * @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state * @st: current draw state
* @to_x: X component of target point * @to_x: X component of target point
* @to_y: Y component of target point * @to_y: Y component of target point
* @user_data: User data pointer passed by the caller * @user_data: User data pointer passed to hb_draw_funcs_set_move_to_func()
* *
* A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
* operation. * operation.
@ -112,11 +112,11 @@ typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data
/** /**
* hb_draw_line_to_func_t: * hb_draw_line_to_func_t:
* @dfuncs: draw functions object * @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state * @st: current draw state
* @to_x: X component of target point * @to_x: X component of target point
* @to_y: Y component of target point * @to_y: Y component of target point
* @user_data: User data pointer passed by the caller * @user_data: User data pointer passed to hb_draw_funcs_set_line_to_func()
* *
* A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
* operation. * operation.
@ -132,13 +132,13 @@ typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data
/** /**
* hb_draw_quadratic_to_func_t: * hb_draw_quadratic_to_func_t:
* @dfuncs: draw functions object * @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state * @st: current draw state
* @control_x: X component of control point * @control_x: X component of control point
* @control_y: Y component of control point * @control_y: Y component of control point
* @to_x: X component of target point * @to_x: X component of target point
* @to_y: Y component of target point * @to_y: Y component of target point
* @user_data: User data pointer passed by the caller * @user_data: User data pointer passed to hb_draw_funcs_set_quadratic_to_func()
* *
* A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
* operation. * operation.
@ -155,7 +155,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw
/** /**
* hb_draw_cubic_to_func_t: * hb_draw_cubic_to_func_t:
* @dfuncs: draw functions object * @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state * @st: current draw state
* @control1_x: X component of first control point * @control1_x: X component of first control point
* @control1_y: Y component of first control point * @control1_y: Y component of first control point
@ -163,7 +163,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw
* @control2_y: Y component of second control point * @control2_y: Y component of second control point
* @to_x: X component of target point * @to_x: X component of target point
* @to_y: Y component of target point * @to_y: Y component of target point
* @user_data: User data pointer passed by the caller * @user_data: User data pointer passed to hb_draw_funcs_set_cubic_to_func()
* *
* A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
* operation. * operation.
@ -181,9 +181,9 @@ typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_dat
/** /**
* hb_draw_close_path_func_t: * hb_draw_close_path_func_t:
* @dfuncs: draw functions object * @dfuncs: draw functions object
* @draw_data: The data accompanying the draw functions * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state * @st: current draw state
* @user_data: User data pointer passed by the caller * @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func()
* *
* A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
* operation. * operation.
@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs,
HB_EXTERN hb_draw_funcs_t * HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_create (void); hb_draw_funcs_create (void);
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_get_empty (void);
HB_EXTERN hb_draw_funcs_t * HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs); hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
HB_EXTERN void HB_EXTERN void
hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs); hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
HB_EXTERN hb_bool_t
hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
hb_user_data_key_t *key);
HB_EXTERN void HB_EXTERN void
hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);

View file

@ -0,0 +1,246 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2012 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.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-face.hh"
#include "hb-map.hh"
#include "hb-open-file.hh"
#include "hb-serialize.hh"
/*
* face-builder: A face that has add_table().
*/
struct face_table_info_t
{
hb_blob_t* data;
signed order;
};
struct hb_face_builder_data_t
{
hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
};
static int compare_entries (const void* pa, const void* pb)
{
const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
/* Order by blob size first (smallest to largest) and then table tag */
if (a.second.order != b.second.order)
return a.second.order < b.second.order ? -1 : +1;
if (a.second.data->length != b.second.data->length)
return a.second.data->length < b.second.data->length ? -1 : +1;
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
}
static hb_face_builder_data_t *
_hb_face_builder_data_create ()
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t));
if (unlikely (!data))
return nullptr;
data->tables.init ();
return data;
}
static void
_hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (auto info : data->tables.values())
hb_blob_destroy (info.data);
data->tables.fini ();
hb_free (data);
}
static hb_blob_t *
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
{
unsigned int table_count = data->tables.get_population ();
unsigned int face_length = table_count * 16 + 12;
for (auto info : data->tables.values())
face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
char *buf = (char *) hb_malloc (face_length);
if (unlikely (!buf))
return nullptr;
hb_serialize_context_t c (buf, face_length);
c.propagate_error (data->tables);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' '))
|| data->tables.has (HB_TAG ('C','F','F','2')));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
// Sort the tags so that produced face is deterministic.
hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
data->tables.iter () | hb_sink (sorted_entries);
if (unlikely (sorted_entries.in_error ()))
{
hb_free (buf);
return nullptr;
}
sorted_entries.qsort (compare_entries);
bool ret = f->serialize_single (&c,
sfnt_tag,
+ sorted_entries.iter()
| hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
}));
c.end_serialize ();
if (unlikely (!ret))
{
hb_free (buf);
return nullptr;
}
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
}
static hb_blob_t *
_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
if (!tag)
return _hb_face_builder_data_reference_blob (data);
return hb_blob_reference (data->tables[tag].data);
}
/**
* hb_face_builder_create:
*
* Creates a #hb_face_t that can be used with hb_face_builder_add_table().
* After tables are added to the face, it can be compiled to a binary
* font file by calling hb_face_reference_blob().
*
* Return value: (transfer full): New face.
*
* Since: 1.9.0
**/
hb_face_t *
hb_face_builder_create ()
{
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
if (unlikely (!data)) return hb_face_get_empty ();
return hb_face_create_for_tables (_hb_face_builder_reference_table,
data,
_hb_face_builder_data_destroy);
}
/**
* hb_face_builder_add_table:
* @face: A face object created with hb_face_builder_create()
* @tag: The #hb_tag_t of the table to add
* @blob: The blob containing the table data to add
*
* Add table for @tag with data provided by @blob to the face. @face must
* be created using hb_face_builder_create().
*
* Since: 1.9.0
**/
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
if (tag == HB_MAP_VALUE_INVALID)
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_blob_t* previous = data->tables.get (tag).data;
if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
{
hb_blob_destroy (blob);
return false;
}
hb_blob_destroy (previous);
return true;
}
/**
* hb_face_builder_sort_tables:
* @face: A face object created with hb_face_builder_create()
* @tags: (array zero-terminated=1): ordered list of table tags terminated by
* %HB_TAG_NONE
*
* Set the ordering of tables for serialization. Any tables not
* specified in the tags list will be ordered after the tables in
* tags, ordered by the default sort ordering.
*
* Since: 5.3.0
**/
void
hb_face_builder_sort_tables (hb_face_t *face,
const hb_tag_t *tags)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
// Sort all unspecified tables after any specified tables.
for (auto& info : data->tables.values_ref())
info.order = (unsigned) -1;
signed order = 0;
for (const hb_tag_t* tag = tags;
*tag;
tag++)
{
face_table_info_t* info;
if (!data->tables.has (*tag, &info)) continue;
info->order = order++;
}
}

View file

@ -33,7 +33,6 @@
#include "hb-open-file.hh" #include "hb-open-file.hh"
#include "hb-ot-face.hh" #include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh" #include "hb-ot-cmap-table.hh"
#include "hb-map.hh"
/** /**
@ -472,6 +471,8 @@ hb_face_get_index (const hb_face_t *face)
* *
* Sets the units-per-em (upem) for a face object to the specified value. * Sets the units-per-em (upem) for a face object to the specified value.
* *
* This API is used in rare circumstances.
*
* Since: 0.9.2 * Since: 0.9.2
**/ **/
void void
@ -488,7 +489,10 @@ hb_face_set_upem (hb_face_t *face,
* hb_face_get_upem: * hb_face_get_upem:
* @face: A face object * @face: A face object
* *
* Fetches the units-per-em (upem) value of the specified face object. * Fetches the units-per-em (UPEM) value of the specified face object.
*
* Typical UPEM values for fonts are 1000, or 2048, but any value
* in between 16 and 16,384 is allowed for OpenType fonts.
* *
* Return value: The upem value of @face * Return value: The upem value of @face
* *
@ -507,6 +511,8 @@ hb_face_get_upem (const hb_face_t *face)
* *
* Sets the glyph count for a face object to the specified value. * Sets the glyph count for a face object to the specified value.
* *
* This API is used in rare circumstances.
*
* Since: 0.9.7 * Since: 0.9.7
**/ **/
void void
@ -581,7 +587,7 @@ hb_face_get_table_tags (const hb_face_t *face,
/** /**
* hb_face_collect_unicodes: * hb_face_collect_unicodes:
* @face: A face object * @face: A face object
* @out: The set to add Unicode characters to * @out: (out): The set to add Unicode characters to
* *
* Collects all of the Unicode characters covered by @face and adds * Collects all of the Unicode characters covered by @face and adds
* them to the #hb_set_t set @out. * them to the #hb_set_t set @out.
@ -594,10 +600,31 @@ hb_face_collect_unicodes (hb_face_t *face,
{ {
face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
} }
/**
* hb_face_collect_nominal_glyph_mapping:
* @face: A face object
* @mapping: (out): The map to add Unicode-to-glyph mapping to
* @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL`
*
* Collects the mapping from Unicode characters to nominal glyphs of the @face,
* and optionally all of the Unicode characters covered by @face.
*
* Since: 7.0.0
*/
void
hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
hb_map_t *mapping,
hb_set_t *unicodes)
{
hb_set_t stack_unicodes;
if (!unicodes)
unicodes = &stack_unicodes;
face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ());
}
/** /**
* hb_face_collect_variation_selectors: * hb_face_collect_variation_selectors:
* @face: A face object * @face: A face object
* @out: The set to add Variation Selector characters to * @out: (out): The set to add Variation Selector characters to
* *
* Collects all Unicode "Variation Selector" characters covered by @face and adds * Collects all Unicode "Variation Selector" characters covered by @face and adds
* them to the #hb_set_t set @out. * them to the #hb_set_t set @out.
@ -614,7 +641,7 @@ hb_face_collect_variation_selectors (hb_face_t *face,
* hb_face_collect_variation_unicodes: * hb_face_collect_variation_unicodes:
* @face: A face object * @face: A face object
* @variation_selector: The Variation Selector to query * @variation_selector: The Variation Selector to query
* @out: The set to add Unicode characters to * @out: (out): The set to add Unicode characters to
* *
* Collects all Unicode characters for @variation_selector covered by @face and adds * Collects all Unicode characters for @variation_selector covered by @face and adds
* them to the #hb_set_t set @out. * them to the #hb_set_t set @out.
@ -629,214 +656,3 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
face->table.cmap->collect_variation_unicodes (variation_selector, out); face->table.cmap->collect_variation_unicodes (variation_selector, out);
} }
#endif #endif
/*
* face-builder: A face that has add_table().
*/
struct face_table_info_t
{
hb_blob_t* data;
signed order;
};
struct hb_face_builder_data_t
{
hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
};
static int compare_entries (const void* pa, const void* pb)
{
const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
/* Order by blob size first (smallest to largest) and then table tag */
if (a.second.order != b.second.order)
return a.second.order < b.second.order ? -1 : +1;
if (a.second.data->length != b.second.data->length)
return a.second.data->length < b.second.data->length ? -1 : +1;
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
}
static hb_face_builder_data_t *
_hb_face_builder_data_create ()
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t));
if (unlikely (!data))
return nullptr;
data->tables.init ();
return data;
}
static void
_hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (auto info : data->tables.values())
hb_blob_destroy (info.data);
data->tables.fini ();
hb_free (data);
}
static hb_blob_t *
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
{
unsigned int table_count = data->tables.get_population ();
unsigned int face_length = table_count * 16 + 12;
for (auto info : data->tables.values())
face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
char *buf = (char *) hb_malloc (face_length);
if (unlikely (!buf))
return nullptr;
hb_serialize_context_t c (buf, face_length);
c.propagate_error (data->tables);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' '))
|| data->tables.has (HB_TAG ('C','F','F','2')));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
// Sort the tags so that produced face is deterministic.
hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
data->tables.iter () | hb_sink (sorted_entries);
if (unlikely (sorted_entries.in_error ()))
{
hb_free (buf);
return nullptr;
}
sorted_entries.qsort (compare_entries);
bool ret = f->serialize_single (&c,
sfnt_tag,
+ sorted_entries.iter()
| hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
}));
c.end_serialize ();
if (unlikely (!ret))
{
hb_free (buf);
return nullptr;
}
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
}
static hb_blob_t *
_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
if (!tag)
return _hb_face_builder_data_reference_blob (data);
return hb_blob_reference (data->tables[tag].data);
}
/**
* hb_face_builder_create:
*
* Creates a #hb_face_t that can be used with hb_face_builder_add_table().
* After tables are added to the face, it can be compiled to a binary
* font file by calling hb_face_reference_blob().
*
* Return value: (transfer full): New face.
*
* Since: 1.9.0
**/
hb_face_t *
hb_face_builder_create ()
{
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
if (unlikely (!data)) return hb_face_get_empty ();
return hb_face_create_for_tables (_hb_face_builder_reference_table,
data,
_hb_face_builder_data_destroy);
}
/**
* hb_face_builder_add_table:
* @face: A face object created with hb_face_builder_create()
* @tag: The #hb_tag_t of the table to add
* @blob: The blob containing the table data to add
*
* Add table for @tag with data provided by @blob to the face. @face must
* be created using hb_face_builder_create().
*
* Since: 1.9.0
**/
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
if (tag == HB_MAP_VALUE_INVALID)
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_blob_t* previous = data->tables.get (tag).data;
if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
{
hb_blob_destroy (blob);
return false;
}
hb_blob_destroy (previous);
return true;
}
/**
* hb_face_builder_sort_tables:
* @face: A face object created with hb_face_builder_create()
* @tags: (array zero-terminated=1): ordered list of table tags terminated by
* %HB_TAG_NONE
*
* Set the ordering of tables for serialization. Any tables not
* specified in the tags list will be ordered after the tables in
* tags, ordered by the default sort ordering.
*
* Since: 5.3.0
**/
void
hb_face_builder_sort_tables (hb_face_t *face,
const hb_tag_t *tags)
{
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
// Sort all unspecified tables after any specified tables.
for (auto& info : data->tables.values_ref())
info.order = (unsigned) -1;
signed order = 0;
for (const hb_tag_t* tag = tags;
*tag;
tag++)
{
face_table_info_t* info;
if (!data->tables.has (*tag, &info)) continue;
info->order = order++;
}
}

View file

@ -33,6 +33,7 @@
#include "hb-common.h" #include "hb-common.h"
#include "hb-blob.h" #include "hb-blob.h"
#include "hb-map.h"
#include "hb-set.h" #include "hb-set.h"
HB_BEGIN_DECLS HB_BEGIN_DECLS
@ -149,6 +150,11 @@ HB_EXTERN void
hb_face_collect_unicodes (hb_face_t *face, hb_face_collect_unicodes (hb_face_t *face,
hb_set_t *out); hb_set_t *out);
HB_EXTERN void
hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
hb_map_t *mapping,
hb_set_t *unicodes);
HB_EXTERN void HB_EXTERN void
hb_face_collect_variation_selectors (hb_face_t *face, hb_face_collect_variation_selectors (hb_face_t *face,
hb_set_t *out); hb_set_t *out);

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