Update Harfbuzz to 7.0.1

Note: 6.4.x update has to be done in a separate commit
because it did not get the update to 6.0.0, so the
cherry-pick will not apply.

Pick-to: 6.2 6.5
Task-number: QTBUG-111535
Change-Id: I9d4aae98f8267827ec983ca89b1310006c6aee78
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2023-02-27 09:53:00 +01:00
parent 5f32c9edce
commit a6edf9cbe5
218 changed files with 14045 additions and 9011 deletions

View File

@ -16,7 +16,8 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-blob.cc src/hb-blob.h
src/hb-buffer.cc src/hb-buffer.h src/hb-buffer.hh
src/hb-buffer-deserialize-json.hh
src/hb-buffer-deserialize-text.hh
src/hb-buffer-deserialize-text-glyphs.hh
src/hb-buffer-deserialize-text-unicode.hh
src/hb-buffer-serialize.cc
src/hb-buffer-verify.cc
src/hb-cache.hh
@ -25,14 +26,20 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-deprecated.h
src/hb-draw.cc src/hb-draw.h src/hb-draw.hh
src/hb-face.cc src/hb-face.h src/hb-face.hh
src/hb-face-builder.cc
src/hb-fallback-shape.cc
src/hb-font.cc src/hb-font.h src/hb-font.hh
src/hb-ft-colr.hh
src/hb-limits.hh
src/hb-map.cc
src/hb-mutex.hh
src/hb-number.cc
src/hb-object.hh
src/hb-open-file.hh
src/hb-open-type.hh
src/hb-outline.cc src/hb-outline.hh
src/hb-paint.cc src/hb-paint.h src/hb-paint.hh
src/hb-paint-extents.cc src/hb-paint-extents.hh
src/hb-priority-queue.hh
src/hb-repacker.hh
src/hb-set.cc src/hb-set.h src/hb-set.hh
@ -49,6 +56,7 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-subset-cff1.cc
src/hb-subset-cff2.cc
src/hb-subset-input.cc
src/hb-subset-instancer-solver.cc
src/hb-subset-plan.cc
src/hb-subset-repacker.cc src/hb-subset-repacker.h
src/hb-unicode.cc src/hb-unicode.h src/hb-unicode.hh
@ -103,8 +111,6 @@ qt_internal_extend_target(BundledHarfbuzz CONDITION TRUE
src/hb-ot-cff2-table.cc
src/hb-ot-cmap-table.hh
src/hb-ot-color.cc
src/hb-ot-color-cbdt-table.hh
src/hb-ot-color-colrv1-closure.hh
src/hb-ot-face.cc
src/hb-ot-font.cc src/hb-ot-font.h
src/hb-ot-glyf-table.hh
@ -163,6 +169,14 @@ qt_internal_extend_target(BundledHarfbuzz CONDITION TRUE
src/hb-ot-var-fvar-table.hh
src/hb-ot-var-hvar-table.hh
src/hb-ot-var-mvar-table.hh
src/OT/Color/CBDT/CBDT.hh
src/OT/Color/COLR/COLR.hh
src/OT/Color/COLR/colrv1-closure.hh
src/OT/Color/CPAL/CPAL.hh
src/OT/Color/sbix/sbix.hh
src/OT/Color/svg/svg.hh
src/OT/Layout/GDEF/GDEF.hh
src/OT/name/name.hh
DEFINES
HAVE_OT
)

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
files names COPYING in subdirectories where applicable.
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
Copyright © 2018,2019,2020 Ebrahim Byagowi
Copyright © 2010-2022 Google, Inc.
Copyright © 2015-2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012 Mozilla Foundation
Copyright © 2012,2015 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2011 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2005,2006,2020,2021 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
Copyright © 1998-2005 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.

View File

@ -1,3 +1,139 @@
Overview of changes leading to 7.0.1
Monday, February 20, 2023
====================================
- Various build and bug fixes.
Overview of changes leading to 7.0.0
Saturday, February 11, 2023
====================================
- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be
also used as a unified API to paint any of the glyph representations
supported by HarfBuzz (B/W outlines, color layers, or color bitmaps).
(Behdad Esfahbod, Matthias Clasen)
- New hb-cairo API for integrating with cairo graphics library. This is provided
as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen)
- Support for instancing “CFF2” table. (Behdad Esfahbod)
- Support font emboldening. (Behdad Esfahbod)
- Support feature ranges with AAT shaping. (Behdad Esfahbod)
- Experimental support to cubic curves in “glyf” table, see
https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md
for spec. (Behdad Esfahbod)
- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
- Various documentation improvements.
(Behdad Esfahbod, Matthias Clasen, Khaled Hosny)
- Significantly reduced memory use during shaping. (Behdad Esfahbod)
- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod)
- New command line utility, hb-info, for querying various font information.
(Behdad Esfahbod, Matthias Clasen)
- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold,
--font-grade, and --named-instance. (Behdad Esfahbod)
- Miscellaneous fixes and improvements.
(Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan,
Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen,
Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich)
- New API:
+HB_FONT_NO_VAR_NAMED_INSTANCE
+HB_PAINT_IMAGE_FORMAT_BGRA
+HB_PAINT_IMAGE_FORMAT_PNG
+HB_PAINT_IMAGE_FORMAT_SVG
+hb_cairo_font_face_create_for_face
+hb_cairo_font_face_create_for_font
+hb_cairo_font_face_get_face
+hb_cairo_font_face_get_font
+hb_cairo_font_face_get_scale_factor
+hb_cairo_font_face_set_font_init_func
+hb_cairo_font_face_set_scale_factor
+hb_cairo_font_init_func_t
+hb_cairo_glyphs_from_buffer
+hb_cairo_scaled_font_get_font
+hb_color_line_get_color_stops
+hb_color_line_get_color_stops_func_t
+hb_color_line_get_extend
+hb_color_line_get_extend_func_t
+hb_color_line_t
+hb_color_stop_t
+hb_draw_funcs_get_empty
+hb_draw_funcs_get_user_data
+hb_draw_funcs_set_user_data
+hb_face_collect_nominal_glyph_mapping
+hb_font_draw_glyph
+hb_font_draw_glyph_func_t
+hb_font_funcs_set_draw_glyph_func
+hb_font_funcs_set_paint_glyph_func
+hb_font_get_synthetic_bold
+hb_font_get_var_named_instance
+hb_font_paint_glyph
+hb_font_paint_glyph_func_t
+hb_font_set_synthetic_bold
+hb_map_keys
+hb_map_next
+hb_map_update
+hb_map_values
+hb_ot_color_glyph_has_paint
+hb_ot_color_has_paint
+hb_ot_layout_script_select_language2
+hb_ot_name_id_predefined_t
+hb_paint_color
+hb_paint_color_func_t
+hb_paint_composite_mode_t
+hb_paint_custom_palette_color
+hb_paint_custom_palette_color_func_t
+hb_paint_extend_t
+hb_paint_funcs_create
+hb_paint_funcs_destroy
+hb_paint_funcs_get_empty
+hb_paint_funcs_get_user_data
+hb_paint_funcs_is_immutable
+hb_paint_funcs_make_immutable
+hb_paint_funcs_reference
+hb_paint_funcs_set_color_func
+hb_paint_funcs_set_custom_palette_color_func
+hb_paint_funcs_set_image_func
+hb_paint_funcs_set_linear_gradient_func
+hb_paint_funcs_set_pop_clip_func
+hb_paint_funcs_set_pop_group_func
+hb_paint_funcs_set_pop_transform_func
+hb_paint_funcs_set_push_clip_glyph_func
+hb_paint_funcs_set_push_clip_rectangle_func
+hb_paint_funcs_set_push_group_func
+hb_paint_funcs_set_push_transform_func
+hb_paint_funcs_set_radial_gradient_func
+hb_paint_funcs_set_sweep_gradient_func
+hb_paint_funcs_set_user_data
+hb_paint_funcs_t
+hb_paint_image
+hb_paint_image_func_t
+hb_paint_linear_gradient
+hb_paint_linear_gradient_func_t
+hb_paint_pop_clip
+hb_paint_pop_clip_func_t
+hb_paint_pop_group
+hb_paint_pop_group_func_t
+hb_paint_pop_transform
+hb_paint_pop_transform_func_t
+hb_paint_push_clip_glyph
+hb_paint_push_clip_glyph_func_t
+hb_paint_push_clip_rectangle
+hb_paint_push_clip_rectangle_func_t
+hb_paint_push_group
+hb_paint_push_group_func_t
+hb_paint_push_transform
+hb_paint_push_transform_func_t
+hb_paint_radial_gradient
+hb_paint_radial_gradient_func_t
+hb_paint_sweep_gradient
+hb_paint_sweep_gradient_func_t
+hb_set_is_inverted
+hb_subset_input_keep_everything
- Deprecated API:
+hb_font_funcs_set_glyph_shape_func
+hb_font_get_glyph_shape_func_t
+hb_font_get_glyph_shape
Overview of changes leading to 6.0.0
Friday, December 16, 2022
====================================

View File

@ -6,23 +6,26 @@
"Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org",
"Version": "6.0.0",
"Version": "7.0.1",
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "COPYING",
"Copyright": "Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
Copyright © 2018,2019,2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2005,2006,2020,2021 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg
"
"Copyright": "Copyright © 2010-2022 Google, Inc.
Copyright © 2015-2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012,2015 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2011 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
Copyright © 1998-2005 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"
}

View File

