/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2020 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): Calder Kitagawa
*/
#ifndef OT_COLOR_COLR_COLR_HH
#define OT_COLOR_COLR_COLR_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
* https://docs.microsoft.com/en-us/typography/opentype/spec/colr
*/
#define HB_OT_TAG_COLR HB_TAG(
'C' ,
'O' ,
'L' ,
'R' )
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>
{
const char *get_name () {
return "PAINT" ; }
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;
ItemVarStoreInstancer &instancer;
hb_map_t current_glyphs;
hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_MAX_GRAPH_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_,
ItemVarStoreInstancer &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>
{
template <
typename T>
return_t dispatch (
const T &obj)
{
if (unlikely (nesting_level_left == 0))
return hb_empty_t ();
if (paint_visited (&obj))
return hb_empty_t ();
nesting_level_left--;
obj.closurev1 (
this );
nesting_level_left++;
return hb_empty_t ();
}
static return_t default_return_value () {
return hb_empty_t (); }
bool paint_visited (
const void *paint)
{
hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
if (visited_paint.in_error() || visited_paint.has (delta))
return true ;
visited_paint.add (delta);
return false ;
}
const COLR* get_colr_table ()
const
{
return reinterpret_cast <
const COLR *> (base); }
void add_glyph (
unsigned glyph_id)
{ glyphs->add (glyph_id); }
void add_layer_indices (
unsigned first_layer_index,
unsigned num_of_layers)
{ layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
void add_palette_index (
unsigned palette_index)
{ palette_indices->add (palette_index); }
void add_var_idxes (
unsigned first_var_idx,
unsigned num_idxes)
{
if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION)
return ;
variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1);
}
public :
const void *base;
hb_set_t visited_paint;
hb_set_t *glyphs;
hb_set_t *layer_indices;
hb_set_t *palette_indices;
hb_set_t *variation_indices;
unsigned num_var_idxes;
unsigned nesting_level_left;
hb_colrv1_closure_context_t (
const void *base_,
hb_set_t *glyphs_,
hb_set_t *layer_indices_,
hb_set_t *palette_indices_,
hb_set_t *variation_indices_,
unsigned num_var_idxes_ = 1,
unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
base (base_),
glyphs (glyphs_),
layer_indices (layer_indices_),
palette_indices (palette_indices_),
variation_indices (variation_indices_),
num_var_idxes (num_var_idxes_),
nesting_level_left (nesting_level_left_)
{}
};
struct LayerRecord
{
operator hb_ot_color_layer_t ()
const {
return {glyphId, colorIdx}; }
bool sanitize (hb_sanitize_context_t *c)
const
{
TRACE_SANITIZE (
this );
return_trace (c->check_struct (
this ));
}
public :
HBGlyphID16 glyphId;
/* Glyph ID of layer glyph */
Index colorIdx;
/* Index value to use with a
* selected color palette.
* An index value of 0xFFFF
* is a special case indicating
* that the text foreground
* color (defined by a
* higher-level client) should
* be used and shall not be
* treated as actual index
* into CPAL ColorRecord array. */
public :
DEFINE_SIZE_STATIC (4);
};
struct BaseGlyphRecord
{
int cmp (hb_codepoint_t g)
const
{
return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
bool sanitize (hb_sanitize_context_t *c)
const
{
TRACE_SANITIZE (
this );
return_trace (c->check_struct (
this ));
}
public :
HBGlyphID16 glyphId;
/* Glyph ID of reference glyph */
HBUINT16 firstLayerIdx;
/* Index (from beginning of
* the Layer Records) to the
* layer record. There will be
* numLayers consecutive entries
* for this base glyph. */
HBUINT16 numLayers;
/* Number of color layers
* associated with this glyph */
public :
DEFINE_SIZE_STATIC (6);
};
template <
typename T>
struct Variable
{
static constexpr
bool is_variable =
true ;
Variable<T>* copy (hb_serialize_context_t *c)
const
{
TRACE_SERIALIZE (
this );
return_trace (c->embed (
this ));
}
void closurev1 (hb_colrv1_closure_context_t* c)
const
{
c->num_var_idxes = 0;
// update c->num_var_idxes during value closure
value.closurev1 (c);
c->add_var_idxes (varIdxBase, c->num_var_idxes);
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer)
const
{
TRACE_SUBSET (
this );
if (!value.subset (c, instancer, varIdxBase)) return_trace (
false );
if (c->plan->all_axes_pinned)
return_trace (
true );
VarIdx new_varidx;
new_varidx = varIdxBase;
if (varIdxBase != VarIdx::NO_VARIATION)
{
hb_pair_t<
unsigned ,
int > *new_varidx_delta;
if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta))
return_trace (
false );
new_varidx = hb_first (*new_varidx_delta);
}
return_trace (c->serializer->embed (new_varidx));
}
bool sanitize (hb_sanitize_context_t *c)
const
{
TRACE_SANITIZE (
this );
return_trace (c->check_struct (
this ) && value.sanitize (c));
}
void paint_glyph (hb_paint_context_t *c)
const
{
TRACE_PAINT (
this );
value.paint_glyph (c, varIdxBase);
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
const ItemVarStoreInstancer &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 :
VarIdx varIdxBase;
public :
DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
};
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
{
TRACE_SERIALIZE (
this );
return_trace (c->embed (
this ));
}
void closurev1 (hb_colrv1_closure_context_t* c)
const
{ value.closurev1 (c); }
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer)
const
{
TRACE_SUBSET (
this );
return_trace (value.subset (c, instancer, varIdxBase));
}
bool sanitize (hb_sanitize_context_t *c)
const
{
TRACE_SANITIZE (
this );
return_trace (c->check_struct (
this ) && value.sanitize (c));
}
void paint_glyph (hb_paint_context_t *c)
const
{
TRACE_PAINT (
this );
value.paint_glyph (c, varIdxBase);
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
const ItemVarStoreInstancer &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_MIN (T::min_size);
};
// Color structures
struct ColorStop
{
void closurev1 (hb_colrv1_closure_context_t* c)
const
{
c->add_palette_index (paletteIndex);
c->num_var_idxes = 2;
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase)
const
{
TRACE_SUBSET (
this );
auto *out = c->serializer->embed (*
this );
if (unlikely (!out)) return_trace (
false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
}
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get
(paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ));
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *out,
uint32_t varIdx,
const ItemVarStoreInstancer &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;
public :
DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
};
struct Extend : HBUINT8
{
enum {
EXTEND_PAD = 0,
EXTEND_REPEAT = 1,
EXTEND_REFLECT = 2,
};
public :
DEFINE_SIZE_STATIC (1);
};
template <template <typename > class Var>
struct ColorLine
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{
for (const auto &stop : stops.iter ())
stop.closurev1 (c);
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->start_embed (this );
if (unlikely (!c->serializer->extend_min (out))) return_trace (false );
if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false );
if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false );
for (const auto & stop : stops.iter ())
{
if (!stop.subset (c, instancer)) return_trace (false );
}
return_trace (true );
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) &&
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 ItemVarStoreInstancer &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 :
DEFINE_SIZE_ARRAY_SIZED (3, stops);
};
// Composition modes
// Compositing modes are taken from https://www.w3.org/TR/compositing-1/
// NOTE: a brief audit of major implementations suggests most support most
// or all of the specified modes.
struct CompositeMode : HBUINT8
{
enum {
// Porter-Duff modes
// https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
// Blend modes
// https://www.w3.org/TR/compositing-1/#blending
COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen
COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay
COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken
COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten
COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge
COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn
COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight
COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight
COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference
COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion
COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply
// Modes that, uniquely, do not operate on components
// https://www.w3.org/TR/compositing-1/#blendingnonseparable
COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue
COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation
COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor
COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity
};
public :
DEFINE_SIZE_STATIC (1);
};
struct Affine2x3
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ));
}
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->num_var_idxes = 6; }
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (*this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
}
return_trace (true );
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
F16DOT16 yy;
F16DOT16 dx;
F16DOT16 dy;
public :
DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
};
struct PaintColrLayers
{
void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
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),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
return_trace (true );
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
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 */
public :
DEFINE_SIZE_STATIC (6);
};
struct PaintSolid
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{
c->add_palette_index (paletteIndex);
c->num_var_idxes = 1;
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (*this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
if (format == 3 && c->plan->all_axes_pinned)
out->format = 2;
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
public :
DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
};
template <template <typename > class Var>
struct PaintLinearGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{
(this +colorLine).closurev1 (c);
c->num_var_idxes = 6;
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->x0 = x0 + (int ) roundf (instancer (varIdxBase, 0));
out->y0 = y0 + (int ) roundf (instancer (varIdxBase, 1));
out->x1 = x1 + (int ) roundf (instancer (varIdxBase, 2));
out->y1 = y1 + (int ) roundf (instancer (varIdxBase, 3));
out->x2 = x2 + (int ) roundf (instancer (varIdxBase, 4));
out->y2 = y2 + (int ) roundf (instancer (varIdxBase, 5));
}
if (format == 5 && c->plan->all_axes_pinned)
out->format = 4;
return_trace (out->colorLine.serialize_subset (c, colorLine, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && colorLine.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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. */
FWORD x0;
FWORD y0;
FWORD x1;
FWORD y1;
FWORD x2;
FWORD y2;
public :
DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
};
template <template <typename > class Var>
struct PaintRadialGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{
(this +colorLine).closurev1 (c);
c->num_var_idxes = 6;
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->x0 = x0 + (int ) roundf (instancer (varIdxBase, 0));
out->y0 = y0 + (int ) roundf (instancer (varIdxBase, 1));
out->radius0 = radius0 + (unsigned ) roundf (instancer (varIdxBase, 2));
out->x1 = x1 + (int ) roundf (instancer (varIdxBase, 3));
out->y1 = y1 + (int ) roundf (instancer (varIdxBase, 4));
out->radius1 = radius1 + (unsigned ) roundf (instancer (varIdxBase, 5));
}
if (format == 7 && c->plan->all_axes_pinned)
out->format = 6;
return_trace (out->colorLine.serialize_subset (c, colorLine, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && colorLine.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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. */
FWORD x0;
FWORD y0;
UFWORD radius0;
FWORD x1;
FWORD y1;
UFWORD radius1;
public :
DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
};
template <template <typename > class Var>
struct PaintSweepGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{
(this +colorLine).closurev1 (c);
c->num_var_idxes = 4;
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->centerX = centerX + (int ) roundf (instancer (varIdxBase, 0));
out->centerY = centerY + (int ) roundf (instancer (varIdxBase, 1));
out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
}
if (format == 9 && c->plan->all_axes_pinned)
out->format = 8;
return_trace (out->colorLine.serialize_subset (c, colorLine, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && colorLine.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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) * HB_PI,
(endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
}
HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient
* table) to ColorLine subtable. */
FWORD centerX;
FWORD centerY;
F2DOT14 startAngle;
F2DOT14 endAngle;
public :
DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
};
// Paint a non-COLR glyph, filled as indicated by paint.
struct PaintGlyph
{
void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false );
return_trace (out->paint.serialize_subset (c, paint, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && paint.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this );
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;
public :
DEFINE_SIZE_STATIC (6);
};
struct PaintColrGlyph
{
void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ));
}
inline void paint_glyph (hb_paint_context_t *c) const ;
HBUINT8 format; /* format = 11 */
HBUINT16 gid;
public :
DEFINE_SIZE_STATIC (3);
};
template <template <typename > class Var>
struct PaintTransform
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (!out->transform.serialize_subset (c, transform, this , instancer)) return_trace (false );
if (format == 13 && c->plan->all_axes_pinned)
out->format = 12;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) &&
src.sanitize (c, this ) &&
transform.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this );
(this +transform).paint_glyph (c); // This does a push_transform()
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;
public :
DEFINE_SIZE_STATIC (7);
};
struct PaintTranslate
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->dx = dx + (int ) roundf (instancer (varIdxBase, 0));
out->dy = dy + (int ) roundf (instancer (varIdxBase, 1));
}
if (format == 15 && c->plan->all_axes_pinned)
out->format = 14;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
FWORD dy;
public :
DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
};
struct PaintScale
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
}
if (format == 17 && c->plan->all_axes_pinned)
out->format = 16;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
F2DOT14 scaleY;
public :
DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
};
struct PaintScaleAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
out->centerX = centerX + (int ) roundf (instancer (varIdxBase, 2));
out->centerY = centerY + (int ) roundf (instancer (varIdxBase, 3));
}
if (format == 19 && c->plan->all_axes_pinned)
out->format = 18;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
F2DOT14 scaleY;
FWORD centerX;
FWORD centerY;
public :
DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
};
struct PaintScaleUniform
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
if (format == 21 && c->plan->all_axes_pinned)
out->format = 20;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
public :
DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
};
struct PaintScaleUniformAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
out->centerX = centerX + (int ) roundf (instancer (varIdxBase, 1));
out->centerY = centerY + (int ) roundf (instancer (varIdxBase, 2));
}
if (format == 23 && c->plan->all_axes_pinned)
out->format = 22;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
FWORD centerX;
FWORD centerY;
public :
DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
};
struct PaintRotate
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
if (format == 25 && c->plan->all_axes_pinned)
out->format = 24;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
public :
DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
};
struct PaintRotateAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
out->centerX = centerX + (int ) roundf (instancer (varIdxBase, 1));
out->centerY = centerY + (int ) roundf (instancer (varIdxBase, 2));
}
if (format ==27 && c->plan->all_axes_pinned)
out->format = 26;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
FWORD centerX;
FWORD centerY;
public :
DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
};
struct PaintSkew
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
}
if (format == 29 && c->plan->all_axes_pinned)
out->format = 28;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
F2DOT14 ySkewAngle;
public :
DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
};
struct PaintSkewAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
out->centerX = centerX + (int ) roundf (instancer (varIdxBase, 2));
out->centerY = centerY + (int ) roundf (instancer (varIdxBase, 3));
}
if (format == 31 && c->plan->all_axes_pinned)
out->format = 30;
return_trace (out->src.serialize_subset (c, src, this , instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && src.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
TRACE_PAINT (this );
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;
F2DOT14 ySkewAngle;
FWORD centerX;
FWORD centerY;
public :
DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
};
struct PaintComposite
{
void closurev1 (hb_colrv1_closure_context_t* c) const ;
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (this );
if (unlikely (!out)) return_trace (false );
bool ret = false ;
ret |= out->src.serialize_subset (c, src, this , instancer);
ret |= out->backdrop.serialize_subset (c, backdrop, this , instancer);
return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) &&
c->check_ops (this->min_size) && // PainComposite can get exponential
src.sanitize (c, this ) &&
backdrop.sanitize (c, this ));
}
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this );
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 */
Offset24To<Paint> backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
public :
DEFINE_SIZE_STATIC (8);
};
struct ClipBoxData
{
int xMin, yMin, xMax, yMax;
};
struct ClipBoxFormat1
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ));
}
void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
clip_box.xMin = xMin;
clip_box.yMin = yMin;
clip_box.xMax = xMax;
clip_box.yMax = yMax;
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (*this );
if (unlikely (!out)) return_trace (false );
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
{
out->xMin = xMin + (int ) roundf (instancer (varIdxBase, 0));
out->yMin = yMin + (int ) roundf (instancer (varIdxBase, 1));
out->xMax = xMax + (int ) roundf (instancer (varIdxBase, 2));
out->yMax = yMax + (int ) roundf (instancer (varIdxBase, 3));
}
if (format == 2 && c->plan->all_axes_pinned)
out->format = 1;
return_trace (true );
}
public :
HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
FWORD xMin;
FWORD yMin;
FWORD xMax;
FWORD yMax;
public :
DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
};
struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
{
void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
{
value.get_clip_box(clip_box, instancer);
if (instancer)
{
clip_box.xMin += roundf (instancer (varIdxBase, 0));
clip_box.yMin += roundf (instancer (varIdxBase, 1));
clip_box.xMax += roundf (instancer (varIdxBase, 2));
clip_box.yMax += roundf (instancer (varIdxBase, 3));
}
}
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->variation_indices->add_range (varIdxBase, varIdxBase + 3); }
};
struct ClipBox
{
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
switch (u.format) {
case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
case 2: return_trace (u.format2.subset (c, instancer));
default :return_trace (c->default_return_value ());
}
}
void closurev1 (hb_colrv1_closure_context_t* c) const
{
switch (u.format) {
case 2: u.format2.closurev1 (c);
default :return ;
}
}
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)...));
default :return_trace (c->default_return_value ());
}
}
bool get_extents (hb_glyph_extents_t *extents,
const ItemVarStoreInstancer &instancer) const
{
ClipBoxData clip_box;
switch (u.format) {
case 1:
u.format1.get_clip_box (clip_box, instancer);
break ;
case 2:
u.format2.get_clip_box (clip_box, instancer);
break ;
default :
return false ;
}
extents->x_bearing = clip_box.xMin;
extents->y_bearing = clip_box.yMax;
extents->width = clip_box.xMax - clip_box.xMin;
extents->height = clip_box.yMin - clip_box.yMax;
return true ;
}
protected :
union {
HBUINT8 format; /* Format identifier */
ClipBoxFormat1 format1;
ClipBoxFormat2 format2;
} u;
};
struct ClipRecord
{
int cmp (hb_codepoint_t g) const
{ return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const
{
if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return ;
(base+clipBox).closurev1 (c);
}
bool subset (hb_subset_context_t *c,
const void *base,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->embed (*this );
if (unlikely (!out)) return_trace (false );
return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this );
return_trace (c->check_struct (this ) && clipBox.sanitize (c, base));
}
bool get_extents (hb_glyph_extents_t *extents,
const void *base,
const ItemVarStoreInstancer &instancer) const
{
return (base+clipBox).get_extents (extents, instancer);
}
public :
HBUINT16 startGlyphID; // first gid clip applies to
HBUINT16 endGlyphID; // last gid clip applies to, inclusive
Offset24To<ClipBox> clipBox; // Box or VarBox
public :
DEFINE_SIZE_STATIC (7);
};
DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList
{
unsigned serialize_clip_records (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer,
const hb_set_t& gids,
const hb_map_t& gid_offset_map) const
{
TRACE_SERIALIZE (this );
if (gids.is_empty () ||
gid_offset_map.get_population () != gids.get_population ())
return_trace (0);
unsigned count = 0;
hb_codepoint_t start_gid= gids.get_min ();
hb_codepoint_t prev_gid = start_gid;
unsigned offset = gid_offset_map.get (start_gid);
unsigned prev_offset = offset;
for (const hb_codepoint_t _ : gids.iter ())
{
if (_ == start_gid) continue ;
offset = gid_offset_map.get (_);
if (_ == prev_gid + 1 && offset == prev_offset)
{
prev_gid = _;
continue ;
}
ClipRecord record;
record.startGlyphID = start_gid;
record.endGlyphID = prev_gid;
record.clipBox = prev_offset;
if (!record.subset (c, this , instancer)) return_trace (0);
count++;
start_gid = _;
prev_gid = _;
prev_offset = offset;
}
//last one
{
ClipRecord record;
record.startGlyphID = start_gid;
record.endGlyphID = prev_gid;
record.clipBox = prev_offset;
if (!record.subset (c, this , instancer)) return_trace (0);
count++;
}
return_trace (count);
}
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->start_embed (*this );
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_map_t &glyph_map = *c->plan->glyph_map;
hb_map_t new_gid_offset_map;
hb_set_t new_gids;
for (const ClipRecord& record : clips.iter ())
{
unsigned start_gid = record.startGlyphID;
unsigned end_gid = record.endGlyphID;
for (unsigned gid = start_gid; gid <= end_gid; gid++)
{
if (!glyphset.has (gid) || !glyph_map.has (gid)) continue ;
unsigned new_gid = glyph_map.get (gid);
new_gid_offset_map.set (new_gid, record.clipBox);
new_gids.add (new_gid);
}
}
unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
if (!count) return_trace (false );
return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
// TODO Make a formatted struct!
return_trace (c->check_struct (this ) && clips.sanitize (c, this ));
}
bool
get_extents (hb_codepoint_t gid,
hb_glyph_extents_t *extents,
const ItemVarStoreInstancer &instancer) const
{
auto *rec = clips.as_array ().bsearch (gid);
if (rec)
{
rec->get_extents (extents, this , instancer);
return true ;
}
return false ;
}
HBUINT8 format; // Set to 1.
SortedArray32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
public :
DEFINE_SIZE_ARRAY_SIZED (5, clips);
};
struct Paint
{
template <typename ...Ts>
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this );
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)...)));
}
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.paintformat1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
default :return_trace (c->default_return_value ());
}
}
protected :
union {
HBUINT8 format;
PaintColrLayers paintformat1;
NoVariable<PaintSolid> paintformat2;
Variable<PaintSolid> paintformat3;
NoVariable<PaintLinearGradient<NoVariable>> paintformat4;
Variable<PaintLinearGradient<Variable>> paintformat5;
NoVariable<PaintRadialGradient<NoVariable>> paintformat6;
Variable<PaintRadialGradient<Variable>> paintformat7;
NoVariable<PaintSweepGradient<NoVariable>> paintformat8;
Variable<PaintSweepGradient<Variable>> paintformat9;
PaintGlyph paintformat10;
PaintColrGlyph paintformat11;
PaintTransform<NoVariable> paintformat12;
PaintTransform<Variable> paintformat13;
NoVariable<PaintTranslate> paintformat14;
Variable<PaintTranslate> paintformat15;
NoVariable<PaintScale> paintformat16;
Variable<PaintScale> paintformat17;
NoVariable<PaintScaleAroundCenter> paintformat18;
Variable<PaintScaleAroundCenter> paintformat19;
NoVariable<PaintScaleUniform> paintformat20;
Variable<PaintScaleUniform> paintformat21;
NoVariable<PaintScaleUniformAroundCenter> paintformat22;
Variable<PaintScaleUniformAroundCenter> paintformat23;
NoVariable<PaintRotate> paintformat24;
Variable<PaintRotate> paintformat25;
NoVariable<PaintRotateAroundCenter> paintformat26;
Variable<PaintRotateAroundCenter> paintformat27;
NoVariable<PaintSkew> paintformat28;
Variable<PaintSkew> paintformat29;
NoVariable<PaintSkewAroundCenter> paintformat30;
Variable<PaintSkewAroundCenter> paintformat31;
PaintComposite paintformat32;
} u;
public :
DEFINE_SIZE_MIN (2);
};
struct BaseGlyphPaintRecord
{
int cmp (hb_codepoint_t g) const
{ return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
const void * src_base, hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SERIALIZE (this );
auto *out = s->embed (this );
if (unlikely (!out)) return_trace (false );
if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false );
return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this );
return_trace (likely (c->check_struct (this ) && paint.sanitize (c, base)));
}
public :
HBGlyphID16 glyphId; /* Glyph ID of reference glyph */
Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
* Typically PaintColrLayers */
public :
DEFINE_SIZE_STATIC (6);
};
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
{
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
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;
for (const auto & _ : as_array ())
{
unsigned gid = _.glyphId;
if (!glyphset->has (gid)) continue ;
if (_.serialize (c->serializer, c->plan->glyph_map, this , c, instancer)) out->len++;
else return_trace (false );
}
return_trace (out->len != 0);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this ));
}
};
struct LayerList : Array32OfOffset32To<Paint>
{
const Paint& get_paint (unsigned i) const
{ return this +(*this )[i]; }
bool subset (hb_subset_context_t *c,
const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this );
auto *out = c->serializer->start_embed (this );
if (unlikely (!c->serializer->extend_min (out))) return_trace (false );
bool ret = false ;
for (const auto & _ : + hb_enumerate (*this )
| hb_filter (c->plan->colrv1_layers, hb_first))
{
auto *o = out->serialize_append (c->serializer);
if (unlikely (!o)) return_trace (false );
ret |= o->serialize_subset (c, _.second, this , instancer);
}
return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this );
return_trace (Array32OfOffset32To<Paint>::sanitize (c, this ));
}
};
struct delta_set_index_map_subset_plan_t
{
unsigned get_inner_bit_count () const { return inner_bit_count; }
unsigned get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map)
{
map_count = 0;
outer_bit_count = 0;
inner_bit_count = 1;
output_map.init ();
/* search backwards */
unsigned count = new_deltaset_idx_varidx_map.get_population ();
if (!count) return ;
unsigned last_idx = (unsigned )-1;
unsigned last_varidx = (unsigned )-1;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=99 H=100 G=99
¤ Dauer der Verarbeitung: 0.55 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland