Compare commits
48 Commits
Author | SHA1 | Date |
---|---|---|
Behdad Esfahbod | d1c00c0470 | |
Behdad Esfahbod | 4129061e37 | |
Behdad Esfahbod | e76a3649db | |
Behdad Esfahbod | 8e43e3a8ce | |
Behdad Esfahbod | 48f8ed7e02 | |
Behdad Esfahbod | b31684dca4 | |
Behdad Esfahbod | bffdca89f7 | |
Behdad Esfahbod | a960571f24 | |
Behdad Esfahbod | 2b042cc5c6 | |
Qunxin Liu | 591c9460dc | |
Behdad Esfahbod | 3520f528aa | |
Behdad Esfahbod | 33972b3bf6 | |
Behdad Esfahbod | 290cef39be | |
Behdad Esfahbod | 4353192d05 | |
Behdad Esfahbod | 305012609b | |
Behdad Esfahbod | f74abc307d | |
Behdad Esfahbod | d1f49ba6d2 | |
Behdad Esfahbod | 1e9a0511f3 | |
Behdad Esfahbod | 106a237e40 | |
Behdad Esfahbod | f2d21425a3 | |
Behdad Esfahbod | 15d0a1dcfd | |
Behdad Esfahbod | 85d0c3b5f1 | |
Behdad Esfahbod | 5d74b42b9e | |
Behdad Esfahbod | c997e490c7 | |
Behdad Esfahbod | 781da13e99 | |
Behdad Esfahbod | 0e4bcf908c | |
Behdad Esfahbod | 639f45ef9e | |
Behdad Esfahbod | b3da715b9c | |
Behdad Esfahbod | 32f145ff9c | |
Behdad Esfahbod | 000a3c5dca | |
Behdad Esfahbod | 1111c7578e | |
Behdad Esfahbod | 219e739c9f | |
Behdad Esfahbod | a2e8ecf996 | |
Behdad Esfahbod | 317e3693da | |
Behdad Esfahbod | 64ecf8720c | |
Behdad Esfahbod | 7f629c0df2 | |
Garret Rieger | 19e1b698c5 | |
Garret Rieger | 647b024784 | |
Garret Rieger | 3db6baa20e | |
Garret Rieger | 8658c257c4 | |
Josef Friedrich | ac4c3b3e85 | |
DeadSix27 | ef6adadba9 | |
Garret Rieger | 90356eb226 | |
Garret Rieger | 14b9d8d534 | |
Behdad Esfahbod | 9c258936e7 | |
Pedro Kaj Kjellerup Nacht | feb1f6d39e | |
Pedro Kaj Kjellerup Nacht | 26c719e8cd | |
Qunxin Liu | 96ed20725c |
|
@ -1,5 +1,9 @@
|
|||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Security Policy
|
||||
|
||||
If you have discovered a security vulnerability in this project, please report it
|
||||
privately. **Do not disclose it as a public issue.** This gives me time to work with you
|
||||
to fix the issue before public exposure, reducing the chance that the exploit will be
|
||||
used before a patch is released.
|
||||
|
||||
You may submit the report in the following ways:
|
||||
|
||||
- send an email to behdad@behdad.org and harfbuzz-admin@googlegroups.com; and/or
|
||||
- send me a [private vulnerability report](https://github.com/harfbuzz/harfbuzz/security/advisories/new)
|
||||
|
||||
Please provide the following information in your report:
|
||||
|
||||
- A description of the vulnerability and its impact
|
||||
- How to reproduce the issue
|
||||
|
||||
This project is mostly maintained by two developers, working on a reasonable effort
|
||||
basis. As such, we ask that you give us 90 days to work on a fix before public
|
||||
disclosure.
|
|
@ -174,7 +174,9 @@
|
|||
<para>
|
||||
HarfBuzz provides integration points with FreeType at the
|
||||
face-object and font-object level and for the font-functions
|
||||
virtual-method structure of a font object. To use the
|
||||
virtual-method structure of a font object. These functions
|
||||
make it easy for clients that use FreeType for rasterization
|
||||
or font-loading, to use HarfBuzz for shaping. To use the
|
||||
FreeType-integration API, include the
|
||||
<filename>hb-ft.h</filename> header.
|
||||
</para>
|
||||
|
|
|
@ -373,7 +373,10 @@ foreach check : check_funcs
|
|||
endforeach
|
||||
|
||||
subdir('src')
|
||||
subdir('util')
|
||||
|
||||
if not get_option('utilities').disabled()
|
||||
subdir('util')
|
||||
endif
|
||||
|
||||
if not get_option('tests').disabled()
|
||||
subdir('test')
|
||||
|
|
|
@ -31,6 +31,8 @@ option('docs', type: 'feature', value: 'auto', yield: true,
|
|||
description: 'Generate documentation with gtk-doc')
|
||||
option('doc_tests', type: 'boolean', value: false,
|
||||
description: 'Run gtkdoc-check tests')
|
||||
option('utilities', type: 'feature', value: 'enabled', yield: true,
|
||||
description: 'Build harfbuzz utils')
|
||||
|
||||
option('benchmark', type: 'feature', value: 'disabled',
|
||||
description: 'Enable benchmark tests')
|
||||
|
|
|
@ -2213,6 +2213,7 @@ struct COLR
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
|
@ -2251,6 +2252,7 @@ struct COLR
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
has_paint_for_glyph (hb_codepoint_t glyph) const
|
||||
|
@ -2274,6 +2276,7 @@ struct COLR
|
|||
instancer);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
|
||||
{
|
||||
|
@ -2360,6 +2363,7 @@ struct COLR
|
|||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number (starts at 0). */
|
||||
|
|
|
@ -29,6 +29,9 @@ struct Ligature
|
|||
bool intersects (const hb_set_t *glyphs) const
|
||||
{ return hb_all (component, glyphs); }
|
||||
|
||||
bool intersects_lig_glyph (const hb_set_t *glyphs) const
|
||||
{ return glyphs->has(ligGlyph); }
|
||||
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
if (!intersects (c->glyphs)) return;
|
||||
|
|
|
@ -34,6 +34,18 @@ struct LigatureSet
|
|||
;
|
||||
}
|
||||
|
||||
bool intersects_lig_glyph (const hb_set_t *glyphs) const
|
||||
{
|
||||
return
|
||||
+ hb_iter (ligature)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([glyphs] (const Ligature<Types> &_) {
|
||||
return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
|
||||
})
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
+ hb_iter (ligature)
|
||||
|
|
|
@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2
|
|||
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
|
||||
| hb_filter (glyphset, hb_first)
|
||||
| hb_filter ([&] (const LigatureSet<Types>& _) {
|
||||
return _.intersects (&glyphset);
|
||||
return _.intersects_lig_glyph (&glyphset);
|
||||
}, hb_second)
|
||||
| hb_map (hb_first)
|
||||
| hb_sink (new_coverage);
|
||||
|
|
|
@ -87,27 +87,34 @@ struct CompositeGlyphRecord
|
|||
}
|
||||
}
|
||||
|
||||
void transform_points (contour_point_vector_t &points) const
|
||||
void transform_points (contour_point_vector_t &points,
|
||||
const float (&matrix)[4],
|
||||
const contour_point_t &trans) const
|
||||
{
|
||||
float matrix[4];
|
||||
contour_point_t trans;
|
||||
if (get_transformation (matrix, trans))
|
||||
if (scaled_offsets ())
|
||||
{
|
||||
if (scaled_offsets ())
|
||||
{
|
||||
points.translate (trans);
|
||||
points.transform (matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
points.transform (matrix);
|
||||
points.translate (trans);
|
||||
}
|
||||
points.translate (trans);
|
||||
points.transform (matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
points.transform (matrix);
|
||||
points.translate (trans);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned compile_with_deltas (const contour_point_t &p_delta,
|
||||
char *out) const
|
||||
bool get_points (contour_point_vector_t &points) const
|
||||
{
|
||||
float matrix[4];
|
||||
contour_point_t trans;
|
||||
get_transformation (matrix, trans);
|
||||
if (unlikely (!points.resize (points.length + 1))) return false;
|
||||
points[points.length - 1] = trans;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned compile_with_point (const contour_point_t &point,
|
||||
char *out) const
|
||||
{
|
||||
const HBINT8 *p = &StructAfter<const HBINT8> (flags);
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
|
@ -121,18 +128,17 @@ struct CompositeGlyphRecord
|
|||
unsigned len_before_val = (const char *)p - (const char *)this;
|
||||
if (flags & ARG_1_AND_2_ARE_WORDS)
|
||||
{
|
||||
// no overflow, copy and update value with deltas
|
||||
// no overflow, copy value
|
||||
hb_memcpy (out, this, len);
|
||||
|
||||
const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
|
||||
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
|
||||
o[0] = px[0] + roundf (p_delta.x);
|
||||
o[1] = px[1] + roundf (p_delta.y);
|
||||
o[0] = roundf (point.x);
|
||||
o[1] = roundf (point.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
int new_x = p[0] + roundf (p_delta.x);
|
||||
int new_y = p[1] + roundf (p_delta.y);
|
||||
int new_x = roundf (point.x);
|
||||
int new_y = roundf (point.y);
|
||||
if (new_x <= 127 && new_x >= -128 &&
|
||||
new_y <= 127 && new_y >= -128)
|
||||
{
|
||||
|
@ -143,7 +149,7 @@ struct CompositeGlyphRecord
|
|||
}
|
||||
else
|
||||
{
|
||||
// int8 overflows after deltas applied
|
||||
// new point value has an int8 overflow
|
||||
hb_memcpy (out, this, len_before_val);
|
||||
|
||||
//update flags
|
||||
|
@ -171,6 +177,7 @@ struct CompositeGlyphRecord
|
|||
bool scaled_offsets () const
|
||||
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
|
||||
|
||||
public:
|
||||
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
|
||||
{
|
||||
matrix[0] = matrix[3] = 1.f;
|
||||
|
@ -225,7 +232,6 @@ struct CompositeGlyphRecord
|
|||
return tx || ty;
|
||||
}
|
||||
|
||||
public:
|
||||
hb_codepoint_t get_gid () const
|
||||
{
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
|
@ -246,6 +252,27 @@ struct CompositeGlyphRecord
|
|||
StructAfter<HBGlyphID16> (flags) = gid;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
void lower_gid_24_to_16 ()
|
||||
{
|
||||
hb_codepoint_t gid = get_gid ();
|
||||
if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
|
||||
return;
|
||||
|
||||
/* Lower the flag and move the rest of the struct down. */
|
||||
|
||||
unsigned size = get_size ();
|
||||
char *end = (char *) this + size;
|
||||
char *p = &StructAfter<char> (flags);
|
||||
p += HBGlyphID24::static_size;
|
||||
|
||||
flags = flags & ~GID_IS_24BIT;
|
||||
set_gid (gid);
|
||||
|
||||
memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
HBUINT16 flags;
|
||||
HBUINT24 pad;
|
||||
|
@ -304,7 +331,7 @@ struct CompositeGlyph
|
|||
}
|
||||
|
||||
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
|
||||
const contour_point_vector_t &deltas,
|
||||
const contour_point_vector_t &points_with_deltas,
|
||||
hb_bytes_t &dest_bytes /* OUT */)
|
||||
{
|
||||
if (source_bytes.length <= GlyphHeader::static_size ||
|
||||
|
@ -319,7 +346,7 @@ struct CompositeGlyph
|
|||
/* try to allocate more memories than source glyph bytes
|
||||
* in case that there might be an overflow for int8 value
|
||||
* and we would need to use int16 instead */
|
||||
char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
|
||||
char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
|
||||
if (unlikely (!o)) return false;
|
||||
|
||||
const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
|
||||
|
@ -329,8 +356,8 @@ struct CompositeGlyph
|
|||
unsigned i = 0, source_comp_len = 0;
|
||||
for (const auto &component : it)
|
||||
{
|
||||
/* last 4 points in deltas are phantom points and should not be included */
|
||||
if (i >= deltas.length - 4) {
|
||||
/* last 4 points in points_with_deltas are phantom points and should not be included */
|
||||
if (i >= points_with_deltas.length - 4) {
|
||||
free (o);
|
||||
return false;
|
||||
}
|
||||
|
@ -343,7 +370,7 @@ struct CompositeGlyph
|
|||
}
|
||||
else
|
||||
{
|
||||
unsigned new_len = component.compile_with_deltas (deltas[i], p);
|
||||
unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
|
||||
p += new_len;
|
||||
}
|
||||
i++;
|
||||
|
|
|
@ -29,7 +29,14 @@ enum phantom_point_index_t
|
|||
|
||||
struct Glyph
|
||||
{
|
||||
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
|
||||
enum glyph_type_t {
|
||||
EMPTY,
|
||||
SIMPLE,
|
||||
COMPOSITE,
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
VAR_COMPOSITE,
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
composite_iter_t get_composite_iterator () const
|
||||
|
@ -39,15 +46,23 @@ struct Glyph
|
|||
}
|
||||
var_composite_iter_t get_var_composite_iterator () const
|
||||
{
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
|
||||
return VarCompositeGlyph (*header, bytes).iter ();
|
||||
#else
|
||||
return var_composite_iter_t ();
|
||||
#endif
|
||||
}
|
||||
|
||||
const hb_bytes_t trim_padding () const
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
|
||||
#endif
|
||||
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
|
||||
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
|
||||
case EMPTY: return bytes;
|
||||
default: return bytes;
|
||||
}
|
||||
}
|
||||
|
@ -55,27 +70,36 @@ struct Glyph
|
|||
void drop_hints ()
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No hinting
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
|
||||
default: return;
|
||||
case EMPTY: return;
|
||||
}
|
||||
}
|
||||
|
||||
void set_overlaps_flag ()
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No overlaps flag
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
|
||||
default: return;
|
||||
case EMPTY: return;
|
||||
}
|
||||
}
|
||||
|
||||
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No hinting
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
|
||||
default: return;
|
||||
case EMPTY: return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +205,7 @@ struct Glyph
|
|||
hb_bytes_t &dest_start, /* IN/OUT */
|
||||
hb_bytes_t &dest_end /* OUT */)
|
||||
{
|
||||
contour_point_vector_t all_points, deltas;
|
||||
contour_point_vector_t all_points, points_with_deltas;
|
||||
unsigned composite_contours = 0;
|
||||
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
|
||||
unsigned *composite_contours_p = &composite_contours;
|
||||
|
@ -195,7 +219,7 @@ struct Glyph
|
|||
composite_contours_p = nullptr;
|
||||
}
|
||||
|
||||
if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
|
||||
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
|
||||
return false;
|
||||
|
||||
// .notdef, set type to empty so we only update metrics and don't compile bytes for
|
||||
|
@ -209,11 +233,20 @@ struct Glyph
|
|||
}
|
||||
|
||||
//dont compile bytes when pinned at default, just recalculate bounds
|
||||
if (!plan->pinned_at_default) {
|
||||
switch (type) {
|
||||
if (!plan->pinned_at_default)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE:
|
||||
// TODO
|
||||
dest_end = hb_bytes_t ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case COMPOSITE:
|
||||
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
|
||||
deltas,
|
||||
points_with_deltas,
|
||||
dest_end))
|
||||
return false;
|
||||
break;
|
||||
|
@ -223,7 +256,7 @@ struct Glyph
|
|||
dest_end))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
case EMPTY:
|
||||
/* set empty bytes for empty glyph
|
||||
* do not use source glyph's pointers */
|
||||
dest_start = hb_bytes_t ();
|
||||
|
@ -247,7 +280,7 @@ struct Glyph
|
|||
template <typename accelerator_t>
|
||||
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
||||
contour_point_vector_t &all_points /* OUT */,
|
||||
contour_point_vector_t *deltas = nullptr, /* OUT */
|
||||
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
|
||||
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
|
||||
unsigned *composite_contours = nullptr, /* OUT */
|
||||
bool shift_points_hori = true,
|
||||
|
@ -287,9 +320,8 @@ struct Glyph
|
|||
break;
|
||||
case COMPOSITE:
|
||||
{
|
||||
/* pseudo component points for each component in composite glyph */
|
||||
unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
|
||||
if (unlikely (!points.resize (num_points))) return false;
|
||||
for (auto &item : get_composite_iterator ())
|
||||
if (unlikely (!item.get_points (points))) return false;
|
||||
break;
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
|
@ -299,7 +331,7 @@ struct Glyph
|
|||
if (unlikely (!item.get_points (points))) return false;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
case EMPTY:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -327,17 +359,11 @@ struct Glyph
|
|||
#endif
|
||||
;
|
||||
phantoms[PHANTOM_LEFT].x = h_delta;
|
||||
phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
|
||||
phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
|
||||
phantoms[PHANTOM_TOP].y = v_orig;
|
||||
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
|
||||
}
|
||||
|
||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
if (unlikely (!deltas->resize (points.length))) return false;
|
||||
deltas->copy_vector (points);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
glyf_accelerator.gvar->apply_deltas_to_points (gid,
|
||||
coords,
|
||||
|
@ -346,13 +372,10 @@ struct Glyph
|
|||
|
||||
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
|
||||
// with child glyphs' points
|
||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
for (unsigned i = 0 ; i < points.length; i++)
|
||||
{
|
||||
deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
|
||||
deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
|
||||
}
|
||||
if (unlikely (!points_with_deltas->resize (points.length))) return false;
|
||||
points_with_deltas->copy_vector (points);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
@ -373,7 +396,7 @@ struct Glyph
|
|||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
comp_points,
|
||||
deltas,
|
||||
points_with_deltas,
|
||||
head_maxp_info,
|
||||
composite_contours,
|
||||
shift_points_hori,
|
||||
|
@ -389,11 +412,12 @@ struct Glyph
|
|||
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
|
||||
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
|
||||
|
||||
/* Apply component transformation & translation */
|
||||
item.transform_points (comp_points);
|
||||
float matrix[4];
|
||||
contour_point_t default_trans;
|
||||
item.get_transformation (matrix, default_trans);
|
||||
|
||||
/* Apply translation from gvar */
|
||||
comp_points.translate (points[comp_index]);
|
||||
/* Apply component transformation & translation (with deltas applied) */
|
||||
item.transform_points (comp_points, matrix, points[comp_index]);
|
||||
|
||||
if (item.is_anchored ())
|
||||
{
|
||||
|
@ -448,7 +472,7 @@ struct Glyph
|
|||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
comp_points,
|
||||
deltas,
|
||||
points_with_deltas,
|
||||
head_maxp_info,
|
||||
nullptr,
|
||||
shift_points_hori,
|
||||
|
@ -477,7 +501,7 @@ struct Glyph
|
|||
all_points.extend (phantoms);
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
case EMPTY:
|
||||
all_points.extend (phantoms);
|
||||
break;
|
||||
}
|
||||
|
@ -503,6 +527,8 @@ struct Glyph
|
|||
}
|
||||
|
||||
hb_bytes_t get_bytes () const { return bytes; }
|
||||
glyph_type_t get_type () const { return type; }
|
||||
const GlyphHeader *get_header () const { return header; }
|
||||
|
||||
Glyph () : bytes (),
|
||||
header (bytes.as<GlyphHeader> ()),
|
||||
|
@ -518,7 +544,9 @@ struct Glyph
|
|||
int num_contours = header->numberOfContours;
|
||||
if (unlikely (num_contours == 0)) type = EMPTY;
|
||||
else if (num_contours > 0) type = SIMPLE;
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
else if (num_contours == -2) type = VAR_COMPOSITE;
|
||||
#endif
|
||||
else type = COMPOSITE; /* negative numbers */
|
||||
}
|
||||
|
||||
|
@ -526,7 +554,7 @@ struct Glyph
|
|||
hb_bytes_t bytes;
|
||||
const GlyphHeader *header;
|
||||
hb_codepoint_t gid;
|
||||
unsigned type;
|
||||
glyph_type_t type;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,11 @@ struct SimpleGlyph
|
|||
unsigned int length (unsigned int instruction_len) const
|
||||
{ return instruction_len_offset () + 2 + instruction_len; }
|
||||
|
||||
bool has_instructions_length () const
|
||||
{
|
||||
return instruction_len_offset () + 2 <= bytes.length;
|
||||
}
|
||||
|
||||
unsigned int instructions_length () const
|
||||
{
|
||||
unsigned int instruction_length_offset = instruction_len_offset ();
|
||||
|
@ -94,6 +99,7 @@ struct SimpleGlyph
|
|||
/* zero instruction length */
|
||||
void drop_hints ()
|
||||
{
|
||||
if (!has_instructions_length ()) return;
|
||||
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
|
||||
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,12 @@ struct SubsetGlyph
|
|||
TRACE_SERIALIZE (this);
|
||||
|
||||
hb_bytes_t dest_glyph = dest_start.copy (c);
|
||||
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
|
||||
hb_bytes_t end_copy = dest_end.copy (c);
|
||||
if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
|
||||
unsigned int pad_length = use_short_loca ? padding () : 0;
|
||||
DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
|
||||
|
||||
|
@ -41,13 +46,68 @@ struct SubsetGlyph
|
|||
|
||||
if (unlikely (!dest_glyph.length)) return_trace (true);
|
||||
|
||||
/* update components gids */
|
||||
/* update components gids. */
|
||||
for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
|
||||
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
|
||||
const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
auto it = Glyph (dest_glyph).get_composite_iterator ();
|
||||
if (it)
|
||||
{
|
||||
/* lower GID24 to GID16 in components if possible.
|
||||
*
|
||||
* TODO: VarComposite. Not as critical, since VarComposite supports
|
||||
* gid24 from the first version. */
|
||||
char *p = it ? (char *) &*it : nullptr;
|
||||
char *q = p;
|
||||
const char *end = dest_glyph.arrayZ + dest_glyph.length;
|
||||
while (it)
|
||||
{
|
||||
auto &rec = const_cast<CompositeGlyphRecord &> (*it);
|
||||
++it;
|
||||
|
||||
q += rec.get_size ();
|
||||
|
||||
rec.lower_gid_24_to_16 ();
|
||||
|
||||
unsigned size = rec.get_size ();
|
||||
|
||||
memmove (p, &rec, size);
|
||||
|
||||
p += size;
|
||||
}
|
||||
memmove (p, q, end - q);
|
||||
p += end - q;
|
||||
|
||||
/* We want to shorten the glyph, but we can't do that without
|
||||
* updating the length in the loca table, which is already
|
||||
* written out :-(. So we just fill the rest of the glyph with
|
||||
* harmless instructions, since that's what they will be
|
||||
* interpreted as.
|
||||
*
|
||||
* Should move the lowering to _populate_subset_glyphs() to
|
||||
* fix this issue. */
|
||||
|
||||
hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
|
||||
p += end - p;
|
||||
dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);
|
||||
|
||||
// TODO: Padding; & trim serialized bytes.
|
||||
// TODO: Update length in loca. Ugh.
|
||||
}
|
||||
#endif
|
||||
|
||||
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
Glyph (dest_glyph).drop_hints ();
|
||||
|
|
|
@ -71,6 +71,14 @@ struct VarCompositeGlyphRecord
|
|||
return StructAfter<const HBGlyphID16> (numAxes);
|
||||
}
|
||||
|
||||
void set_gid (hb_codepoint_t gid)
|
||||
{
|
||||
if (flags & GID_IS_24BIT)
|
||||
StructAfter<HBGlyphID24> (numAxes) = gid;
|
||||
else
|
||||
StructAfter<HBGlyphID16> (numAxes) = gid;
|
||||
}
|
||||
|
||||
unsigned get_numAxes () const
|
||||
{
|
||||
return numAxes;
|
||||
|
@ -344,6 +352,13 @@ struct VarCompositeGlyph
|
|||
var_composite_iter_t iter () const
|
||||
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
|
||||
|
||||
const hb_bytes_t trim_padding () const
|
||||
{
|
||||
unsigned length = GlyphHeader::static_size;
|
||||
for (auto &comp : iter ())
|
||||
length += comp.get_size ();
|
||||
return bytes.sub_array (0, length);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -241,6 +241,8 @@ struct glyf_accelerator_t
|
|||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
struct points_aggregator_t
|
||||
{
|
||||
|
@ -304,7 +306,6 @@ struct glyf_accelerator_t
|
|||
contour_point_t *get_phantoms_sink () { return phantoms; }
|
||||
};
|
||||
|
||||
public:
|
||||
unsigned
|
||||
get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
|
||||
{
|
||||
|
@ -346,6 +347,15 @@ struct glyf_accelerator_t
|
|||
}
|
||||
#endif
|
||||
|
||||
bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
|
||||
{
|
||||
if (unlikely (gid >= num_glyphs)) return false;
|
||||
if (is_vertical) return false; // TODO Humm, what to do here?
|
||||
|
||||
*lsb = glyph_for_gid (gid).get_header ()->xMin;
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
|
|
|
@ -464,7 +464,8 @@ enum { DELETED_GLYPH = 0xFFFF };
|
|||
template <typename T>
|
||||
struct Entry
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
// This does seem like it's ever called.
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
/* Note, we don't recurse-sanitize data because we don't access it.
|
||||
|
@ -492,7 +493,8 @@ struct Entry
|
|||
template <>
|
||||
struct Entry<void>
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
|
||||
// This does seem like it's ever called.
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
|
||||
/*
|
||||
* Atomic integers and pointers.
|
||||
*
|
||||
* hb_atomic_int_t and hb_atomic_ptr_t are typedefs to the actual
|
||||
* atomic type. They are guaranteed to be at least 32 bits wide.
|
||||
* hb_atomic_int_t is signed.
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@
|
|||
* Buffers serve a dual role in HarfBuzz; before shaping, they hold
|
||||
* the input characters that are passed to hb_shape(), and after
|
||||
* shaping they hold the output glyphs.
|
||||
*
|
||||
* The input buffer is a sequence of Unicode codepoints, with
|
||||
* associated attributes such as direction and script. The output
|
||||
* buffer is a sequence of glyphs, with associated attributes such
|
||||
* as position and cluster.
|
||||
**/
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,19 @@
|
|||
#include "hb.hh"
|
||||
|
||||
|
||||
/* Implements a lockfree cache for int->int functions. */
|
||||
/* Implements a lockfree cache for int->int functions.
|
||||
*
|
||||
* The cache is a fixed-size array of 16-bit or 32-bit integers.
|
||||
* The key is split into two parts: the cache index and the rest.
|
||||
*
|
||||
* The cache index is used to index into the array. The rest is used
|
||||
* to store the key and the value.
|
||||
*
|
||||
* The value is stored in the least significant bits of the integer.
|
||||
* The key is stored in the most significant bits of the integer.
|
||||
* The key is shifted by cache_bits to the left to make room for the
|
||||
* value.
|
||||
*/
|
||||
|
||||
template <unsigned int key_bits=16,
|
||||
unsigned int value_bits=8 + 32 - key_bits,
|
||||
|
|
|
@ -47,6 +47,12 @@
|
|||
* More precisely, a font face represents a single face in a binary font file.
|
||||
* Font faces are typically built from a binary blob and a face index.
|
||||
* Font faces are used to create fonts.
|
||||
*
|
||||
* A font face can be created from a binary blob using hb_face_create().
|
||||
* The face index is used to select a face from a binary blob that contains
|
||||
* multiple faces. For example, a binary blob that contains both a regular
|
||||
* and a bold face can be used to create two font faces, one for each face
|
||||
* index.
|
||||
**/
|
||||
|
||||
|
||||
|
@ -197,7 +203,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
|
|||
* a face index into that blob.
|
||||
*
|
||||
* The face index is used for blobs of file formats such as TTC and
|
||||
* and DFont that can contain more than one face. Face indices within
|
||||
* DFont that can contain more than one face. Face indices within
|
||||
* such collections are zero-based.
|
||||
*
|
||||
* <note>Note: If the blob font format is not a collection, @index
|
||||
|
|
|
@ -76,7 +76,7 @@ struct hb_face_t
|
|||
if (unlikely (!reference_table_func))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
|
||||
blob = reference_table_func (/*Oh, well.*/const_cast<hb_face_t *> (this), tag, user_data);
|
||||
if (unlikely (!blob))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
|
|
|
@ -59,6 +59,11 @@
|
|||
*
|
||||
* HarfBuzz provides a built-in set of lightweight default
|
||||
* functions for each method in #hb_font_funcs_t.
|
||||
*
|
||||
* The default font functions are implemented in terms of the
|
||||
* #hb_font_funcs_t methods of the parent font object. This allows
|
||||
* client programs to override only the methods they need to, and
|
||||
* otherwise inherit the parent font's implementation, if any.
|
||||
**/
|
||||
|
||||
|
||||
|
|
|
@ -413,7 +413,7 @@ hb_ot_get_glyph_extents (hb_font_t *font,
|
|||
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
|
||||
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
#if !defined(HB_NO_COLOR)
|
||||
#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
|
||||
if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
|
||||
|
@ -633,20 +633,4 @@ hb_ot_font_set_funcs (hb_font_t *font)
|
|||
_hb_ot_font_destroy);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
bool
|
||||
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
|
||||
int *lsb)
|
||||
{
|
||||
return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
|
||||
{
|
||||
return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -76,7 +76,7 @@ struct DeviceRecord
|
|||
HBUINT8 maxWidth; /* Maximum width. */
|
||||
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (2, widthsZ);
|
||||
DEFINE_SIZE_UNBOUNDED (2);
|
||||
};
|
||||
|
||||
|
||||
|
@ -87,14 +87,6 @@ struct hdmx
|
|||
unsigned int get_size () const
|
||||
{ return min_size + numRecords * sizeDeviceRecord; }
|
||||
|
||||
const DeviceRecord& operator [] (unsigned int i) const
|
||||
{
|
||||
/* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1300 */
|
||||
if (unlikely (i >= numRecords)) return Null (DeviceRecord);
|
||||
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
|
||||
|
|
|
@ -63,7 +63,25 @@ struct head
|
|||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (serialize (c->serializer));
|
||||
head *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
enum mac_style_flag_t {
|
||||
|
|
|
@ -50,6 +50,9 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly
|
|||
HB_INTERNAL unsigned
|
||||
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
|
||||
|
||||
HB_INTERNAL bool
|
||||
_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb);
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
@ -92,7 +95,7 @@ struct hmtxvmtx
|
|||
|
||||
unsigned int length;
|
||||
H *table = (H *) hb_blob_get_data (dest_blob, &length);
|
||||
table->numberOfLongMetrics = num_hmetrics;
|
||||
c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (c->plan->normalized_coords)
|
||||
|
@ -165,12 +168,19 @@ struct hmtxvmtx
|
|||
lm.sb = _.second;
|
||||
if (unlikely (!c->embed<LongMetric> (&lm))) return;
|
||||
}
|
||||
else
|
||||
else if (idx < 0x10000u)
|
||||
{
|
||||
FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
|
||||
if (unlikely (!sb)) return;
|
||||
*sb = _.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This does not do tail optimization.
|
||||
UFWORD *adv = c->allocate_size<UFWORD> (UFWORD::static_size);
|
||||
if (unlikely (!adv)) return;
|
||||
*adv = _.first;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +199,7 @@ struct hmtxvmtx
|
|||
/* Determine num_long_metrics to encode. */
|
||||
auto& plan = c->plan;
|
||||
|
||||
num_long_metrics = plan->num_output_glyphs ();
|
||||
num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu);
|
||||
unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
|
||||
while (num_long_metrics > 1 &&
|
||||
last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
|
||||
|
@ -208,7 +218,8 @@ struct hmtxvmtx
|
|||
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||
return hb_pair (0u, 0);
|
||||
int lsb = 0;
|
||||
(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
|
||||
if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
|
||||
(void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
|
||||
return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
|
||||
}
|
||||
return mtx_map->get (_);
|
||||
|
|
|
@ -64,6 +64,8 @@ using OT::Layout::GPOS;
|
|||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for querying OpenType Layout features in the font face.
|
||||
* See the <ulink url="http://www.microsoft.com/typography/otspec/">OpenType
|
||||
* specification</ulink> for details.
|
||||
**/
|
||||
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ struct maxp
|
|||
maxp *maxp_prime = c->serializer->embed (this);
|
||||
if (unlikely (!maxp_prime)) return_trace (false);
|
||||
|
||||
maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
|
||||
maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu);
|
||||
if (maxp_prime->version.major == 1)
|
||||
{
|
||||
const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
|
||||
|
|
|
@ -181,6 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t *face,
|
|||
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
|
||||
}
|
||||
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -265,6 +265,9 @@ struct HVARVVAR
|
|||
rsbMap.sanitize (c, this));
|
||||
}
|
||||
|
||||
const VariationStore& get_var_store () const
|
||||
{ return this+varStore; }
|
||||
|
||||
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
|
||||
{
|
||||
index_maps.push (&(this+advMap));
|
||||
|
|
|
@ -29,7 +29,16 @@
|
|||
|
||||
#include "hb.hh"
|
||||
|
||||
/* Memory pool for persistent allocation of small objects. */
|
||||
/* Memory pool for persistent allocation of small objects.
|
||||
*
|
||||
* Some AI musings on this, not necessarily true:
|
||||
*
|
||||
* This is a very simple implementation, but it's good enough for our
|
||||
* purposes. It's not thread-safe. It's not very fast. It's not
|
||||
* very memory efficient. It's not very cache efficient. It's not
|
||||
* very anything efficient. But it's simple and it works. And it's
|
||||
* good enough for our purposes. If you need something more
|
||||
* sophisticated, use a real allocator. Or use a real language. */
|
||||
|
||||
template <typename T, unsigned ChunkLen = 32>
|
||||
struct hb_pool_t
|
||||
|
|
|
@ -35,6 +35,12 @@
|
|||
*
|
||||
* Priority queue implemented as a binary heap. Supports extract minimum
|
||||
* and insert operations.
|
||||
*
|
||||
* The priority queue is implemented as a binary heap, which is a complete
|
||||
* binary tree. The root of the tree is the minimum element. The heap
|
||||
* property is that the priority of a node is less than or equal to the
|
||||
* priority of its children. The heap is stored in an array, with the
|
||||
* children of node i stored at indices 2i + 1 and 2i + 2.
|
||||
*/
|
||||
struct hb_priority_queue_t
|
||||
{
|
||||
|
|
|
@ -36,9 +36,11 @@
|
|||
#include "OT/Color/COLR/COLR.hh"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-maxp-table.hh"
|
||||
|
||||
#ifndef HB_NO_VISIBILITY
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
|
||||
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
|
||||
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
|
||||
|
@ -108,4 +110,26 @@ hb_face_t::load_upem () const
|
|||
}
|
||||
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
bool
|
||||
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
|
||||
int *lsb)
|
||||
{
|
||||
return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
|
||||
{
|
||||
return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb)
|
||||
{
|
||||
return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -125,7 +125,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
|
|||
return result_t{}; // No overlap
|
||||
|
||||
/* case 2: Only the peak and outermost bound fall outside the new limit;
|
||||
* we keep the deltaset, update peak and outermost bound and and scale deltas
|
||||
* we keep the deltaset, update peak and outermost bound and scale deltas
|
||||
* by the scalar value for the restricted axis at the new limit, and solve
|
||||
* recursively.
|
||||
*
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "hb-ot-layout-gpos-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "OT/Color/COLR/COLR.hh"
|
||||
#include "OT/Color/COLR/colrv1-closure.hh"
|
||||
#include "OT/Color/CPAL/CPAL.hh"
|
||||
|
@ -294,7 +295,7 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
|||
feature_record_cond_idx_map,
|
||||
feature_substitutes_map);
|
||||
|
||||
if (table_tag == HB_OT_TAG_GSUB)
|
||||
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
|
||||
hb_ot_layout_lookups_substitute_closure (plan->source,
|
||||
&lookup_indices,
|
||||
gids_to_retain);
|
||||
|
@ -622,7 +623,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
|
|||
|
||||
gids_to_retain->add (gid);
|
||||
|
||||
for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ())
|
||||
for (auto &item : glyf.glyph_for_gid (gid).get_composite_iterator ())
|
||||
operation_count =
|
||||
_glyf_add_gid_and_children (glyf,
|
||||
item.get_gid (),
|
||||
|
@ -630,6 +631,18 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
|
|||
operation_count,
|
||||
depth);
|
||||
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
for (auto &item : glyf.glyph_for_gid (gid).get_var_composite_iterator ())
|
||||
{
|
||||
operation_count =
|
||||
_glyf_add_gid_and_children (glyf,
|
||||
item.get_gid (),
|
||||
gids_to_retain,
|
||||
operation_count,
|
||||
depth);
|
||||
}
|
||||
#endif
|
||||
|
||||
return operation_count;
|
||||
}
|
||||
|
||||
|
@ -644,9 +657,10 @@ _nameid_closure (hb_subset_plan_t* plan,
|
|||
if (!plan->all_axes_pinned)
|
||||
plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_COLOR
|
||||
if (!drop_tables->has (HB_OT_TAG_CPAL))
|
||||
plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||
|
@ -854,6 +868,89 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
|||
}
|
||||
plan->all_axes_pinned = !axis_not_pinned;
|
||||
}
|
||||
|
||||
static void
|
||||
_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
|
||||
{
|
||||
if (!plan->normalized_coords) return;
|
||||
OT::cff2::accelerator_t cff2 (plan->source);
|
||||
if (!cff2.is_valid ()) return;
|
||||
|
||||
hb_font_t *font = nullptr;
|
||||
if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
|
||||
{
|
||||
hb_font_destroy (font);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_glyph_extents_t extents = {0x7FFF, -0x7FFF};
|
||||
OT::hmtx_accelerator_t _hmtx (plan->source);
|
||||
float *hvar_store_cache = nullptr;
|
||||
if (_hmtx.has_data () && _hmtx.var_table.get_length ())
|
||||
hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
|
||||
|
||||
OT::vmtx_accelerator_t _vmtx (plan->source);
|
||||
float *vvar_store_cache = nullptr;
|
||||
if (_vmtx.has_data () && _vmtx.var_table.get_length ())
|
||||
vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache ();
|
||||
|
||||
for (auto p : *plan->glyph_map)
|
||||
{
|
||||
hb_codepoint_t old_gid = p.first;
|
||||
hb_codepoint_t new_gid = p.second;
|
||||
if (!cff2.get_extents (font, old_gid, &extents)) continue;
|
||||
bool has_bounds_info = true;
|
||||
if (extents.x_bearing == 0 && extents.width == 0 &&
|
||||
extents.height == 0 && extents.y_bearing == 0)
|
||||
has_bounds_info = false;
|
||||
|
||||
if (has_bounds_info)
|
||||
{
|
||||
plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing);
|
||||
plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width);
|
||||
plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing);
|
||||
plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height);
|
||||
}
|
||||
|
||||
if (_hmtx.has_data ())
|
||||
{
|
||||
int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid);
|
||||
if (_hmtx.var_table.get_length ())
|
||||
hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
|
||||
hvar_store_cache));
|
||||
int lsb = extents.x_bearing;
|
||||
if (!has_bounds_info)
|
||||
{
|
||||
if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
|
||||
continue;
|
||||
}
|
||||
plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
|
||||
plan->bounds_width_map.set (new_gid, extents.width);
|
||||
}
|
||||
|
||||
if (_vmtx.has_data ())
|
||||
{
|
||||
int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid);
|
||||
if (_vmtx.var_table.get_length ())
|
||||
vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
|
||||
vvar_store_cache));
|
||||
|
||||
int tsb = extents.y_bearing;
|
||||
if (!has_bounds_info)
|
||||
{
|
||||
if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb))
|
||||
continue;
|
||||
}
|
||||
plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
|
||||
plan->bounds_height_map.set (new_gid, extents.height);
|
||||
}
|
||||
}
|
||||
hb_font_destroy (font);
|
||||
if (hvar_store_cache)
|
||||
_hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache);
|
||||
if (vvar_store_cache)
|
||||
_vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
|
||||
|
@ -942,6 +1039,10 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
|
|||
if (unlikely (in_error ()))
|
||||
return;
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
_update_instance_metrics_map_from_cff2 (this);
|
||||
#endif
|
||||
|
||||
if (attach_accelerator_data)
|
||||
{
|
||||
hb_multimap_t gid_to_unicodes;
|
||||
|
|
|
@ -637,8 +637,3 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
|
|||
end:
|
||||
return success ? hb_face_reference (plan->dest) : nullptr;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VISIBILITY
|
||||
/* If NO_VISIBILITY, libharfbuzz has this. */
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
#endif
|
||||
|
|
|
@ -71,6 +71,8 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
|
|||
* in the final subset.
|
||||
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
|
||||
* OS/2 will not be recalculated.
|
||||
* @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
|
||||
* substitution rules (GSUB).
|
||||
*
|
||||
* List of boolean properties that can be configured on the subset input.
|
||||
*
|
||||
|
@ -87,6 +89,7 @@ typedef enum { /*< flags >*/
|
|||
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
|
||||
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
|
||||
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
|
||||
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
|
||||
} hb_subset_flags_t;
|
||||
|
||||
/**
|
||||
|
|
Binary file not shown.
|
@ -44,6 +44,7 @@ EXTRA_DIST += \
|
|||
expected/layout.duplicate_features \
|
||||
expected/layout.unsorted_featurelist \
|
||||
expected/layout.drop_feature \
|
||||
expected/no_layout_closure \
|
||||
expected/cmap \
|
||||
expected/cmap14 \
|
||||
expected/sbix \
|
||||
|
@ -70,6 +71,7 @@ EXTRA_DIST += \
|
|||
expected/apply_cvar_delta \
|
||||
expected/collect_name_ids \
|
||||
expected/instantiate_colrv1 \
|
||||
expected/instantiate_cff2_update_metrics \
|
||||
fonts \
|
||||
profiles \
|
||||
$(NULL)
|
||||
|
|
|
@ -43,6 +43,7 @@ TESTS = \
|
|||
tests/layout.duplicate_features.tests \
|
||||
tests/layout.unsorted_featurelist.tests \
|
||||
tests/layout.drop_feature.tests \
|
||||
tests/no_layout_closure.tests \
|
||||
tests/sbix.tests \
|
||||
tests/variable.tests \
|
||||
tests/glyph_names.tests \
|
||||
|
@ -61,6 +62,7 @@ TESTS = \
|
|||
tests/apply_cvar_delta.tests \
|
||||
tests/collect_name_ids.tests \
|
||||
tests/instantiate_colrv1.tests \
|
||||
tests/instantiate_cff2_update_metrics.tests \
|
||||
$(NULL)
|
||||
|
||||
# TODO: re-enable once colrv1 subsetting is stabilized.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
--no-layout-closure
|
||||
--gids=74,77,446
|
|
@ -0,0 +1,3 @@
|
|||
--no-layout-closure
|
||||
--gids=74,87,88,443,448
|
||||
--layout-features+=dlig
|
|
@ -0,0 +1,15 @@
|
|||
FONTS:
|
||||
Cantarell-VF-ABC.otf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
retain-gids.txt
|
||||
|
||||
SUBSETS:
|
||||
*
|
||||
|
||||
INSTANCES:
|
||||
wght=800
|
||||
|
||||
OPTIONS:
|
||||
no_fonttools
|
|
@ -0,0 +1,9 @@
|
|||
FONTS:
|
||||
Roboto-Regular.ttf
|
||||
|
||||
PROFILES:
|
||||
no-layout-closure-gids.txt
|
||||
no-layout-closure-gids2.txt
|
||||
|
||||
SUBSETS:
|
||||
no-unicodes
|
|
@ -47,8 +47,10 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
|
|||
args.extend(["--drop-tables+=DSIG",
|
||||
"--drop-tables-=sbix",
|
||||
"--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself.
|
||||
"--unicodes=%s" % unicodes,
|
||||
"--output-file=%s" % fonttools_path])
|
||||
if unicodes != "":
|
||||
args.extend(["--unicodes=%s" % unicodes,])
|
||||
|
||||
args.extend(profile_flags)
|
||||
if not no_fonttools:
|
||||
check_call(args)
|
||||
|
@ -63,9 +65,10 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
|
|||
hb_subset,
|
||||
"--font-file=" + input_file,
|
||||
"--output-file=" + harfbuzz_path,
|
||||
"--unicodes=%s" % unicodes,
|
||||
"--drop-tables+=DSIG",
|
||||
"--drop-tables-=sbix"]
|
||||
if unicodes != "":
|
||||
args.extend(["--unicodes=%s" % unicodes,])
|
||||
args.extend(profile_flags)
|
||||
if instance_flags:
|
||||
args.extend(["--instance=%s" % ','.join(instance_flags)])
|
||||
|
|
|
@ -34,6 +34,7 @@ tests = [
|
|||
'layout.duplicate_features',
|
||||
'layout.unsorted_featurelist',
|
||||
'layout.drop_feature',
|
||||
'no_layout_closure',
|
||||
'cmap',
|
||||
'cmap14',
|
||||
'sbix',
|
||||
|
@ -63,6 +64,7 @@ tests = [
|
|||
'apply_cvar_delta',
|
||||
'collect_name_ids',
|
||||
'instantiate_colrv1',
|
||||
'instantiate_cff2_update_metrics',
|
||||
]
|
||||
|
||||
repack_tests = [
|
||||
|
|
|
@ -16,6 +16,8 @@ class Test:
|
|||
import re
|
||||
if self.subset == '*':
|
||||
return self.subset[0]
|
||||
elif self.subset == "no-unicodes":
|
||||
return ""
|
||||
elif re.match("^U\+", self.subset):
|
||||
s = re.sub (r"U\+", "", self.subset)
|
||||
return s
|
||||
|
@ -49,6 +51,11 @@ class Test:
|
|||
profile_name,
|
||||
self.instance_name(),
|
||||
font_base_name_parts[1])
|
||||
elif self.unicodes() == "":
|
||||
return "%s.%s.no-unicodes%s%s" % (font_base_name_parts[0],
|
||||
profile_name,
|
||||
self.instance_name(),
|
||||
font_base_name_parts[1])
|
||||
else:
|
||||
return "%s.%s.%s%s%s" % (font_base_name_parts[0],
|
||||
profile_name,
|
||||
|
|
|
@ -941,6 +941,7 @@ subset_main_t::add_options ()
|
|||
{"set-overlaps-flag", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG>, "Set the overlaps flag on each glyph.", nullptr},
|
||||
{"notdef-outline", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NOTDEF_OUTLINE>, "Keep the outline of \'.notdef\' glyph", nullptr},
|
||||
{"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
|
||||
{"no-layout-closure", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE>, "Don't perform glyph closure for layout substitution (GSUB).", nullptr},
|
||||
{"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>, "Keep PS glyph names in TT-flavored fonts. ", nullptr},
|
||||
{"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
|
||||
{"preprocess-face", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->preprocess,
|
||||
|
|
Loading…
Reference in New Issue