@ -24,10 +24,11 @@
* Google Author(s): Seigo Nonaka, Calder Kitagawa
*/
#ifndef HB_OT_COLOR_CBDT_TABLE_HH
#define HB_OT_COLOR_CBDT_TABLE_HH
#ifndef OT_COLOR_CBDT_CBDT_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
@ -80,12 +81,15 @@ struct SmallGlyphMetrics
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->y_bearing = font->em_scale_y (bearingY);
extents->width = font->em_scale_x (width);
extents->height = font->em_scale_y (-static_cast<int>(height));
extents->x_bearing = bearingX;
extents->y_bearing = bearingY;
extents->width = width;
extents->height = -static_cast<int> (height);
if (scale)
font->scale_glyph_extents (extents);
}
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)
{
@ -504,8 +508,8 @@ struct IndexSubtableRecord
return num_missing;
}
bool get_extents (hb_glyph_extents_t *extents, const void *base) const
{ return (base+offsetToSubtable).get_extents (extents); }
bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const
{ return (base+offsetToSubtable).get_extents (extents, scale); }
bool get_image_data (unsigned int gid,
const void *base,
@ -833,7 +837,7 @@ struct CBDT
}
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 BitmapSizeTable &strike = this->cblc->choose_strike (font);
@ -841,7 +845,7 @@ struct CBDT
if (!subtable_record || !strike.ppemX || !strike.ppemY)
return false;
if (subtable_record->get_extents (extents, base))
if (subtable_record->get_extents (extents, base, scale))
return true;
unsigned int image_offset = 0, image_length = 0, image_format = 0;
@ -858,26 +862,29 @@ struct CBDT
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
return false;
auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
glyphFormat17.glyphMetrics.get_extents (font, extents);
glyphFormat17.glyphMetrics.get_extents (font, extents, scale);
break;
}
case 18: {
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
return false;
auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
glyphFormat18.glyphMetrics.get_extents (font, extents);
glyphFormat18.glyphMetrics.get_extents (font, extents, scale);
break;
}
default: return false; /* TODO: Support other image formats. */
}
/* Convert to font units. */
float x_scale = upem / (float) strike.ppemX;
float y_scale = upem / (float) strike.ppemY;
extents->x_bearing = roundf (extents->x_bearing * x_scale);
extents->y_bearing = roundf (extents->y_bearing * y_scale);
extents->width = roundf (extents->width * x_scale);
extents->height = roundf (extents->height * y_scale);
if (scale)
{
float x_scale = upem / (float) strike.ppemX;
float y_scale = upem / (float) strike.ppemY;
extents->x_bearing = roundf (extents->x_bearing * x_scale);
extents->y_bearing = roundf (extents->y_bearing * y_scale);
extents->width = roundf (extents->width * x_scale);
extents->height = roundf (extents->height * y_scale);
}
return true;
}
@ -934,6 +941,32 @@ struct CBDT
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:
hb_blob_ptr_t<CBLC> cblc;
hb_blob_ptr_t<CBDT> cbdt;
@ -994,4 +1027,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t {
} /* 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
*/
#ifndef HB_OT_COLOR_COLR_TABLE_HH
#define HB_OT_COLOR_COLR_TABLE_HH
#ifndef OT_COLOR_COLR_COLR_HH
#define OT_COLOR_COLR_COLR_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-var-common.hh"
#include "../../../hb.hh"
#include "../../../hb-open-type.hh"
#include "../../../hb-ot-var-common.hh"
#include "../../../hb-paint.hh"
#include "../../../hb-paint-extents.hh"
/*
* COLR -- Color
@ -38,13 +40,82 @@
*/
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
#ifndef HB_COLRV1_MAX_NESTING_LEVEL
#define HB_COLRV1_MAX_NESTING_LEVEL 16
#endif
namespace OT {
struct hb_paint_context_t;
}
namespace OT {
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 :
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 *layer_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_),
glyphs (glyphs_),
layer_indices (layer_indices_),
@ -160,6 +231,8 @@ struct BaseGlyphRecord
template <typename T>
struct Variable
{
static constexpr bool is_variable = true;
Variable<T>* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@ -182,6 +255,23 @@ struct Variable
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:
T value;
public:
@ -193,6 +283,8 @@ struct Variable
template <typename T>
struct NoVariable
{
static constexpr bool is_variable = false;
static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
NoVariable<T>* copy (hb_serialize_context_t *c) const
@ -216,6 +308,23 @@ struct NoVariable
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;
public:
DEFINE_SIZE_STATIC (T::static_size);
@ -233,7 +342,7 @@ struct ColorStop
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
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));
}
@ -243,6 +352,17 @@ struct ColorStop
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;
HBUINT16 paletteIndex;
F2DOT14 alpha;
@ -294,6 +414,52 @@ struct ColorLine
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;
Array16Of<Var<ColorStop>> stops;
public:
@ -357,6 +523,17 @@ struct Affine2x3
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 yx;
F16DOT16 xy;
@ -376,7 +553,7 @@ struct PaintColrLayers
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
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));
return_trace (true);
@ -388,6 +565,8 @@ struct PaintColrLayers
return_trace (c->check_struct (this));
}
inline void paint_glyph (hb_paint_context_t *c) const;
HBUINT8 format; /* format = 1 */
HBUINT8 numLayers;
HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */
@ -405,7 +584,7 @@ struct PaintSolid
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
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));
}
@ -415,6 +594,17 @@ struct PaintSolid
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)*/
HBUINT16 paletteIndex;
F2DOT14 alpha;
@ -443,6 +633,23 @@ struct PaintLinearGradient
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) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient
* table) to ColorLine subtable. */
@ -477,6 +684,23 @@ struct PaintRadialGradient
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) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient
* table) to ColorLine subtable. */
@ -511,6 +735,21 @@ struct PaintSweepGradient
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) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient
* table) to ColorLine subtable. */
@ -522,8 +761,6 @@ struct PaintSweepGradient
DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
};
struct Paint;
// Paint a non-COLR glyph, filled as indicated by paint.
struct PaintGlyph
{
@ -548,6 +785,17 @@ struct PaintGlyph
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 */
Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
HBUINT16 gid;
@ -575,6 +823,8 @@ struct PaintColrGlyph
return_trace (c->check_struct (this));
}
inline void paint_glyph (hb_paint_context_t *c) const;
HBUINT8 format; /* format = 11 */
HBUINT16 gid;
public:
@ -603,6 +853,13 @@ struct PaintTransform
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
Offset24To<Var<Affine2x3>> transform;
@ -629,6 +886,16 @@ struct PaintTranslate
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
FWORD dx;
@ -656,6 +923,16 @@ struct PaintScale
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
F2DOT14 scaleX;
@ -683,6 +960,22 @@ struct PaintScaleAroundCenter
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
F2DOT14 scaleX;
@ -712,6 +1005,15 @@ struct PaintScaleUniform
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
F2DOT14 scale;
@ -738,6 +1040,21 @@ struct PaintScaleUniformAroundCenter
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
F2DOT14 scale;
@ -766,6 +1083,15 @@ struct PaintRotate
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
F2DOT14 angle;
@ -792,6 +1118,21 @@ struct PaintRotateAroundCenter
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
F2DOT14 angle;
@ -820,6 +1161,16 @@ struct PaintSkew
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
F2DOT14 xSkewAngle;
@ -847,6 +1198,22 @@ struct PaintSkewAroundCenter
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) */
Offset24To<Paint> src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
F2DOT14 xSkewAngle;
@ -879,6 +1246,14 @@ struct PaintComposite
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 */
Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */
@ -948,8 +1323,8 @@ struct ClipBox
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
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)...));
@ -1084,7 +1459,7 @@ struct ClipList
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);
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;
hb_map_t new_gid_offset_map;
@ -1142,7 +1517,7 @@ struct Paint
{
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->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
@ -1151,8 +1526,8 @@ struct Paint
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
@ -1194,35 +1569,35 @@ struct Paint
union {
HBUINT8 format;
PaintColrLayers paintformat1;
PaintSolid paintformat2;
NoVariable<PaintSolid> paintformat2;
Variable<PaintSolid> paintformat3;
PaintLinearGradient<NoVariable> paintformat4;
NoVariable<PaintLinearGradient<NoVariable>> paintformat4;
Variable<PaintLinearGradient<Variable>> paintformat5;
PaintRadialGradient<NoVariable> paintformat6;
NoVariable<PaintRadialGradient<NoVariable>> paintformat6;
Variable<PaintRadialGradient<Variable>> paintformat7;
PaintSweepGradient<NoVariable> paintformat8;
NoVariable<PaintSweepGradient<NoVariable>> paintformat8;
Variable<PaintSweepGradient<Variable>> paintformat9;
PaintGlyph paintformat10;
PaintColrGlyph paintformat11;
PaintTransform<NoVariable> paintformat12;
PaintTransform<Variable> paintformat13;
PaintTranslate paintformat14;
NoVariable<PaintTranslate> paintformat14;
Variable<PaintTranslate> paintformat15;
PaintScale paintformat16;
NoVariable<PaintScale> paintformat16;
Variable<PaintScale> paintformat17;
PaintScaleAroundCenter paintformat18;
NoVariable<PaintScaleAroundCenter> paintformat18;
Variable<PaintScaleAroundCenter> paintformat19;
PaintScaleUniform paintformat20;
NoVariable<PaintScaleUniform> paintformat20;
Variable<PaintScaleUniform> paintformat21;
PaintScaleUniformAroundCenter paintformat22;
NoVariable<PaintScaleUniformAroundCenter> paintformat22;
Variable<PaintScaleUniformAroundCenter> paintformat23;
PaintRotate paintformat24;
NoVariable<PaintRotate> paintformat24;
Variable<PaintRotate> paintformat25;
PaintRotateAroundCenter paintformat26;
NoVariable<PaintRotateAroundCenter> paintformat26;
Variable<PaintRotateAroundCenter> paintformat27;
PaintSkew paintformat28;
NoVariable<PaintSkew> paintformat28;
Variable<PaintSkew> paintformat29;
PaintSkewAroundCenter paintformat30;
NoVariable<PaintSkewAroundCenter> paintformat30;
Variable<PaintSkewAroundCenter> paintformat31;
PaintComposite paintformat32;
} u;
@ -1269,7 +1644,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
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 ())
{
@ -1323,7 +1698,14 @@ struct 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 start_offset,
@ -1503,7 +1885,7 @@ struct COLR
TRACE_SUBSET (this);
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 =
+ 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)))
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
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);
@ -1585,10 +1967,23 @@ struct COLR
colr_prime->layerList.serialize_subset (c, layerList, this);
colr_prime->clipList.serialize_subset (c, clipList, 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);
}
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
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
@ -1599,14 +1994,138 @@ struct COLR
this+varIdxMap,
hb_array (font->coords, font->num_coords));
if ((this+clipList).get_extents (glyph,
extents,
instancer))
if (get_clip (glyph, extents, instancer))
{
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_x (extents->y_bearing);
extents->width = font->em_scale_x (extents->width);
extents->height = font->em_scale_x (extents->height);
font->scale_glyph_extents (extents);
return true;
}
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;
}
@ -1635,7 +2154,50 @@ struct COLR_accelerator_t : COLR::accelerator_t {
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 */
#endif /* HB_OT_COLOR_COLR_TABLE_HH */
#endif /* OT_COLOR_COLR_COLR_HH */

View File

@ -24,12 +24,11 @@
*
*/
#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH
#define HB_OT_COLR_COLRV1_CLOSURE_HH
#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH
#define OT_COLOR_COLR_COLRV1_CLOSURE_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-color-colr-table.hh"
#include "../../../hb-open-type.hh"
#include "COLR.hh"
/*
* COLR -- Color
@ -105,4 +104,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons
} /* 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
*/
#ifndef HB_OT_COLOR_CPAL_TABLE_HH
#define HB_OT_COLOR_CPAL_TABLE_HH
#ifndef OT_COLOR_CPAL_CPAL_HH
#define OT_COLOR_CPAL_CPAL_HH
#include "hb-open-type.hh"
#include "hb-ot-color.h"
#include "hb-ot-name.h"
#include "../../../hb-open-type.hh"
#include "../../../hb-ot-color.h"
#include "../../../hb-ot-name.h"
/*
@ -239,7 +239,7 @@ struct CPAL
TRACE_SUBSET (this);
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);
hb_set_t retained_color_indices;
@ -319,4 +319,4 @@ struct CPAL
} /* 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
*/
#ifndef HB_OT_COLOR_SBIX_TABLE_HH
#define HB_OT_COLOR_SBIX_TABLE_HH
#ifndef OT_COLOR_SBIX_SBIX_HH
#define OT_COLOR_SBIX_SBIX_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "../../../hb-open-type.hh"
#include "../../../hb-paint.hh"
/*
* sbix -- Standard Bitmap Graphics
@ -213,10 +213,11 @@ struct sbix
bool get_extents (hb_font_t *font,
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. */
return get_png_extents (font, glyph, extents);
return get_png_extents (font, glyph, extents, scale);
}
hb_blob_t *reference_png (hb_font_t *font,
@ -231,6 +232,37 @@ struct sbix
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:
const SBIXStrike &choose_strike (hb_font_t *font) const
@ -285,7 +317,8 @@ struct sbix
bool get_png_extents (hb_font_t *font,
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.
* But faster to short-circuit. */
@ -310,22 +343,18 @@ struct sbix
extents->height = -1 * png.IHDR.height;
/* Convert to font units. */
if (strike_ppem)
if (strike_ppem && scale)
{
float scale = font->face->get_upem () / (float) strike_ppem;
extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
extents->width = font->em_scalef_x (extents->width * scale);
extents->height = font->em_scalef_y (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);
extents->x_bearing = roundf (extents->x_bearing * scale);
extents->y_bearing = roundf (extents->y_bearing * scale);
extents->width = roundf (extents->width * scale);
extents->height = roundf (extents->height * scale);
}
if (scale)
font->scale_glyph_extents (extents);
hb_blob_destroy (blob);
return strike_ppem;
@ -420,4 +449,4 @@ struct sbix_accelerator_t : sbix::accelerator_t {
} /* 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.
*/
#ifndef HB_OT_COLOR_SVG_TABLE_HH
#define HB_OT_COLOR_SVG_TABLE_HH
#ifndef OT_COLOR_SVG_SVG_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)
@ -91,8 +93,31 @@ struct SVG
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:
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
@ -123,4 +148,4 @@ struct SVG_accelerator_t : SVG::accelerator_t {
} /* 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);
auto it =
+ iter ()
| hb_take (c->plan->source->get_num_glyphs ())
| hb_filter (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);
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 (!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;
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 (!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 (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->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, 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);
return_trace (out);
}

View File

@ -19,8 +19,8 @@ struct CursivePos
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());

View File

@ -143,7 +143,7 @@ struct CursivePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
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);
}
@ -241,7 +241,7 @@ struct CursivePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
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);
}

View File

@ -42,7 +42,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
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);
}
@ -56,7 +56,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
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);
}

View File

@ -22,8 +22,8 @@ struct MarkBasePos
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K

View File

@ -90,6 +90,25 @@ struct MarkBasePosFormat1_2
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
{
TRACE_APPLY (this);
@ -97,48 +116,54 @@ struct MarkBasePosFormat1_2
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
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;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
do {
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
/* 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 */
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 */
//if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
if (base_index == NOT_COVERED)
if (c->last_base_until > buffer->idx)
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, 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 ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
unsigned idx = (unsigned) c->last_base;
/* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint);
if (base_index == NOT_COVERED)
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
}
bool subset (hb_subset_context_t *c) const

View File

@ -22,8 +22,8 @@ struct MarkLigPos
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K

View File

@ -100,20 +100,37 @@ struct MarkLigPosFormat1_2
if (likely (mark_index == NOT_COVERED)) return_trace (false);
/* Now we search backwards for a non-mark glyph */
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);
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);
}
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
j = (unsigned) c->last_base;
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_ligature (&buffer->info[j])) { return_trace (false); }
unsigned int j = skippy_iter.idx;
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
if (lig_index == NOT_COVERED)
{

View File

@ -22,8 +22,8 @@ struct MarkMarkPos
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K

View File

@ -25,8 +25,8 @@ struct PairPos
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
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)...));

