[glyf] Move padding removal logic to GlyphHeader
This commit is contained in:
parent
1ab8f9aa7a
commit
cbefbb2439
|
@ -290,6 +290,70 @@ struct glyf
|
|||
*len = instruction_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum simple_glyph_flag_t
|
||||
{
|
||||
FLAG_ON_CURVE = 0x01,
|
||||
FLAG_X_SHORT = 0x02,
|
||||
FLAG_Y_SHORT = 0x04,
|
||||
FLAG_REPEAT = 0x08,
|
||||
FLAG_X_SAME = 0x10,
|
||||
FLAG_Y_SAME = 0x20,
|
||||
FLAG_RESERVED1 = 0x40,
|
||||
FLAG_RESERVED2 = 0x80
|
||||
};
|
||||
|
||||
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
|
||||
{
|
||||
unsigned int end_offset = glyph_bytes.length;
|
||||
/* based on FontTools _g_l_y_f.py::trim */
|
||||
const char *glyph = glyph_bytes.arrayZ;
|
||||
const char *glyph_end = glyph + glyph_bytes.length;
|
||||
/* simple glyph w/contours, possibly trimmable */
|
||||
glyph += instruction_len_offset ();
|
||||
|
||||
if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
|
||||
unsigned int nCoordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
|
||||
unsigned int nInstructions = StructAtOffset<HBUINT16> (glyph, 0);
|
||||
|
||||
glyph += 2 + nInstructions;
|
||||
if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
|
||||
|
||||
unsigned int coordBytes = 0;
|
||||
unsigned int coordsWithFlags = 0;
|
||||
while (glyph < glyph_end)
|
||||
{
|
||||
uint8_t flag = *glyph;
|
||||
glyph++;
|
||||
|
||||
unsigned int repeat = 1;
|
||||
if (flag & FLAG_REPEAT)
|
||||
{
|
||||
if (unlikely (glyph >= glyph_end)) return hb_bytes_t ();
|
||||
repeat = *glyph + 1;
|
||||
glyph++;
|
||||
}
|
||||
|
||||
unsigned int xBytes, yBytes;
|
||||
xBytes = yBytes = 0;
|
||||
if (flag & FLAG_X_SHORT) xBytes = 1;
|
||||
else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
|
||||
|
||||
if (flag & FLAG_Y_SHORT) yBytes = 1;
|
||||
else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
|
||||
|
||||
coordBytes += (xBytes + yBytes) * repeat;
|
||||
coordsWithFlags += repeat;
|
||||
if (coordsWithFlags >= nCoordinates) break;
|
||||
}
|
||||
|
||||
if (unlikely (coordsWithFlags != nCoordinates)) return hb_bytes_t ();
|
||||
glyph += coordBytes;
|
||||
|
||||
if (glyph < glyph_end)
|
||||
end_offset -= glyph_end - glyph;
|
||||
return glyph_bytes.sub_array (0, end_offset);
|
||||
}
|
||||
};
|
||||
|
||||
struct CompositeHeader
|
||||
|
@ -312,6 +376,11 @@ struct glyf
|
|||
*length = end - start;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Trimming for composites not implemented.
|
||||
* If removing hints it falls out of that. */
|
||||
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
|
||||
{ return glyph_bytes; }
|
||||
};
|
||||
|
||||
const SimpleHeader as_simple () const { return SimpleHeader (*this); }
|
||||
|
@ -337,6 +406,17 @@ struct glyf
|
|||
}
|
||||
}
|
||||
|
||||
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
|
||||
{
|
||||
switch (get_type ())
|
||||
{
|
||||
case COMPOSITE: return as_composite ().bytes_without_padding (glyph_bytes);
|
||||
case SIMPLE: return as_simple ().bytes_without_padding (glyph_bytes);
|
||||
default:
|
||||
case EMPTY: return glyph_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_data () const { return numberOfContours; }
|
||||
bool is_simple_glyph () const { return numberOfContours > 0; }
|
||||
bool is_composite_glyph () const { return numberOfContours < 0; }
|
||||
|
@ -656,10 +736,7 @@ struct glyf
|
|||
else if (glyph_header.is_simple_glyph ())
|
||||
{
|
||||
const HBUINT16 *end_pts = &StructAfter<HBUINT16, GlyphHeader> (glyph_header);
|
||||
|
||||
unsigned int start_offset, end_offset;
|
||||
if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) return false;
|
||||
range_checker_t checker (glyf_table, start_offset, end_offset);
|
||||
range_checker_t checker (bytes.arrayZ, 0, bytes.length);
|
||||
num_points = 0;
|
||||
int num_contours = glyph_header.numberOfContours;
|
||||
if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false;
|
||||
|
@ -854,105 +931,6 @@ struct glyf
|
|||
#endif
|
||||
|
||||
public:
|
||||
/* based on FontTools _g_l_y_f.py::trim */
|
||||
bool remove_padding (unsigned int start_offset,
|
||||
unsigned int *end_offset) const
|
||||
{
|
||||
unsigned int glyph_length = *end_offset - start_offset;
|
||||
const char *glyph = ((const char *) glyf_table) + start_offset;
|
||||
const GlyphHeader &glyph_header = *hb_bytes_t (glyph, glyph_length).as<GlyphHeader> ();
|
||||
if (!glyph_header.has_data ()) return true;
|
||||
|
||||
const char *glyph_end = glyph + glyph_length;
|
||||
if (glyph_header.is_composite_glyph ())
|
||||
/* Trimming for composites not implemented.
|
||||
* If removing hints it falls out of that. */
|
||||
return true;
|
||||
else
|
||||
{
|
||||
/* simple glyph w/contours, possibly trimmable */
|
||||
glyph += glyph_header.as_simple ().instruction_len_offset ();
|
||||
|
||||
if (unlikely (glyph + 2 >= glyph_end)) return false;
|
||||
uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
|
||||
uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16> (glyph, 0);
|
||||
|
||||
glyph += 2 + nInstructions;
|
||||
if (unlikely (glyph + 2 >= glyph_end)) return false;
|
||||
|
||||
unsigned int coordBytes = 0;
|
||||
unsigned int coordsWithFlags = 0;
|
||||
while (glyph < glyph_end)
|
||||
{
|
||||
uint8_t flag = (uint8_t) *glyph;
|
||||
glyph++;
|
||||
|
||||
unsigned int repeat = 1;
|
||||
if (flag & FLAG_REPEAT)
|
||||
{
|
||||
if (glyph >= glyph_end)
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "Bad flag");
|
||||
return false;
|
||||
}
|
||||
repeat = ((uint8_t) *glyph) + 1;
|
||||
glyph++;
|
||||
}
|
||||
|
||||
unsigned int xBytes, yBytes;
|
||||
xBytes = yBytes = 0;
|
||||
if (flag & FLAG_X_SHORT) xBytes = 1;
|
||||
else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
|
||||
|
||||
if (flag & FLAG_Y_SHORT) yBytes = 1;
|
||||
else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
|
||||
|
||||
coordBytes += (xBytes + yBytes) * repeat;
|
||||
coordsWithFlags += repeat;
|
||||
if (coordsWithFlags >= nCoordinates)
|
||||
break;
|
||||
}
|
||||
|
||||
if (coordsWithFlags != nCoordinates)
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d",
|
||||
nCoordinates, coordsWithFlags);
|
||||
return false;
|
||||
}
|
||||
glyph += coordBytes;
|
||||
|
||||
if (glyph < glyph_end)
|
||||
*end_offset -= glyph_end - glyph;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_offsets (hb_codepoint_t glyph,
|
||||
unsigned int *start_offset /* OUT */,
|
||||
unsigned int *end_offset /* OUT */) const
|
||||
{
|
||||
if (unlikely (glyph >= num_glyphs)) return false;
|
||||
|
||||
if (short_offset)
|
||||
{
|
||||
const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
|
||||
*start_offset = 2 * offsets[glyph];
|
||||
*end_offset = 2 * offsets[glyph + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
|
||||
|
||||
*start_offset = offsets[glyph];
|
||||
*end_offset = offsets[glyph + 1];
|
||||
}
|
||||
|
||||
if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t glyph,
|
||||
bool is_vertical) const
|
||||
|
@ -1015,22 +993,35 @@ struct glyf
|
|||
bool needs_padding_removal = false) const
|
||||
{
|
||||
unsigned int start_offset, end_offset;
|
||||
if (unlikely (!get_offsets (gid, &start_offset, &end_offset)))
|
||||
if (unlikely (gid >= num_glyphs)) return hb_bytes_t ();
|
||||
|
||||
if (short_offset)
|
||||
{
|
||||
const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
|
||||
start_offset = 2 * offsets[gid];
|
||||
end_offset = 2 * offsets[gid + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
|
||||
start_offset = offsets[gid];
|
||||
end_offset = offsets[gid + 1];
|
||||
}
|
||||
|
||||
if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
|
||||
return hb_bytes_t ();
|
||||
|
||||
/* Remove padding, needed for subset */
|
||||
if (needs_padding_removal)
|
||||
if (unlikely (!remove_padding (start_offset, &end_offset)))
|
||||
return hb_bytes_t ();
|
||||
|
||||
hb_bytes_t glyph_bytes = hb_bytes_t ((const char *) this->glyf_table + start_offset,
|
||||
hb_bytes_t glyph_bytes ((const char *) this->glyf_table + start_offset,
|
||||
end_offset - start_offset);
|
||||
|
||||
/* Glyph size smaller than minimum header */
|
||||
if (!glyph_bytes.as<GlyphHeader> ()->has_data ())
|
||||
return hb_bytes_t ();
|
||||
const GlyphHeader &glyph_header = *glyph_bytes.as<GlyphHeader> ();
|
||||
|
||||
return glyph_bytes;
|
||||
/* Empty glyph or its size is smaller than minimum header */
|
||||
if (!glyph_header.has_data ()) return hb_bytes_t ();
|
||||
|
||||
if (!needs_padding_removal) return glyph_bytes;
|
||||
|
||||
return glyph_header.bytes_without_padding (glyph_bytes);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue