From b23f29bf05650134a9d398d03eb271840172ac9e Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Sat, 17 Apr 2021 09:59:45 -0700 Subject: [PATCH] [subset] Add subset () method for COLRv1 Paint tables, BaseGlyphV1List and LayerV1List Also add support for Offset24 in serializer and repacker --- src/hb-ot-color-colr-table.hh | 196 +++++++++++++++++++++++++++++++++- src/hb-repacker.hh | 16 ++- src/hb-serialize.hh | 17 +-- 3 files changed, 216 insertions(+), 13 deletions(-) diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh index c7399e13b..93e473d2e 100644 --- a/src/hb-ot-color-colr-table.hh +++ b/src/hb-ot-color-colr-table.hh @@ -180,6 +180,15 @@ struct NoVariable template class Var> struct ColorIndex { + 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 (c->serializer->check_assign (out->paletteIndex, c->plan->colrv1_palettes->get (paletteIndex), + HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -195,6 +204,13 @@ struct ColorIndex template class Var> struct ColorStop { + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + if (unlikely (!c->serializer->embed (stopOffset))) return_trace (false); + return_trace (color.subset (c)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -221,6 +237,23 @@ struct Extend : HBUINT8 template class Var> struct ColorLine { + 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 (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)) return_trace (false); + } + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -306,6 +339,17 @@ struct PaintColrLayers { void closurev1 (hb_colrv1_closure_context_t* c) const; + 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 (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); @@ -325,6 +369,13 @@ struct PaintSolid void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (color.paletteIndex); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + if (unlikely (!c->serializer->embed (format))) return_trace (false); + return_trace (color.subset (c)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -346,6 +397,15 @@ struct PaintLinearGradient c->add_palette_index (stop.color.paletteIndex); } + 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 (out->colorLine.serialize_subset (c, colorLine, this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -368,6 +428,15 @@ struct PaintLinearGradient template class Var> struct PaintRadialGradient { + 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 (out->colorLine.serialize_subset (c, colorLine, this)); + } + void closurev1 (hb_colrv1_closure_context_t* c) const { for (const auto &stop : (this+colorLine).stops.iter ()) @@ -396,6 +465,15 @@ struct PaintRadialGradient template class Var> struct PaintSweepGradient { + 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 (out->colorLine.serialize_subset (c, colorLine, this)); + } + void closurev1 (hb_colrv1_closure_context_t* c) const { for (const auto &stop : (this+colorLine).stops.iter ()) @@ -425,6 +503,19 @@ struct PaintGlyph { void closurev1 (hb_colrv1_closure_context_t* c) const; + bool subset (hb_subset_context_t *c) 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)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -442,6 +533,16 @@ struct PaintColrGlyph { void closurev1 (hb_colrv1_closure_context_t* c) const; + 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 (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); @@ -459,6 +560,15 @@ struct PaintTransform { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + 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 (out->src.serialize_subset (c, src, this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -476,6 +586,15 @@ template class Var> struct PaintTranslate { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + + 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 (out->src.serialize_subset (c, src, this)); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -496,6 +615,15 @@ struct PaintRotate { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + 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 (out->src.serialize_subset (c, src, this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -516,6 +644,15 @@ struct PaintSkew { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; + 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 (out->src.serialize_subset (c, src, this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -536,6 +673,16 @@ struct PaintComposite { void closurev1 (hb_colrv1_closure_context_t* c) const; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (!out->src.serialize_subset (c, src, this)) return_trace (false); + return_trace (out->backdrop.serialize_subset (c, backdrop, this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -615,6 +762,19 @@ struct BaseGlyphV1Record 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 + { + 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)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -629,13 +789,47 @@ struct BaseGlyphV1Record DEFINE_SIZE_STATIC (6); }; -typedef SortedArray32Of BaseGlyphV1List; +struct BaseGlyphV1List : SortedArray32Of +{ + 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); + const hb_set_t* glyphset = c->plan->_glyphset; + + for (const auto& _ : as_array ()) + { + unsigned gid = _.glyphId; + if (!glyphset->has (gid)) continue; + + if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; + else return_trace (false); + } + + return_trace (true); + } +}; struct LayerV1List : Array32OfOffset32To { const Paint& get_paint (unsigned i) const { return this+(*this)[i]; } + 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); + + for (const auto& offset : as_array ()) { + auto *o = out->serialize_append (c->serializer); + if (unlikely (!o) || !o->serialize_subset (c, offset, this)) + return_trace (false); + } + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh index 6211dedb9..8d222712d 100644 --- a/src/hb-repacker.hh +++ b/src/hb-repacker.hh @@ -531,7 +531,7 @@ struct graph_t const auto& child = vertices_[link.objidx].obj; int64_t child_weight = child.tail - child.head + - (!link.is_wide ? (1 << 16) : ((int64_t) 1 << 32)); + ((int64_t) 1 << (link.width * 8)); int64_t child_distance = next_distance + child_weight; if (child_distance < vertices_[link.objidx].distance) @@ -578,15 +578,17 @@ struct graph_t { if (link.is_signed) { - if (link.is_wide) + if (link.width == 4) return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); else return offset >= -(1 << 15) && offset < (1 << 15); } else { - if (link.is_wide) + if (link.width == 4) return offset >= 0 && offset < ((int64_t) 1 << 32); + else if (link.width == 3) + return offset >= 0 && offset < ((int32_t) 1 << 24); else return offset >= 0 && offset < (1 << 16); } @@ -627,7 +629,7 @@ struct graph_t char* head, hb_serialize_context_t* c) const { - if (link.is_wide) + if (link.width == 4) { if (link.is_signed) { @@ -635,7 +637,9 @@ struct graph_t } else { serialize_link_of_type (link, head, c); } - } else { + } + else if (link.width == 2) + { if (link.is_signed) { serialize_link_of_type (link, head, c); @@ -643,6 +647,8 @@ struct graph_t serialize_link_of_type (link, head, c); } } + else + serialize_link_of_type (link, head, c); } public: diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index 3ec055b7b..d6aa58405 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -82,7 +82,7 @@ struct hb_serialize_context_t struct link_t { - bool is_wide: 1; + unsigned width: 3; bool is_signed: 1; unsigned whence: 2; unsigned position: 28; @@ -354,7 +354,6 @@ struct hb_serialize_context_t whence_t whence = Head, unsigned bias = 0) { - static_assert (sizeof (T) == 2 || sizeof (T) == 4, ""); if (unlikely (in_error ())) return; if (!objidx) @@ -365,7 +364,7 @@ struct hb_serialize_context_t auto& link = *current->links.push (); - link.is_wide = sizeof (T) == 4; + link.width = sizeof (T); link.is_signed = hb_is_signed (hb_unwrap_type (T)); link.whence = (unsigned) whence; link.position = (const char *) &ofs - current->head; @@ -405,15 +404,19 @@ struct hb_serialize_context_t offset -= link.bias; if (link.is_signed) { - if (link.is_wide) + assert (link.width == 2 || link.width == 4); + if (link.width == 4) assign_offset (parent, link, offset); else assign_offset (parent, link, offset); } else { - if (link.is_wide) + assert (link.width == 2 || link.width == 3 || link.width == 4); + if (link.width == 4) assign_offset (parent, link, offset); + else if (link.width == 3) + assign_offset (parent, link, offset); else assign_offset (parent, link, offset); } @@ -566,10 +569,10 @@ struct hb_serialize_context_t { return packed; } private: - template + template void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) { - auto &off = * ((BEInt *) (parent->head + link.position)); + auto &off = * ((BEInt *) (parent->head + link.position)); assert (0 == off); check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); }