View File

@ -43,7 +43,7 @@ struct PairPosFormat1_3
{
valueFormat,
len1,
1 + len1 + len2
PairSet::get_size (len1, len2)
};
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
{
unsigned len1 = valueFormat[0].get_len ();
unsigned len2 = valueFormat[1].get_len ();
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
unsigned record_size = PairSet::get_size (valueFormat);
unsigned format1 = 0;
unsigned format2 = 0;

View File

@ -49,7 +49,7 @@ struct PairPosFormat2_4
unsigned int len1 = valueFormat1.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 count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_range ((const void *) values,
@ -220,7 +220,7 @@ struct PairPosFormat2_4
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"try kerning glyphs at %d,%d",
"try kerning glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx);
}
@ -231,14 +231,14 @@ struct PairPosFormat2_4
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerned glyphs at %d,%d",
"kerned glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx);
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"tried kerning glyphs at %d,%d",
"tried kerning glyphs at %u,%u",
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))
{
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);
valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], 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);
}
}

View File

@ -24,11 +24,22 @@ struct PairSet
public:
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
{
const ValueFormat *valueFormats;
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
@ -37,7 +48,6 @@ struct PairSet
if (!(c->check_struct (this)
&& c->check_range (&firstPairValueRecord,
len,
HBUINT16::static_size,
closure->stride))) return_trace (false);
unsigned int count = len;
@ -49,9 +59,7 @@ struct PairSet
bool intersects (const hb_set_t *glyphs,
const ValueFormat *valueFormats) const
{
unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
unsigned record_size = get_size (valueFormats);
const PairValueRecord *record = &firstPairValueRecord;
unsigned int count = len;
@ -67,9 +75,7 @@ struct PairSet
void collect_glyphs (hb_collect_glyphs_context_t *c,
const ValueFormat *valueFormats) const
{
unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
unsigned record_size = get_size (valueFormats);
const PairValueRecord *record = &firstPairValueRecord;
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,
const ValueFormat *valueFormats) const
{
unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
unsigned record_size = get_size (valueFormats);
const PairValueRecord *record = &firstPairValueRecord;
unsigned count = len;
@ -101,7 +105,7 @@ struct PairSet
hb_buffer_t *buffer = c->buffer;
unsigned int len1 = valueFormats[0].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,
&firstPairValueRecord,
@ -112,7 +116,7 @@ struct PairSet
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"try kerning glyphs at %d,%d",
"try kerning glyphs at %u,%u",
c->buffer->idx, pos);
}
@ -123,14 +127,14 @@ struct PairSet
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerned glyphs at %d,%d",
"kerned glyphs at %u,%u",
c->buffer->idx, pos);
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"tried kerning glyphs at %d,%d",
"tried kerning glyphs at %u,%u",
c->buffer->idx, pos);
}
@ -168,7 +172,7 @@ struct PairSet
unsigned len1 = valueFormats[0].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 =
{
@ -177,7 +181,7 @@ struct PairSet
newFormats,
len1,
&glyph_map,
c->plan->layout_variation_idx_delta_map
&c->plan->layout_variation_idx_delta_map
};
const PairValueRecord *record = &firstPairValueRecord;

View File

@ -72,8 +72,8 @@ struct SinglePos
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
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)...));

View File

@ -63,7 +63,7 @@ struct SinglePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioning glyph at %d",
"positioning glyph at %u",
c->buffer->idx);
}
@ -72,7 +72,7 @@ struct SinglePosFormat1
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioned glyph at %d",
"positioned glyph at %u",
c->buffer->idx);
}
@ -144,7 +144,7 @@ struct SinglePosFormat1
;
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);
}
};

View File

@ -73,7 +73,7 @@ struct SinglePosFormat2
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioning glyph at %d",
"positioning glyph at %u",
c->buffer->idx);
}
@ -84,7 +84,7 @@ struct SinglePosFormat2
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioned glyph at %d",
"positioned glyph at %u",
c->buffer->idx);
}
@ -163,7 +163,7 @@ struct SinglePosFormat2
;
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);
}
};

View File

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

View File

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

View File

@ -23,8 +23,8 @@ struct AlternateSubst
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K

View File

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

View File

@ -23,8 +23,8 @@ struct LigatureSubst
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K

