[subset] Add subset () method for COLRv1 Paint tables, BaseGlyphV1List and LayerV1List

Also add support for Offset24 in serializer and repacker
This commit is contained in:
Qunxin Liu 2021-04-17 09:59:45 -07:00 committed by Garret Rieger
parent 413769bf86
commit b23f29bf05
3 changed files with 216 additions and 13 deletions

View File

@ -180,6 +180,15 @@ struct NoVariable
template <template<typename> class Var> template <template<typename> class Var>
struct ColorIndex 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -195,6 +204,13 @@ struct ColorIndex
template <template<typename> class Var> template <template<typename> class Var>
struct ColorStop 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -221,6 +237,23 @@ struct Extend : HBUINT8
template <template<typename> class Var> template <template<typename> class Var>
struct ColorLine 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -306,6 +339,17 @@ struct PaintColrLayers
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -325,6 +369,13 @@ struct PaintSolid
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (color.paletteIndex); } { 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -346,6 +397,15 @@ struct PaintLinearGradient
c->add_palette_index (stop.color.paletteIndex); 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -368,6 +428,15 @@ struct PaintLinearGradient
template <template<typename> class Var> template <template<typename> class Var>
struct PaintRadialGradient 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 void closurev1 (hb_colrv1_closure_context_t* c) const
{ {
for (const auto &stop : (this+colorLine).stops.iter ()) for (const auto &stop : (this+colorLine).stops.iter ())
@ -396,6 +465,15 @@ struct PaintRadialGradient
template <template<typename> class Var> template <template<typename> class Var>
struct PaintSweepGradient 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 void closurev1 (hb_colrv1_closure_context_t* c) const
{ {
for (const auto &stop : (this+colorLine).stops.iter ()) for (const auto &stop : (this+colorLine).stops.iter ())
@ -425,6 +503,19 @@ struct PaintGlyph
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -442,6 +533,16 @@ struct PaintColrGlyph
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -459,6 +560,15 @@ struct PaintTransform
{ {
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -477,6 +587,15 @@ struct PaintTranslate
{ {
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -496,6 +615,15 @@ struct PaintRotate
{ {
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -516,6 +644,15 @@ struct PaintSkew
{ {
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -536,6 +673,16 @@ struct PaintComposite
{ {
void closurev1 (hb_colrv1_closure_context_t* c) const; 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -615,6 +762,19 @@ struct BaseGlyphV1Record
int cmp (hb_codepoint_t g) const int cmp (hb_codepoint_t g) const
{ return g < glyphId ? -1 : g > glyphId ? 1 : 0; } { 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -629,13 +789,47 @@ struct BaseGlyphV1Record
DEFINE_SIZE_STATIC (6); DEFINE_SIZE_STATIC (6);
}; };
typedef SortedArray32Of<BaseGlyphV1Record> BaseGlyphV1List; struct BaseGlyphV1List : SortedArray32Of<BaseGlyphV1Record>
{
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<Paint> struct LayerV1List : Array32OfOffset32To<Paint>
{ {
const Paint& get_paint (unsigned i) const const Paint& get_paint (unsigned i) const
{ return this+(*this)[i]; } { 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 bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);

View File

@ -531,7 +531,7 @@ struct graph_t
const auto& child = vertices_[link.objidx].obj; const auto& child = vertices_[link.objidx].obj;
int64_t child_weight = child.tail - child.head + 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; int64_t child_distance = next_distance + child_weight;
if (child_distance < vertices_[link.objidx].distance) if (child_distance < vertices_[link.objidx].distance)
@ -578,15 +578,17 @@ struct graph_t
{ {
if (link.is_signed) if (link.is_signed)
{ {
if (link.is_wide) if (link.width == 4)
return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
else else
return offset >= -(1 << 15) && offset < (1 << 15); return offset >= -(1 << 15) && offset < (1 << 15);
} }
else else
{ {
if (link.is_wide) if (link.width == 4)
return offset >= 0 && offset < ((int64_t) 1 << 32); return offset >= 0 && offset < ((int64_t) 1 << 32);
else if (link.width == 3)
return offset >= 0 && offset < ((int32_t) 1 << 24);
else else
return offset >= 0 && offset < (1 << 16); return offset >= 0 && offset < (1 << 16);
} }
@ -627,7 +629,7 @@ struct graph_t
char* head, char* head,
hb_serialize_context_t* c) const hb_serialize_context_t* c) const
{ {
if (link.is_wide) if (link.width == 4)
{ {
if (link.is_signed) if (link.is_signed)
{ {
@ -635,7 +637,9 @@ struct graph_t
} else { } else {
serialize_link_of_type<OT::HBUINT32> (link, head, c); serialize_link_of_type<OT::HBUINT32> (link, head, c);
} }
} else { }
else if (link.width == 2)
{
if (link.is_signed) if (link.is_signed)
{ {
serialize_link_of_type<OT::HBINT16> (link, head, c); serialize_link_of_type<OT::HBINT16> (link, head, c);
@ -643,6 +647,8 @@ struct graph_t
serialize_link_of_type<OT::HBUINT16> (link, head, c); serialize_link_of_type<OT::HBUINT16> (link, head, c);
} }
} }
else
serialize_link_of_type<OT::HBUINT24> (link, head, c);
} }
public: public:

View File

@ -82,7 +82,7 @@ struct hb_serialize_context_t
struct link_t struct link_t
{ {
bool is_wide: 1; unsigned width: 3;
bool is_signed: 1; bool is_signed: 1;
unsigned whence: 2; unsigned whence: 2;
unsigned position: 28; unsigned position: 28;
@ -354,7 +354,6 @@ struct hb_serialize_context_t
whence_t whence = Head, whence_t whence = Head,
unsigned bias = 0) unsigned bias = 0)
{ {
static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
if (unlikely (in_error ())) return; if (unlikely (in_error ())) return;
if (!objidx) if (!objidx)
@ -365,7 +364,7 @@ struct hb_serialize_context_t
auto& link = *current->links.push (); 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.is_signed = hb_is_signed (hb_unwrap_type (T));
link.whence = (unsigned) whence; link.whence = (unsigned) whence;
link.position = (const char *) &ofs - current->head; link.position = (const char *) &ofs - current->head;
@ -405,15 +404,19 @@ struct hb_serialize_context_t
offset -= link.bias; offset -= link.bias;
if (link.is_signed) if (link.is_signed)
{ {
if (link.is_wide) assert (link.width == 2 || link.width == 4);
if (link.width == 4)
assign_offset<int32_t> (parent, link, offset); assign_offset<int32_t> (parent, link, offset);
else else
assign_offset<int16_t> (parent, link, offset); assign_offset<int16_t> (parent, link, offset);
} }
else else
{ {
if (link.is_wide) assert (link.width == 2 || link.width == 3 || link.width == 4);
if (link.width == 4)
assign_offset<uint32_t> (parent, link, offset); assign_offset<uint32_t> (parent, link, offset);
else if (link.width == 3)
assign_offset<uint32_t, 3> (parent, link, offset);
else else
assign_offset<uint16_t> (parent, link, offset); assign_offset<uint16_t> (parent, link, offset);
} }
@ -566,10 +569,10 @@ struct hb_serialize_context_t
{ return packed; } { return packed; }
private: private:
template <typename T> template <typename T, unsigned Size = sizeof (T)>
void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
{ {
auto &off = * ((BEInt<T> *) (parent->head + link.position)); auto &off = * ((BEInt<T, Size> *) (parent->head + link.position));
assert (0 == off); assert (0 == off);
check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
} }