View File

@ -24,8 +24,8 @@ struct MultipleSubst
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K

View File

@ -20,8 +20,8 @@ struct ReverseChainSingleSubst
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());

View File

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

View File

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

View File

@ -27,8 +27,8 @@ struct SingleSubst
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
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)...));

View File

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

View File

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

View File

@ -18,11 +18,6 @@ struct glyf_accelerator_t;
namespace glyf_impl {
#ifndef HB_GLYF_MAX_POINTS
#define HB_GLYF_MAX_POINTS 10000
#endif
enum phantom_point_index_t
{
PHANTOM_LEFT = 0,
@ -85,28 +80,38 @@ struct Glyph
}
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
{
hb_codepoint_t new_gid = 0;
if (!plan->new_gid_for_old_gid (gid, &new_gid))
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;
float leftSideX = all_points[len - 4].x;
float rightSideX = all_points[len - 3].x;
float topSideY = all_points[len - 2].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;
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;
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,
@ -114,7 +119,7 @@ struct Glyph
hb_bytes_t &dest_bytes /* OUT */) const
{
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);
if (unlikely (!glyph_header)) return false;
@ -138,18 +143,33 @@ struct Glyph
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);
int rounded_xMin = roundf (xMin);
int rounded_xMax = roundf (xMax);
int rounded_yMin = roundf (yMin);
int rounded_yMax = roundf (yMax);
/*for empty glyphs: all_points only include phantom points.
*just update metrics and then return */
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 */
if (!glyph_header)
return true;
glyph_header->numberOfContours = header->numberOfContours;
glyph_header->xMin = roundf (xMin);
glyph_header->yMin = roundf (yMin);
glyph_header->xMax = roundf (xMax);
glyph_header->yMax = roundf (yMax);
glyph_header->xMin = rounded_xMin;
glyph_header->yMin = rounded_yMin;
glyph_header->xMax = rounded_xMax;
glyph_header->yMax = rounded_yMax;
dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
return true;
@ -162,34 +182,54 @@ struct Glyph
hb_bytes_t &dest_end /* OUT */)
{
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;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
// it
if (gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
{
type = EMPTY;
switch (type) {
case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
deltas,
dest_end))
return false;
break;
case SIMPLE:
if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
dest_end))
return false;
break;
default:
/* set empty bytes for empty glyph
* do not use source glyph's pointers */
dest_start = hb_bytes_t ();
dest_end = hb_bytes_t ();
break;
}
//dont compile bytes when pinned at default, just recalculate bounds
if (!plan->pinned_at_default) {
switch (type) {
case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
deltas,
dest_end))
return false;
break;
case SIMPLE:
if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
dest_end))
return false;
break;
default:
/* set empty bytes for empty glyph
* do not use source glyph's pointers */
dest_start = hb_bytes_t ();
dest_end = hb_bytes_t ();
break;
}
}
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,
contour_point_vector_t &all_points /* 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 use_my_metrics = true,
bool phantom_only = false,
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;
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)
coords = hb_array (font->coords, font->num_coords);
@ -226,6 +278,10 @@ struct Glyph
switch (type) {
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)))
return false;
break;
@ -301,6 +357,8 @@ struct Glyph
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
if (!inplace)
all_points.extend (points.as_array ());
break;
@ -311,17 +369,19 @@ struct Glyph
for (auto &item : get_composite_iterator ())
{
comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font,
glyf_accelerator,
comp_points,
deltas,
head_maxp_info,
composite_contours,
shift_points_hori,
use_my_metrics,
phantom_only,
coords,
depth + 1)))
depth + 1,
edge_count)))
return false;
/* Copy phantom points from component if USE_MY_METRICS flag set */
@ -357,6 +417,13 @@ struct Glyph
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);
} break;
#ifndef HB_NO_VAR_COMPOSITES
@ -370,7 +437,11 @@ struct Glyph
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);
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
@ -378,11 +449,14 @@ struct Glyph
glyf_accelerator,
comp_points,
deltas,
head_maxp_info,
nullptr,
shift_points_hori,
use_my_metrics,
phantom_only,
coord_setter.get_coords (),
depth + 1)))
depth + 1,
edge_count)))
return false;
/* Apply component transformation */

View File

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

View File

@ -20,7 +20,7 @@ struct SimpleGlyph
FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20,
FLAG_OVERLAP_SIMPLE = 0x40,
FLAG_RESERVED2 = 0x80
FLAG_CUBIC = 0x80
};
const GlyphHeader &header;
@ -184,7 +184,7 @@ struct SimpleGlyph
if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
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 (phantom_only) return true;
@ -272,9 +272,9 @@ struct SimpleGlyph
unsigned num_points = all_points.length - 4;
hb_vector_t<uint8_t> flags, x_coords, y_coords;
if (unlikely (!flags.alloc (num_points))) return false;
if (unlikely (!x_coords.alloc (2*num_points))) return false;
if (unlikely (!y_coords.alloc (2*num_points))) return false;
if (unlikely (!flags.alloc (num_points, true))) return false;
if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
uint8_t lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0;

View File

@ -21,22 +21,14 @@ struct SubsetGlyph
bool serialize (hb_serialize_context_t *c,
bool use_short_loca,
const hb_subset_plan_t *plan,
hb_font_t *font)
const hb_subset_plan_t *plan)
{
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);
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
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;
pad = 0;

View File

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

View File

@ -7,6 +7,7 @@
#include "../../hb-ot-hmtx-table.hh"
#include "../../hb-ot-var-gvar-table.hh"
#include "../../hb-draw.hh"
#include "../../hb-paint.hh"
#include "glyf-helpers.hh"
#include "Glyph.hh"
@ -42,14 +43,13 @@ struct glyf
bool serialize (hb_serialize_context_t *c,
Iterator it,
bool use_short_loca,
const hb_subset_plan_t *plan,
hb_font_t *font)
const hb_subset_plan_t *plan)
{
TRACE_SERIALIZE (this);
unsigned init_len = c->length ();
for (auto &_ : it)
if (unlikely (!_.serialize (c, use_short_loca, plan, font)))
if (unlikely (!_.serialize (c, use_short_loca, plan)))
return false;
/* 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> ();
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;
if (!c->plan->pinned_at_default)
if (c->plan->normalized_coords)
{
font = _create_font_for_instancing (c->plan);
if (unlikely (!font)) return false;
}
auto padded_offsets =
+ hb_iter (glyphs)
| hb_map (&glyf_impl::SubsetGlyph::padded_size)
;
hb_vector_t<unsigned> padded_offsets;
unsigned num_glyphs = c->plan->num_output_glyphs ();
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;
if (likely (!c->plan->force_long_loca))
{
unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
use_short_loca = max_offset < 0x1FFFF;
}
glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan, font);
if (!use_short_loca) {
padded_offsets =
+ hb_iter (glyphs)
| hb_map (&glyf_impl::SubsetGlyph::length)
;
for (unsigned i = 0; i < num_glyphs; i++)
padded_offsets[i] = glyphs[i].length ();
}
if (font)
{
_free_compiled_subset_glyphs (&glyphs);
hb_font_destroy (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, glyphs.length - 1);
if (!result) return false;
if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
padded_offsets,
padded_offsets.iter (),
use_short_loca)));
}
void
bool
_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
hb_font_t *
_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)
_.free_compiled_bytes ();
for (unsigned i = 0; i <= index && i < glyphs.length; i++)
glyphs[i].free_compiled_bytes ();
}
protected:
@ -193,7 +200,7 @@ struct glyf_accelerator_t
contour_point_vector_t all_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;
if (consumer.is_consuming_contour_points ())
@ -247,19 +254,14 @@ struct glyf_accelerator_t
extents->y_bearing = 0;
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->width = roundf (max_x - extents->x_bearing);
extents->y_bearing = roundf (max_y);
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);
}
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
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,
hb_font_t *font,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
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 ())
{
unsigned new_gid = p.second;
@ -401,7 +414,7 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
if (unlikely (new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
plan->pinned_at_default)
!plan->normalized_coords)
subset_glyph.source_glyph = glyf_impl::Glyph ();
else
{
@ -414,7 +427,20 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
subset_glyph.drop_hints_bytes ();
else
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 *
@ -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;
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;
for (auto _ : *plan->user_axes_location)
for (auto _ : plan->user_axes_location)
{
hb_variation_t var;
var.tag = _.first;
@ -436,7 +462,7 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
}
#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
return font;
}

View File

@ -26,22 +26,29 @@ struct path_builder_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)); }
} first_oncurve, first_offcurve, last_offcurve;
} first_oncurve, first_offcurve, last_offcurve, last_offcurve2;
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{
font = font_;
draw_session = &draw_session_;
first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
}
/* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
See also:
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
* https://stackoverflow.com/a/20772557 */
* https://stackoverflow.com/a/20772557
*
* Cubic support added (incomplete). */
void consume_point (const contour_point_t &point)
{
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));
if (!first_oncurve)
{
@ -69,16 +76,41 @@ struct path_builder_t
{
if (is_on_curve)
{
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
p.x, p.y);
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,
p.x, p.y);
last_offcurve = optional_point_t ();
}
else
{
optional_point_t mid = last_offcurve.lerp (p, .5f);
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = p;
if (is_cubic && !last_offcurve2)
{
last_offcurve2 = last_offcurve;
last_offcurve = p;
}
else
{
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,
mid.x, mid.y);
last_offcurve = p;
}
}
}
else
@ -105,8 +137,15 @@ struct path_builder_t
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
else if (last_offcurve && first_oncurve)
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
{
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,
first_oncurve.x, first_oncurve.y);
}
else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve)
@ -117,7 +156,7 @@ struct path_builder_t
}
/* 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 ();
}
}

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)
{
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++;
b++;
}
@ -700,6 +700,9 @@ struct graph_t
}
}
if (in_error ())
return false;
if (!made_changes)
return false;
@ -833,7 +836,11 @@ struct graph_t
if (index_map.has (node_idx))
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 ()) {
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
// 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);
return -1;
}
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u => %u",
parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx);
@ -981,7 +988,7 @@ struct graph_t
*/
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);
// 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

View File

@ -153,8 +153,8 @@ void print_overflows (graph_t& graph,
const auto& child = graph.vertices_[o.child];
DEBUG_MSG (SUBSET_REPACK, nullptr,
" overflow from "
"%4d (%4d in, %4d out, space %2d) => "
"%4d (%4d in, %4d out, space %2d)",
"%4u (%4u in, %4u out, space %2u) => "
"%4u (%4u in, %4u out, space %2u)",
o.parent,
parent.incoming_edges (),
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));
}
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

@ -7,6 +7,7 @@
#include "hb-buffer.cc"
#include "hb-common.cc"
#include "hb-draw.cc"
#include "hb-face-builder.cc"
#include "hb-face.cc"
#include "hb-fallback-shape.cc"
#include "hb-font.cc"
@ -40,6 +41,9 @@
#include "hb-ot-shaper-vowel-constraints.cc"
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
#include "hb-outline.cc"
#include "hb-paint-extents.cc"
#include "hb-paint.cc"
#include "hb-set.cc"
#include "hb-shape-plan.cc"
#include "hb-shape.cc"
@ -50,6 +54,7 @@
#include "hb-subset-cff1.cc"
#include "hb-subset-cff2.cc"
#include "hb-subset-input.cc"
#include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan.cc"
#include "hb-subset-repacker.cc"
#include "hb-subset.cc"

View File

@ -8,6 +8,7 @@
#include "hb-coretext.cc"
#include "hb-directwrite.cc"
#include "hb-draw.cc"
#include "hb-face-builder.cc"
#include "hb-face.cc"
#include "hb-fallback-shape.cc"
#include "hb-font.cc"
@ -45,6 +46,9 @@
#include "hb-ot-shaper-vowel-constraints.cc"
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
#include "hb-outline.cc"
#include "hb-paint-extents.cc"
#include "hb-paint.cc"
#include "hb-set.cc"
#include "hb-shape-plan.cc"
#include "hb-shape.cc"

View File

@ -28,6 +28,7 @@
#define HB_AAT_LAYOUT_COMMON_HH
#include "hb-aat-layout.hh"
#include "hb-aat-map.hh"
#include "hb-open-type.hh"
namespace OT {
@ -39,6 +40,43 @@ namespace AAT {
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
*/
@ -740,16 +778,44 @@ struct StateTableDriver
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t>
void drive (context_t *c)
void drive (context_t *c, hb_aat_apply_context_t *ac)
{
if (!c->in_place)
buffer->clear_output ();
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;)
{
/* 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 ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
machine.get_class (buffer->cur().codepoint, num_glyphs) :
(unsigned) StateTableT::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
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 */

View File

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

View File

@ -169,7 +169,7 @@ struct RearrangementSubtable
driver_context_t dc (this);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
driver.drive (&dc, c);
return_trace (dc.ret);
}
@ -325,7 +325,7 @@ struct ContextualSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
driver.drive (&dc, c);
return_trace (dc.ret);
}
@ -525,7 +525,7 @@ struct LigatureSubtable
if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
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 & LigActionLast));
if (action & (LigActionStore | LigActionLast))
@ -577,7 +577,7 @@ struct LigatureSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
driver.drive (&dc, c);
return_trace (dc.ret);
}
@ -618,8 +618,27 @@ struct NoncontextualSubtable
hb_glyph_info_t *info = c->buffer->info;
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++)
{
/* 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);
if (replacement)
{
@ -820,7 +839,7 @@ struct InsertionSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
driver.drive (&dc, c);
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.
// (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 };
if (map->features.bsearch (info))
if (map->current_features.bsearch (info))
{
flags &= feature.disableFlags;
flags |= feature.enableFlags;
@ -994,8 +1013,7 @@ struct Chain
return flags;
}
void apply (hb_aat_apply_context_t *c,
hb_mask_t flags) const
void apply (hb_aat_apply_context_t *c) const
{
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
unsigned int count = subtableCount;
@ -1003,8 +1021,10 @@ struct Chain
{
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;
c->subtable_flags = subtable->subFeatureFlags;
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@ -1043,7 +1063,7 @@ struct Chain
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
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;
if (reverse)
@ -1054,7 +1074,7 @@ struct Chain
if (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;
@ -1120,22 +1140,31 @@ struct mortmorx
{
const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount;
if (unlikely (!map->chain_flags.resize (count)))
return;
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);
}
}
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;
c->buffer->unsafe_to_concat ();
c->set_lookup_index (0);
const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount;
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;
chain = &StructAfter<Chain<Types>> (*chain);
}

View File

@ -244,15 +244,23 @@ hb_aat_layout_has_substitution (hb_face_t *face)
void
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
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 ();
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
if (morx.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
if (!buffer->message (font, "start table morx")) return;
morx.apply (&c);
morx.apply (&c, map);
(void) buffer->message (font, "end table morx");
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);
if (!buffer->message (font, "start table mort")) return;
mort.apply (&c);
mort.apply (&c, map);
(void) buffer->message (font, "end table mort");
return;
}

View File

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

View File

@ -36,27 +36,29 @@
#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 (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))
return;
feature_info_t *info = features.push();
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
info->setting = (hb_aat_layout_feature_selector_t) value;
info->seq = features.length;
info->is_exclusive = true;
feature_range_t *range = features.push();
range->start = feature.start;
range->end = feature.end;
range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
range->info.setting = (hb_aat_layout_feature_selector_t) feature.value;
range->info.seq = features.length;
range->info.is_exclusive = true;
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;
const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
if (!feature->has_data ())
const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType);
if (!feature_name->has_data ())
{
/* 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.
@ -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 &&
mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
{
feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
if (!feature->has_data ()) return;
feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
if (!feature_name->has_data ()) return;
}
else return;
}
feature_info_t *info = features.push();
info->type = mapping->aatFeatureType;
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
info->seq = features.length;
info->is_exclusive = feature->is_exclusive ();
feature_range_t *range = features.push();
range->start = feature.start;
range->end = feature.end;
range->info.type = mapping->aatFeatureType;
range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable;
range->info.seq = features.length;
range->info.is_exclusive = feature_name->is_exclusive ();
}
void
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
{
/* Sort features and merge duplicates */
if (features.length)
/* Compute active features per range, and compile each. */
/* 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 ();
unsigned int j = 0;
for (unsigned int i = 1; i < features.length; i++)
if (features[i].type != features[j].type ||
/* 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"
* (selectors referring to the same feature setting) here. */
(!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
features[++j] = features[i];
features.shrink (j + 1);
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;
}
hb_aat_layout_compile_map (this, &m);
/* 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;
for (unsigned int i = 1; i < current_features.length; i++)
if (current_features[i].type != current_features[j].type ||
/* 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"
* (selectors referring to the same feature setting) here. */
(!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1))))
current_features[++j] = current_features[i];
current_features.shrink (j + 1);
}
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;
public:
void init ()
struct range_flags_t
{
hb_memset (this, 0, sizeof (*this));
chain_flags.init ();
}
void fini () { chain_flags.fini (); }
hb_mask_t flags;
unsigned cluster_first;
unsigned cluster_last; // end - 1
};
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
@ -56,7 +55,7 @@ struct hb_aat_map_builder_t
face (face_),
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);
@ -78,7 +77,7 @@ struct hb_aat_map_builder_t
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
{
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:
hb_face_t *face;
hb_segment_properties_t props;
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

@ -875,7 +875,7 @@ hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
{
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && (__clang_major__ >= 8))
unsigned stack_result;
if (!result)
result = &stack_result;

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;
};
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)
{ return hb_array_t<T> (array, length); }
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_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_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (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_get_relaxed(AI) (reinterpret_cast<std::atomic<int> 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_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<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#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<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#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_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
/* 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
/* This we always use std::atomic for; and should never be disabled...
* except that MSVC gives me an internal compiler error on it. */
#if !defined(_MSC_VER)
#if defined(__ATOMIC_ACQUIRE) // gcc-like
#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
#elif !defined(_MSC_VER)
#include <atomic>
#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
#else
@ -145,15 +150,35 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#endif
#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 (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; }
#endif
#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 short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; }
#endif
#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; }
#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
{
hb_atomic_int_t () = default;

View File

@ -34,14 +34,24 @@
/* Compiler-assisted vectorization. */
/* 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>
struct hb_vector_size_t
{
elt_t& operator [] (unsigned int i) { 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>
hb_vector_size_t process (const Op& op) const
@ -79,10 +89,10 @@ struct hb_vector_size_t
struct hb_bit_page_t
{
void init0 () { v.clear (); }
void init1 () { v.clear (0xFF); }
void init0 () { v.init0 (); }
void init1 () { v.init1 (); }
constexpr unsigned len () const
static inline constexpr unsigned len ()
{ return ARRAY_LENGTH_CONST (v); }
bool is_empty () const
@ -300,10 +310,10 @@ struct hb_bit_page_t
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
typedef unsigned long long elt_t;
static constexpr unsigned PAGE_BITS = 512;
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
static constexpr unsigned PAGE_BITS_LOG_2 = 9;
static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits
static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2;
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 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;
}
bool is_inverted () const
{
return inverted;
}
bool is_empty () const
{
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 (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& 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; }
@ -85,12 +85,16 @@ struct hb_bit_set_t
void err () { if (successful) successful = false; } /* TODO Remove */
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 (!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;
return false;
}
@ -346,11 +350,11 @@ struct hb_bit_set_t
hb_codepoint_t c = first - 1;
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;
unsigned int count = other.pages.length;
if (unlikely (!resize (count, false)))
if (unlikely (!resize (count, false, exact_size)))
return;
population = other.population;
@ -422,7 +426,7 @@ struct hb_bit_set_t
private:
bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
{
if (unlikely (!workspace.resize (pages.length)))
if (unlikely (!workspace.resize_exact (pages.length)))
{
successful = 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);
if (unlikely (!wchar_file_name)) goto fail_without_close;
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 };
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
@ -697,7 +697,7 @@ 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;
GetFileSizeEx (fd, &length);
@ -710,7 +710,7 @@ fail_without_close:
#endif
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);
#else
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);

View File

@ -35,34 +35,34 @@
#line 33 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
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,
9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u,
120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u,
9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u,
9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u,
34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u,
9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u,
34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u,
9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u,
9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u,
9u, 123u, 0u, 0u, 0
};
static const char _deserialize_json_key_spans[] = {
0, 115, 26, 21, 2, 1, 50, 49,
10, 117, 117, 117, 1, 50, 49, 10,
117, 117, 1, 1, 50, 49, 117, 117,
2, 1, 50, 49, 10, 117, 117, 1,
50, 49, 10, 117, 117, 1, 1, 50,
49, 117, 117, 1, 50, 49, 59, 117,
59, 117, 117, 1, 50, 49, 117, 85,
10, 117, 117, 85, 117, 1, 50, 49,
10, 117, 117, 1, 1, 50, 49, 117,
117, 2, 1, 50, 49, 10, 117, 117,
1, 50, 49, 10, 117, 117, 1, 1,
50, 49, 117, 117, 1, 50, 49, 59,
117, 59, 117, 117, 1, 50, 49, 117,
115, 0
};
static const short _deserialize_json_index_offsets[] = {
0, 0, 116, 143, 165, 168, 170, 221,
271, 282, 400, 518, 636, 638, 689, 739,
750, 868, 986, 988, 990, 1041, 1091, 1209,
1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680,
1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034,
2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534,
2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169,
271, 282, 400, 518, 604, 722, 724, 775,
825, 836, 954, 1072, 1074, 1076, 1127, 1177,
1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648,
1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118,
2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560,
2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137,
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, 24, 1, 20,
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,
1, 1, 1, 1, 1, 24, 1, 25,
25, 25, 25, 25, 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, 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,
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, 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, 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, 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,
@ -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, 34, 1, 32, 32, 32,
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, 37, 1, 35, 35, 35, 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, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 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, 35, 1, 1, 1, 1, 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,
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, 37, 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, 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,
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,
@ -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, 45, 1,
43, 43, 43, 43, 43, 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, 40, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 41, 1, 1,
1, 43, 43, 43, 43, 43, 43, 43,
43, 43, 43, 1, 1, 1, 1, 1,
1, 1, 1, 44, 1, 1, 1, 46,
46, 46, 46, 46, 46, 46, 46, 46,
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,
@ -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, 42, 1,
44, 45, 1, 46, 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, 1,
1, 1, 1, 1, 45, 1, 47, 48,
1, 49, 1, 49, 49, 49, 49, 49,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 47, 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, 49, 1, 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, 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, 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, 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, 51, 1, 1, 52, 53, 53,
53, 53, 53, 53, 53, 53, 53, 1,
54, 55, 55, 55, 55, 55, 55, 55,
55, 55, 1, 56, 56, 56, 56, 56,
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, 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, 57, 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, 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, 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,
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, 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,
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, 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,
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, 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, 60, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 65, 1, 66,
1, 67, 1, 67, 67, 67, 67, 67,
61, 1, 1, 62, 63, 63, 63, 63,
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, 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, 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, 68, 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, 71,
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, 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, 66, 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, 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, 71, 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, 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,
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, 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, 71, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 73, 1, 75, 1, 75, 75,
75, 75, 75, 1, 1, 1, 1, 1,
1, 1, 1, 72, 73, 73, 73, 73,
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, 75, 1, 1,
1, 1, 1, 1, 1, 74, 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, 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,
76, 1, 77, 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, 83, 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, 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, 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, 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,
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, 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, 80,
1, 86, 86, 86, 86, 86, 1, 1,
1, 1, 1, 1, 1, 79, 1, 79,
79, 79, 79, 79, 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,
86, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 87, 1, 1, 1,
1, 1, 1, 1, 86, 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,
@ -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, 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, 86, 1,
1, 88, 1, 83, 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, 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, 89, 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, 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, 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,
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, 91, 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, 86, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 87,
1, 1, 1, 94, 94, 94, 94, 94,
1, 1, 1, 91, 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, 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,
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,
@ -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,
88, 1, 95, 95, 95, 95, 95, 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,
1, 1, 1, 1, 1, 1, 91, 1,
0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
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[] = {
1, 0, 2, 2, 3, 4, 18, 24,
37, 43, 51, 5, 12, 6, 7, 8,
9, 11, 9, 11, 10, 2, 55, 10,
55, 13, 14, 15, 16, 17, 16, 17,
10, 2, 55, 19, 20, 21, 22, 23,
10, 2, 55, 23, 25, 31, 26, 27,
28, 29, 30, 29, 30, 10, 2, 55,
32, 33, 34, 35, 36, 35, 36, 10,
2, 55, 38, 39, 40, 41, 42, 10,
2, 55, 42, 44, 45, 46, 49, 50,
46, 47, 48, 10, 2, 55, 10, 2,
55, 50, 52, 53, 49, 54, 54, 55,
56, 57
1, 0, 2, 2, 3, 4, 19, 25,
38, 44, 52, 5, 13, 6, 7, 8,
9, 12, 9, 12, 10, 2, 11, 10,
11, 11, 56, 57, 14, 15, 16, 17,
18, 17, 18, 10, 2, 11, 20, 21,
22, 23, 24, 10, 2, 11, 24, 26,
32, 27, 28, 29, 30, 31, 30, 31,
10, 2, 11, 33, 34, 35, 36, 37,
36, 37, 10, 2, 11, 39, 40, 41,
42, 43, 10, 2, 11, 43, 45, 46,
47, 50, 51, 47, 48, 49, 10, 2,
11, 10, 2, 11, 51, 53, 54, 50,
55, 55
};
static const char _deserialize_json_trans_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2,
2, 2, 0, 0, 3, 3, 4, 0,
5, 0, 0, 2, 2, 2, 0, 0,
6, 6, 7, 0, 0, 0, 2, 2,
8, 8, 9, 0, 0, 0, 0, 0,
2, 2, 2, 0, 0, 10, 10, 11,
0, 0, 2, 2, 2, 0, 0, 12,
12, 13, 0, 0, 0, 2, 2, 14,
14, 15, 0, 0, 0, 2, 16, 16,
0, 17, 0, 18, 18, 19, 20, 20,
21, 17, 0, 0, 22, 22, 23, 0,
0, 0
5, 0, 0, 0, 0, 0, 2, 2,
2, 0, 0, 6, 6, 7, 0, 0,
0, 2, 2, 8, 8, 9, 0, 0,
0, 0, 0, 2, 2, 2, 0, 0,
10, 10, 11, 0, 0, 2, 2, 2,
0, 0, 12, 12, 13, 0, 0, 0,
2, 2, 14, 14, 15, 0, 0, 0,
2, 16, 16, 0, 17, 0, 18, 18,
19, 20, 20, 21, 17, 0, 0, 22,
22, 23
};
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_en_main = 1;
@ -548,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? ',' : '['))
{
*end_ptr = ++p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {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;
}
#line 557 "hb-buffer-deserialize-json.hh"
#line 555 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
@ -774,7 +772,7 @@ _resume:
*end_ptr = p;
}
break;
#line 735 "hb-buffer-deserialize-json.hh"
#line 733 "hb-buffer-deserialize-json.hh"
}
_again:
@ -786,7 +784,7 @@ _again:
_out: {}
}
#line 139 "hb-buffer-deserialize-json.rl"
#line 137 "hb-buffer-deserialize-json.rl"
*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 36 "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 353 "hb-buffer-deserialize-text-glyphs.hh"
{
cs = deserialize_text_glyphs_start;
}
#line 358 "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 554 "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 671 "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-text.hh"
#include "hb-buffer-deserialize-text-glyphs.hh"
#include "hb-buffer-deserialize-text-unicode.hh"
/**
* 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
* 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
**/
@ -779,9 +781,9 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
switch (format)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_deserialize_text (buffer,
buf, buf_len, end_ptr,
font);
return _hb_buffer_deserialize_text_glyphs (buffer,
buf, buf_len, end_ptr,
font);
case HB_BUFFER_SERIALIZE_FORMAT_JSON:
return _hb_buffer_deserialize_json (buffer,
@ -808,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
* Deserializes Unicode @buffer from textual representation in the format
* 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
**/
@ -849,9 +852,9 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
switch (format)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_deserialize_text (buffer,
buf, buf_len, end_ptr,
font);
return _hb_buffer_deserialize_text_unicode (buffer,
buf, buf_len, end_ptr,
font);
case HB_BUFFER_SERIALIZE_FORMAT_JSON:
return _hb_buffer_deserialize_json (buffer,

View File

@ -150,7 +150,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
assert (text_start < text_end);
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);
@ -292,7 +292,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
assert (text_start < text_end);
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
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);
/* Extend end */
while (end < len && info[end - 1].cluster == info[end].cluster)
end++;
if (cluster != info[end - 1].cluster)
while (end < len && info[end - 1].cluster == info[end].cluster)
end++;
/* Extend start */
while (idx < start && info[start - 1].cluster == info[start].cluster)
start--;
if (cluster != info[start].cluster)
while (idx < start && info[start - 1].cluster == info[start].cluster)
start--;
/* 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--)
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
* 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
**/
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"
#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) == sizeof (hb_glyph_position_t)), "");
@ -601,21 +581,59 @@ struct hb_buffer_t
unsigned int cluster,
hb_mask_t mask)
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster)
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++)
if (cluster != infos[i].cluster)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask;
}
return;
}
/* 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;
}
}
}
static unsigned
unsigned
_infos_find_min_cluster (const hb_glyph_info_t *infos,
unsigned start, unsigned end,
unsigned cluster = UINT_MAX)
{
for (unsigned int i = start; i < end; i++)
cluster = hb_min (cluster, infos[i].cluster);
return cluster;
if (unlikely (start == end))
return cluster;
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{
for (unsigned int i = start; i < end; i++)
cluster = hb_min (cluster, infos[i].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)

View File

@ -39,7 +39,9 @@ template <unsigned int key_bits=16,
struct hb_cache_t
{
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,
short,
int>::type
@ -48,8 +50,9 @@ struct hb_cache_t
static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
hb_cache_t () { init (); }
void init () { clear (); }
void fini () {}
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
src/3rdparty/harfbuzz-ng/src/hb-cairo.cc vendored Normal file

File diff suppressed because it is too large Load Diff

99
src/3rdparty/harfbuzz-ng/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;
op_code_t op;
op_code_t op = OpCode_Invalid;
uint8_t length = 0;
};
@ -522,20 +522,10 @@ struct parsed_values_t
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 ())
{
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)
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 (v);
val->op = op;

View File

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

View File

@ -35,10 +35,8 @@ using namespace OT;
/* an opstr and the parsed out dict value(s) */
struct dict_val_t : op_str_t
{
void init () { single_val.set_int (0); }
void init () {}
void fini () {}
number_t single_val;
};
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>
{
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)
{
processed_width = false;

View File

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

View File

@ -29,32 +29,6 @@
#include "hb.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

View File

@ -897,6 +897,32 @@ HB_EXTERN uint8_t
hb_color_get_blue (hb_color_t color);
#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
#endif /* HB_COMMON_H */

View File

@ -37,6 +37,7 @@
#ifndef HB_EXPERIMENTAL_API
#define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES
#endif
@ -80,9 +81,10 @@
#define HB_NO_MMAP
#define HB_NO_NAME
#define HB_NO_OPEN
#define HB_NO_SETLOCALE
#define HB_NO_OT_FONT_GLYPH_NAMES
#define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_PAINT
#define HB_NO_SETLOCALE
#define HB_NO_STYLE
#define HB_NO_SUBSET_LAYOUT
#define HB_NO_VERTICAL

View File

@ -511,7 +511,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
buffer->merge_clusters (i - 1, i + 1);
}
hb_vector_t<feature_record_t> feature_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 (shape_plan);
HB_DEFINE_VTABLE (unicode_funcs);
HB_DEFINE_VTABLE (draw_funcs);
HB_DEFINE_VTABLE (paint_funcs);
#undef HB_DEFINE_VTABLE

View File

@ -113,7 +113,7 @@ _hb_print_func (const char *func)
const char *paren = strchr (func, '(');
if (paren)
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 : "");
if (obj)
fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj);
else
fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
fprintf (stderr, " %*s ", (int) (2 * sizeof (void *)), "");
if (indented) {
#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,
"return %s (line %d)",
"return %s (line %u)",
hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
if (plevel) --*plevel;
plevel = nullptr;
@ -396,7 +396,7 @@ struct hb_no_trace_t {
#define TRACE_APPLY(this) \
hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
(&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)
#else
#define TRACE_APPLY(this) hb_no_trace_t<bool> trace
@ -454,7 +454,7 @@ struct hb_no_trace_t {
#define TRACE_DISPATCH(this, format) \
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
"format %d", (int) format)
"format %u", (unsigned) format)
#else
#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
#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,
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_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);

View File

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

View File

@ -35,6 +35,8 @@
* @include: hb.h
*
* Functions for drawing (extracting) glyph shapes.
*
* The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph().
**/
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)
* @dfuncs: draw functions
*
* Increases the reference count on @dfuncs by one. This prevents @buffer from
* being destroyed until a matching call to hb_draw_funcs_destroy() is made.
* Increases the reference count on @dfuncs by one.
*
* This prevents @dfuncs from being destroyed until a matching
* call to hb_draw_funcs_destroy() is made.
*
* Return value: (transfer full):
* The referenced #hb_draw_funcs_t.
@ -246,6 +264,49 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *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:
* @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:
* @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
* @to_x: X 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
* 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:
* @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
* @to_x: X 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
* 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:
* @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
* @control_x: X component of control point
* @control_y: Y component of control point
* @to_x: X 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
* 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:
* @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
* @control1_x: X 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
* @to_x: X 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
* 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:
* @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
* @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
* operation.
@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs,
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_create (void);
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_get_empty (void);
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
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_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-ot-face.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.
*
* This API is used in rare circumstances.
*
* Since: 0.9.2
**/
void
@ -488,7 +489,10 @@ hb_face_set_upem (hb_face_t *face,
* hb_face_get_upem:
* @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
*
@ -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.
*
* This API is used in rare circumstances.
*
* Since: 0.9.7
**/
void
@ -581,7 +587,7 @@ hb_face_get_table_tags (const hb_face_t *face,
/**
* hb_face_collect_unicodes:
* @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
* 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 ());
}
/**
* 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:
* @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
* 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:
* @face: A face object
* @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
* 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);
}
#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-blob.h"
#include "hb-map.h"
#include "hb-set.h"
HB_BEGIN_DECLS
@ -149,6 +150,11 @@ HB_EXTERN void
hb_face_collect_unicodes (hb_face_t *face,
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_face_collect_variation_selectors (hb_face_t *face,
hb_set_t *out);

View File

@ -30,6 +30,7 @@
#include "hb-font.hh"
#include "hb-draw.hh"
#include "hb-paint.hh"
#include "hb-machinery.hh"
#include "hb-ot.h"
@ -503,23 +504,34 @@ hb_font_get_glyph_from_name_default (hb_font_t *font,
}
static void
hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs,
void *draw_data,
void *user_data HB_UNUSED)
hb_font_draw_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs,
void *draw_data,
void *user_data HB_UNUSED)
{
}
static void
hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph HB_UNUSED,
hb_paint_funcs_t *paint_funcs HB_UNUSED,
void *paint_data HB_UNUSED,
unsigned int palette HB_UNUSED,
hb_color_t foreground HB_UNUSED,
void *user_data HB_UNUSED)
{
}
typedef struct hb_font_get_glyph_shape_default_adaptor_t {
typedef struct hb_font_draw_glyph_default_adaptor_t {
hb_draw_funcs_t *draw_funcs;
void *draw_data;
float x_scale;
float y_scale;
float slant;
} hb_font_get_glyph_shape_default_adaptor_t;
} hb_font_draw_glyph_default_adaptor_t;
static void
hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
@ -528,7 +540,7 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@ -543,7 +555,7 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@ -562,7 +574,7 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@ -583,7 +595,7 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@ -602,7 +614,7 @@ hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_draw_state_t *st,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st);
}
@ -618,14 +630,14 @@ static const hb_draw_funcs_t _hb_draw_funcs_default = {
};
static void
hb_font_get_glyph_shape_default (hb_font_t *font,
hb_font_draw_glyph_default (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs,
void *draw_data,
void *user_data HB_UNUSED)
{
hb_font_get_glyph_shape_default_adaptor_t adaptor = {
hb_font_draw_glyph_default_adaptor_t adaptor = {
draw_funcs,
draw_data,
font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
@ -634,11 +646,34 @@ hb_font_get_glyph_shape_default (hb_font_t *font,
(float) font->x_scale / (float) font->parent->y_scale : 0.f
};
font->parent->get_glyph_shape (glyph,
font->parent->draw_glyph (glyph,
const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default),
&adaptor);
}
static void
hb_font_paint_glyph_default (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
hb_paint_funcs_t *paint_funcs,
void *paint_data,
unsigned int palette,
hb_color_t foreground,
void *user_data)
{
paint_funcs->push_transform (paint_data,
font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
font->parent->y_scale ? (font->slant - font->parent->slant) *
(float) font->x_scale / (float) font->parent->y_scale : 0.f,
0.f,
font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
0.f, 0.f);
font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground);
paint_funcs->pop_transform (paint_data);
}
DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
@ -647,7 +682,7 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
nullptr,
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_nil,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
@ -661,7 +696,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = {
nullptr,
{
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default,
#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_default,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
@ -739,7 +774,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
if (ffuncs->destroy)
{
#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \
#define HB_FONT_FUNC_IMPLEMENT(get_,name) if (ffuncs->destroy->name) \
ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name);
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
@ -879,11 +914,11 @@ fail:
return false;
}
#define HB_FONT_FUNC_IMPLEMENT(name) \
#define HB_FONT_FUNC_IMPLEMENT(get_,name) \
\
void \
hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
hb_font_get_##name##_func_t func, \
hb_font_##get_##name##_func_t func, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
@ -899,7 +934,7 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
if (func) \
ffuncs->get.f.name = func; \
else \
ffuncs->get.f.name = hb_font_get_##name##_default; \
ffuncs->get.f.name = hb_font_##get_##name##_default; \
\
if (ffuncs->user_data) \
ffuncs->user_data->name = user_data; \
@ -1026,7 +1061,8 @@ hb_font_get_nominal_glyph (hb_font_t *font,
* @glyph_stride: The stride between successive glyph IDs
*
* Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
* IDs must be returned in a #hb_codepoint_t output parameter.
* IDs must be returned in a #hb_codepoint_t output parameter. Stopes at the
* first unsupported glyph ID.
*
* Return value: the number of code points processed
*
@ -1308,6 +1344,9 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
*
* Fetches the glyph-name string for a glyph ID in the specified @font.
*
* According to the OpenType specification, glyph names are limited to 63
* characters and can only contain (a subset of) ASCII.
*
* Return value: `true` if data found, `false` otherwise
*
* Since: 0.9.2
@ -1357,13 +1396,67 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* objects, with @draw_data passed to them.
*
* Since: 4.0.0
**/
* Deprecated: 7.0.0: Use hb_font_draw_glyph() instead
*/
void
hb_font_get_glyph_shape (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data)
{
hb_font_draw_glyph (font, glyph, dfuncs, draw_data);
}
/**
* hb_font_draw_glyph:
* @font: #hb_font_t to work upon
* @glyph: : The glyph ID
* @dfuncs: #hb_draw_funcs_t to draw to
* @draw_data: User data to pass to draw callbacks
*
* Draws the outline that corresponds to a glyph in the specified @font.
*
* The outline is returned by way of calls to the callbacks of the @dfuncs
* objects, with @draw_data passed to them.
*
* Since: 7.0.0
**/
void
hb_font_draw_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data)
{
font->get_glyph_shape (glyph, dfuncs, draw_data);
font->draw_glyph (glyph, dfuncs, draw_data);
}
/**
* hb_font_paint_glyph:
* @font: #hb_font_t to work upon
* @glyph: The glyph ID
* @pfuncs: #hb_paint_funcs_t to paint with
* @paint_data: User data to pass to paint callbacks
* @palette_index: The index of the font's color palette to use
* @foreground: The foreground color, unpremultipled
*
* Paints the glyph.
*
* The painting instructions are returned by way of calls to
* the callbacks of the @funcs object, with @paint_data passed
* to them.
*
* If the font has color palettes (see hb_ot_color_has_palettes()),
* then @palette_index selects the palette to use. If the font only
* has one palette, this will be 0.
*
* Since: 7.0.0
*/
void
hb_font_paint_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_paint_funcs_t *pfuncs, void *paint_data,
unsigned int palette_index,
hb_color_t foreground)
{
font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground);
}
/* A bit higher-level, and with fallback */
@ -1624,6 +1717,9 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
* If the glyph ID has no name in @font, a string of the form `gidDDD` is
* generated, with `DDD` being the glyph ID.
*
* According to the OpenType specification, glyph names are limited to 63
* characters and can only contain (a subset of) ASCII.
*
* Since: 0.9.2
**/
void
@ -1677,8 +1773,13 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
1000, /* x_scale */
1000, /* y_scale */
0., /* slant */
0., /* slant_xy; */
0.f, /* x_embolden */
0.f, /* y_embolden */
true, /* embolden_in_place */
0, /* x_strength */
0, /* y_strength */
0.f, /* slant */
0.f, /* slant_xy; */
1.f, /* x_multf */
1.f, /* y_multf */
1<<16, /* x_mult */
@ -1688,6 +1789,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
0, /* y_ppem */
0, /* ptem */
HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */
0, /* num_coords */
nullptr, /* coords */
nullptr, /* design_coords */
@ -1715,8 +1817,10 @@ _hb_font_create (hb_face_t *face)
font->klass = hb_font_funcs_get_empty ();
font->data.init0 (font);
font->x_scale = font->y_scale = face->get_upem ();
font->embolden_in_place = true;
font->x_multf = font->y_multf = 1.f;
font->x_mult = font->y_mult = 1 << 16;
font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE;
return font;
}
@ -1798,6 +1902,9 @@ hb_font_create_sub_font (hb_font_t *parent)
font->x_scale = parent->x_scale;
font->y_scale = parent->y_scale;
font->x_embolden = parent->x_embolden;
font->y_embolden = parent->y_embolden;
font->embolden_in_place = parent->embolden_in_place;
font->slant = parent->slant;
font->x_ppem = parent->x_ppem;
font->y_ppem = parent->y_ppem;
@ -2187,6 +2294,31 @@ hb_font_set_funcs_data (hb_font_t *font,
*
* Sets the horizontal and vertical scale of a font.
*
* The font scale is a number related to, but not the same as,
* font size. Typically the client establishes a scale factor
* to be used between the two. For example, 64, or 256, which
* would be the fractional-precision part of the font scale.
* This is necessary because #hb_position_t values are integer
* types and you need to leave room for fractional values
* in there.
*
* For example, to set the font size to 20, with 64
* levels of fractional precision you would call
* `hb_font_set_scale(font, 20 * 64, 20 * 64)`.
*
* In the example above, even what font size 20 means is up to
* you. It might be 20 pixels, or 20 points, or 20 millimeters.
* HarfBuzz does not care about that. You can set the point
* size of the font using hb_font_set_ptem(), and the pixel
* size using hb_font_set_ppem().
*
* The choice of scale is yours but needs to be consistent between
* what you set here, and what you expect out of #hb_position_t
* as well has draw / paint API output values.
*
* Fonts default to a scale equal to the UPEM value of their face.
* A font with this setting is sometimes called an "unscaled" font.
*
* Since: 0.9.2
**/
void
@ -2232,7 +2364,11 @@ hb_font_get_scale (hb_font_t *font,
* @x_ppem: Horizontal ppem value to assign
* @y_ppem: Vertical ppem value to assign
*
* Sets the horizontal and vertical pixels-per-em (ppem) of a font.
* Sets the horizontal and vertical pixels-per-em (PPEM) of a font.
*
* These values are used for pixel-size-specific adjustment to
* shaping and draw results, though for the most part they are
* unused and can be left unset.
*
* Since: 0.9.2
**/
@ -2316,6 +2452,76 @@ hb_font_get_ptem (hb_font_t *font)
return font->ptem;
}
/**
* hb_font_set_synthetic_bold:
* @font: #hb_font_t to work upon
* @x_embolden: the amount to embolden horizontally
* @y_embolden: the amount to embolden vertically
* @in_place: whether to embolden glyphs in-place
*
* Sets the "synthetic boldness" of a font.
*
* Positive values for @x_embolden / @y_embolden make a font
* bolder, negative values thinner. Typical values are in the
* 0.01 to 0.05 range. The default value is zero.
*
* Synthetic boldness is applied by offsetting the contour
* points of the glyph shape.
*
* Synthetic boldness is applied when rendering a glyph via
* hb_font_draw_glyph().
*
* If @in_place is `false`, then glyph advance-widths are also
* adjusted, otherwise they are not. The in-place mode is
* useful for simulating [font grading](https://fonts.google.com/knowledge/glossary/grade).
*
*
* Since: 7.0.0
**/
void
hb_font_set_synthetic_bold (hb_font_t *font,
float x_embolden,
float y_embolden,
hb_bool_t in_place)
{
if (hb_object_is_immutable (font))
return;
if (font->x_embolden == x_embolden &&
font->y_embolden == y_embolden &&
font->embolden_in_place == (bool) in_place)
return;
font->serial++;
font->x_embolden = x_embolden;
font->y_embolden = y_embolden;
font->embolden_in_place = in_place;
font->mults_changed ();
}
/**
* hb_font_get_synthetic_bold:
* @font: #hb_font_t to work upon
* @x_embolden: (out): return location for horizontal value
* @y_embolden: (out): return location for vertical value
* @in_place: (out): return location for in-place value
*
* Fetches the "synthetic boldness" parameters of a font.
*
* Since: 7.0.0
**/
void
hb_font_get_synthetic_bold (hb_font_t *font,
float *x_embolden,
float *y_embolden,
hb_bool_t *in_place)
{
if (x_embolden) *x_embolden = font->x_embolden;
if (y_embolden) *y_embolden = font->y_embolden;
if (in_place) *in_place = font->embolden_in_place;
}
/**
* hb_font_set_synthetic_slant:
* @font: #hb_font_t to work upon
@ -2328,9 +2534,8 @@ hb_font_get_ptem (hb_font_t *font)
* HarfBuzz needs to know this value to adjust shaping results,
* metrics, and style values to match the slanted rendering.
*
* <note>Note: The glyph shape fetched via the
* hb_font_get_glyph_shape() is slanted to reflect this value
* as well.</note>
* <note>Note: The glyph shape fetched via the hb_font_draw_glyph()
* function is slanted to reflect this value as well.</note>
*
* <note>Note: The slant value is a ratio. For example, a
* 20% slant would be represented as a 0.2 value.</note>
@ -2397,7 +2602,7 @@ hb_font_set_variations (hb_font_t *font,
font->serial_coords = ++font->serial;
if (!variations_length)
if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE)
{
hb_font_set_var_coords_normalized (font, nullptr, 0);
return;
@ -2417,9 +2622,18 @@ hb_font_set_variations (hb_font_t *font,
return;
}
/* Initialize design coords to default from fvar. */
/* Initialize design coords. */
for (unsigned int i = 0; i < coords_length; i++)
design_coords[i] = axes[i].get_default ();
if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE)
{
unsigned count = coords_length;
/* This may fail if index is out-of-range;
* That's why we initialize design_coords from fvar above
* unconditionally. */
hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index,
&count, design_coords);
}
for (unsigned int i = 0; i < variations_length; i++)
{
@ -2427,13 +2641,11 @@ hb_font_set_variations (hb_font_t *font,
const auto v = variations[i].value;
for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
if (axes[axis_index].axisTag == tag)
{
design_coords[axis_index] = v;
normalized[axis_index] = fvar.normalize_axis_value (axis_index, v);
}
}
font->face->table.avar->map_coords (normalized, coords_length);
hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
}
@ -2484,28 +2696,40 @@ hb_font_set_var_coords_design (hb_font_t *font,
* @font: a font.
* @instance_index: named instance index.
*
* Sets design coords of a font from a named instance index.
* Sets design coords of a font from a named-instance index.
*
* Since: 2.6.0
*/
void
hb_font_set_var_named_instance (hb_font_t *font,
unsigned instance_index)
unsigned int instance_index)
{
if (hb_object_is_immutable (font))
return;
font->serial_coords = ++font->serial;
unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
if (unlikely (coords_length && !coords))
if (font->instance_index == instance_index)
return;
hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
hb_font_set_var_coords_design (font, coords, coords_length);
hb_free (coords);
font->serial_coords = ++font->serial;
font->instance_index = instance_index;
hb_font_set_variations (font, nullptr, 0);
}
/**
* hb_font_get_var_named_instance:
* @font: a font.
*
* Returns the currently-set named-instance index of the font.
*
* Return value: Named-instance index or %HB_FONT_NO_VAR_NAMED_INSTANCE.
*
* Since: 7.0.0
**/
unsigned int
hb_font_get_var_named_instance (hb_font_t *font)
{
return font->instance_index;
}
/**
@ -2754,3 +2978,13 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
trampoline_destroy);
}
#endif
void
hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_shape_func_t func,
void *user_data,
hb_destroy_func_t destroy /* May be NULL. */)
{
hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
}

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