Compare commits

..

1 Commits

Author SHA1 Message Date
Behdad Esfahbod cd7be13059 [map] Try to fix build with old clang, again
https://github.com/harfbuzz/harfbuzz/issues/4138
2023-03-15 17:58:02 -06:00
75 changed files with 235 additions and 961 deletions

View File

@ -1,9 +1,5 @@
name: CIFuzz name: CIFuzz
on: [pull_request] on: [pull_request]
permissions:
contents: read
jobs: jobs:
Fuzzing: Fuzzing:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -1,20 +0,0 @@
# 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.

View File

@ -174,9 +174,7 @@
<para> <para>
HarfBuzz provides integration points with FreeType at the HarfBuzz provides integration points with FreeType at the
face-object and font-object level and for the font-functions face-object and font-object level and for the font-functions
virtual-method structure of a font object. These functions virtual-method structure of a font object. To use the
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 FreeType-integration API, include the
<filename>hb-ft.h</filename> header. <filename>hb-ft.h</filename> header.
</para> </para>

View File

@ -373,10 +373,7 @@ foreach check : check_funcs
endforeach endforeach
subdir('src') subdir('src')
subdir('util')
if not get_option('utilities').disabled()
subdir('util')
endif
if not get_option('tests').disabled() if not get_option('tests').disabled()
subdir('test') subdir('test')

View File

@ -31,8 +31,6 @@ option('docs', type: 'feature', value: 'auto', yield: true,
description: 'Generate documentation with gtk-doc') description: 'Generate documentation with gtk-doc')
option('doc_tests', type: 'boolean', value: false, option('doc_tests', type: 'boolean', value: false,
description: 'Run gtkdoc-check tests') description: 'Run gtkdoc-check tests')
option('utilities', type: 'feature', value: 'enabled', yield: true,
description: 'Build harfbuzz utils')
option('benchmark', type: 'feature', value: 'disabled', option('benchmark', type: 'feature', value: 'disabled',
description: 'Enable benchmark tests') description: 'Enable benchmark tests')

View File

@ -40,6 +40,7 @@
*/ */
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R') #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
namespace OT { namespace OT {
struct hb_paint_context_t; struct hb_paint_context_t;
} }
@ -241,15 +242,10 @@ struct Variable
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ value.closurev1 (c); } { value.closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
if (!value.subset (c, instancer, varIdxBase)) return_trace (false); if (!value.subset (c)) return_trace (false);
if (c->plan->all_axes_pinned)
return_trace (true);
//TODO: update varIdxBase for partial-instancing
return_trace (c->serializer->embed (varIdxBase)); return_trace (c->serializer->embed (varIdxBase));
} }
@ -300,11 +296,10 @@ struct NoVariable
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ value.closurev1 (c); } { value.closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
return_trace (value.subset (c, instancer, varIdxBase)); return_trace (value.subset (c));
} }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
@ -342,20 +337,11 @@ struct ColorStop
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (paletteIndex); } { c->add_palette_index (paletteIndex); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this); auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false); 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), return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW)); HB_SERIALIZE_ERROR_INT_OVERFLOW));
} }
@ -404,8 +390,7 @@ struct ColorLine
stop.closurev1 (c); stop.closurev1 (c);
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
@ -417,7 +402,7 @@ struct ColorLine
for (const auto& stop : stops.iter ()) for (const auto& stop : stops.iter ())
{ {
if (!stop.subset (c, instancer)) return_trace (false); if (!stop.subset (c)) return_trace (false);
} }
return_trace (true); return_trace (true);
} }
@ -538,25 +523,6 @@ struct Affine2x3
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));
} }
bool subset (hb_subset_context_t *c,
const VarStoreInstancer &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 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{ {
c->funcs->push_transform (c->data, c->funcs->push_transform (c->data,
@ -582,8 +548,7 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer HB_UNUSED) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -614,20 +579,11 @@ struct PaintSolid
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (paletteIndex); } { c->add_palette_index (paletteIndex); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this); auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false); 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), return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW)); HB_SERIALIZE_ERROR_INT_OVERFLOW));
} }
@ -662,28 +618,13 @@ struct PaintLinearGradient
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); } { (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->colorLine.serialize_subset (c, colorLine, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -728,28 +669,13 @@ struct PaintRadialGradient
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); } { (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->colorLine.serialize_subset (c, colorLine, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -794,26 +720,13 @@ struct PaintSweepGradient
void closurev1 (hb_colrv1_closure_context_t* c) const void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); } { (this+colorLine).closurev1 (c); }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->colorLine.serialize_subset (c, colorLine, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -853,8 +766,7 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -864,7 +776,7 @@ struct PaintGlyph
HB_SERIALIZE_ERROR_INT_OVERFLOW)) HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false); return_trace (false);
return_trace (out->paint.serialize_subset (c, paint, this, instancer)); 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
@ -895,8 +807,7 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer HB_UNUSED) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
@ -925,16 +836,13 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false); if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false);
if (format == 13 && c->plan->all_axes_pinned) return_trace (out->src.serialize_subset (c, src, this));
out->format = 12;
return_trace (out->src.serialize_subset (c, src, this, instancer));
} }
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
@ -963,24 +871,13 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1011,24 +908,13 @@ struct PaintScale
{ {
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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1059,26 +945,13 @@ struct PaintScaleAroundCenter
{ {
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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1117,21 +990,13 @@ struct PaintScaleUniform
{ {
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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1160,25 +1025,13 @@ struct PaintScaleUniformAroundCenter
{ {
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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1215,21 +1068,13 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1258,25 +1103,13 @@ struct PaintRotateAroundCenter
{ {
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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1313,24 +1146,13 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1361,26 +1183,13 @@ struct PaintSkewAroundCenter
{ {
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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer,
uint32_t varIdxBase) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) return_trace (out->src.serialize_subset (c, src, this));
{
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 bool sanitize (hb_sanitize_context_t *c) const
@ -1419,15 +1228,14 @@ 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->embed (this); auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (false);
if (!out->src.serialize_subset (c, src, this, instancer)) return_trace (false); if (!out->src.serialize_subset (c, src, this)) return_trace (false);
return_trace (out->backdrop.serialize_subset (c, backdrop, this, instancer)); 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
@ -1475,28 +1283,6 @@ struct ClipBoxFormat1
clip_box.yMax = yMax; clip_box.yMax = yMax;
} }
bool subset (hb_subset_context_t *c,
const VarStoreInstancer &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: public:
HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
FWORD xMin; FWORD xMin;
@ -1524,14 +1310,13 @@ struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
struct ClipBox struct ClipBox
{ {
bool subset (hb_subset_context_t *c, ClipBox* copy (hb_serialize_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SERIALIZE (this);
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1)));
case 2: return_trace (u.format2.subset (c, instancer)); case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2)));
default:return_trace (c->default_return_value ()); default:return_trace (nullptr);
} }
} }
@ -1582,15 +1367,13 @@ struct ClipRecord
int cmp (hb_codepoint_t g) const int cmp (hb_codepoint_t g) const
{ return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
bool subset (hb_subset_context_t *c, ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
const void *base,
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SERIALIZE (this);
auto *out = c->serializer->embed (*this); auto *out = c->embed (this);
if (unlikely (!out)) return_trace (false); if (unlikely (!out)) return_trace (nullptr);
if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr);
return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer)); return_trace (out);
} }
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
@ -1617,8 +1400,7 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList struct ClipList
{ {
unsigned serialize_clip_records (hb_subset_context_t *c, unsigned serialize_clip_records (hb_serialize_context_t *c,
const VarStoreInstancer &instancer,
const hb_set_t& gids, const hb_set_t& gids,
const hb_map_t& gid_offset_map) const const hb_map_t& gid_offset_map) const
{ {
@ -1650,7 +1432,7 @@ struct ClipList
record.endGlyphID = prev_gid; record.endGlyphID = prev_gid;
record.clipBox = prev_offset; record.clipBox = prev_offset;
if (!record.subset (c, this, instancer)) return_trace (0); if (!c->copy (record, this)) return_trace (0);
count++; count++;
start_gid = _; start_gid = _;
@ -1664,14 +1446,13 @@ struct ClipList
record.startGlyphID = start_gid; record.startGlyphID = start_gid;
record.endGlyphID = prev_gid; record.endGlyphID = prev_gid;
record.clipBox = prev_offset; record.clipBox = prev_offset;
if (!record.subset (c, this, instancer)) return_trace (0); if (!c->copy (record, this)) return_trace (0);
count++; count++;
} }
return_trace (count); return_trace (count);
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -1696,7 +1477,7 @@ struct ClipList
} }
} }
unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map); unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map);
if (!count) return_trace (false); if (!count) return_trace (false);
return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
} }
@ -1830,8 +1611,7 @@ struct BaseGlyphPaintRecord
{ 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, bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
const void* src_base, hb_subset_context_t *c, const void* src_base, hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
auto *out = s->embed (this); auto *out = s->embed (this);
@ -1840,7 +1620,7 @@ struct BaseGlyphPaintRecord
HB_SERIALIZE_ERROR_INT_OVERFLOW)) HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false); return_trace (false);
return_trace (out->paint.serialize_subset (c, paint, src_base, instancer)); return_trace (out->paint.serialize_subset (c, paint, src_base));
} }
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
@ -1859,8 +1639,7 @@ struct BaseGlyphPaintRecord
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
{ {
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
@ -1872,7 +1651,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
unsigned gid = _.glyphId; unsigned gid = _.glyphId;
if (!glyphset->has (gid)) continue; if (!glyphset->has (gid)) continue;
if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++; if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
else return_trace (false); else return_trace (false);
} }
@ -1891,8 +1670,7 @@ struct LayerList : 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, bool subset (hb_subset_context_t *c) const
const VarStoreInstancer &instancer) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this); auto *out = c->serializer->start_embed (this);
@ -1903,7 +1681,7 @@ struct LayerList : Array32OfOffset32To<Paint>
{ {
auto *o = out->serialize_append (c->serializer); auto *o = out->serialize_append (c->serializer);
if (unlikely (!o) || !o->serialize_subset (c, _.second, this, instancer)) if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
return_trace (false); return_trace (false);
} }
return_trace (true); return_trace (true);
@ -2105,6 +1883,7 @@ struct COLR
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
const hb_set_t& glyphset = c->plan->_glyphset_colred; const hb_set_t& glyphset = c->plan->_glyphset_colred;
@ -2175,12 +1954,7 @@ struct COLR
auto snap = c->serializer->snapshot (); auto snap = c->serializer->snapshot ();
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false); if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this))
VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
varIdxMap ? &(this+varIdxMap) : nullptr,
c->plan->normalized_coords.as_array ());
if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
{ {
if (c->serializer->in_error ()) return_trace (false); if (c->serializer->in_error ()) return_trace (false);
//no more COLRv1 glyphs: downgrade to version 0 //no more COLRv1 glyphs: downgrade to version 0
@ -2190,11 +1964,8 @@ struct COLR
if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
colr_prime->layerList.serialize_subset (c, layerList, this, instancer); colr_prime->layerList.serialize_subset (c, layerList, this);
colr_prime->clipList.serialize_subset (c, clipList, this, instancer); colr_prime->clipList.serialize_subset (c, clipList, this);
if (!varStore || c->plan->all_axes_pinned)
return_trace (true);
colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
colr_prime->varStore.serialize_copy (c->serializer, varStore, this); colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
return_trace (true); return_trace (true);
@ -2213,15 +1984,14 @@ struct COLR
return nullptr; return nullptr;
} }
#ifndef HB_NO_PAINT
bool bool
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{ {
if (version != 1) if (version != 1)
return false; return false;
VarStoreInstancer instancer (&(this+varStore), VarStoreInstancer instancer (this+varStore,
&(this+varIdxMap), this+varIdxMap,
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
if (get_clip (glyph, extents, instancer)) if (get_clip (glyph, extents, instancer))
@ -2252,7 +2022,6 @@ struct COLR
return ret; return ret;
} }
#endif
bool bool
has_paint_for_glyph (hb_codepoint_t glyph) const has_paint_for_glyph (hb_codepoint_t glyph) const
@ -2276,12 +2045,11 @@ struct COLR
instancer); instancer);
} }
#ifndef HB_NO_PAINT
bool 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 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
{ {
VarStoreInstancer instancer (&(this+varStore), VarStoreInstancer instancer (this+varStore,
&(this+varIdxMap), this+varIdxMap,
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
@ -2292,8 +2060,8 @@ struct COLR
{ {
// COLRv1 glyph // COLRv1 glyph
VarStoreInstancer instancer (&(this+varStore), VarStoreInstancer instancer (this+varStore,
&(this+varIdxMap), this+varIdxMap,
hb_array (font->coords, font->num_coords)); hb_array (font->coords, font->num_coords));
bool is_bounded = true; bool is_bounded = true;
@ -2363,7 +2131,6 @@ struct COLR
return false; return false;
} }
#endif
protected: protected:
HBUINT16 version; /* Table version number (starts at 0). */ HBUINT16 version; /* Table version number (starts at 0). */

View File

@ -55,7 +55,7 @@ struct PairPosFormat1_3
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
{ {
for (hb_codepoint_t g : glyphs->iter()) for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
{ {
unsigned i = cov.get_coverage (g); unsigned i = cov.get_coverage (g);
if ((this+pairSet[i]).intersects (glyphs, valueFormat)) if ((this+pairSet[i]).intersects (glyphs, valueFormat))

View File

@ -29,9 +29,6 @@ struct Ligature
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return hb_all (component, glyphs); } { 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 void closure (hb_closure_context_t *c) const
{ {
if (!intersects (c->glyphs)) return; if (!intersects (c->glyphs)) return;

View File

@ -34,18 +34,6 @@ 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 void closure (hb_closure_context_t *c) const
{ {
+ hb_iter (ligature) + hb_iter (ligature)

View File

@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
| hb_filter (glyphset, hb_first) | hb_filter (glyphset, hb_first)
| hb_filter ([&] (const LigatureSet<Types>& _) { | hb_filter ([&] (const LigatureSet<Types>& _) {
return _.intersects_lig_glyph (&glyphset); return _.intersects (&glyphset);
}, hb_second) }, hb_second)
| hb_map (hb_first) | hb_map (hb_first)
| hb_sink (new_coverage); | hb_sink (new_coverage);

View File

@ -87,34 +87,27 @@ struct CompositeGlyphRecord
} }
} }
void transform_points (contour_point_vector_t &points, void transform_points (contour_point_vector_t &points) const
const float (&matrix)[4],
const contour_point_t &trans) const
{
if (scaled_offsets ())
{
points.translate (trans);
points.transform (matrix);
}
else
{
points.transform (matrix);
points.translate (trans);
}
}
bool get_points (contour_point_vector_t &points) const
{ {
float matrix[4]; float matrix[4];
contour_point_t trans; contour_point_t trans;
get_transformation (matrix, trans); if (get_transformation (matrix, trans))
if (unlikely (!points.resize (points.length + 1))) return false; {
points[points.length - 1] = trans; if (scaled_offsets ())
return true; {
points.translate (trans);
points.transform (matrix);
}
else
{
points.transform (matrix);
points.translate (trans);
}
}
} }
unsigned compile_with_point (const contour_point_t &point, unsigned compile_with_deltas (const contour_point_t &p_delta,
char *out) const char *out) const
{ {
const HBINT8 *p = &StructAfter<const HBINT8> (flags); const HBINT8 *p = &StructAfter<const HBINT8> (flags);
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K
@ -128,17 +121,18 @@ struct CompositeGlyphRecord
unsigned len_before_val = (const char *)p - (const char *)this; unsigned len_before_val = (const char *)p - (const char *)this;
if (flags & ARG_1_AND_2_ARE_WORDS) if (flags & ARG_1_AND_2_ARE_WORDS)
{ {
// no overflow, copy value // no overflow, copy and update value with deltas
hb_memcpy (out, this, len); hb_memcpy (out, this, len);
const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val); HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
o[0] = roundf (point.x); o[0] = px[0] + roundf (p_delta.x);
o[1] = roundf (point.y); o[1] = px[1] + roundf (p_delta.y);
} }
else else
{ {
int new_x = roundf (point.x); int new_x = p[0] + roundf (p_delta.x);
int new_y = roundf (point.y); int new_y = p[1] + roundf (p_delta.y);
if (new_x <= 127 && new_x >= -128 && if (new_x <= 127 && new_x >= -128 &&
new_y <= 127 && new_y >= -128) new_y <= 127 && new_y >= -128)
{ {
@ -149,7 +143,7 @@ struct CompositeGlyphRecord
} }
else else
{ {
// new point value has an int8 overflow // int8 overflows after deltas applied
hb_memcpy (out, this, len_before_val); hb_memcpy (out, this, len_before_val);
//update flags //update flags
@ -177,7 +171,6 @@ struct CompositeGlyphRecord
bool scaled_offsets () const bool scaled_offsets () const
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
public:
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
{ {
matrix[0] = matrix[3] = 1.f; matrix[0] = matrix[3] = 1.f;
@ -232,6 +225,7 @@ struct CompositeGlyphRecord
return tx || ty; return tx || ty;
} }
public:
hb_codepoint_t get_gid () const hb_codepoint_t get_gid () const
{ {
#ifndef HB_NO_BEYOND_64K #ifndef HB_NO_BEYOND_64K
@ -252,27 +246,6 @@ struct CompositeGlyphRecord
StructAfter<HBGlyphID16> (flags) = gid; 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: protected:
HBUINT16 flags; HBUINT16 flags;
HBUINT24 pad; HBUINT24 pad;
@ -331,7 +304,7 @@ struct CompositeGlyph
} }
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes, bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
const contour_point_vector_t &points_with_deltas, const contour_point_vector_t &deltas,
hb_bytes_t &dest_bytes /* OUT */) hb_bytes_t &dest_bytes /* OUT */)
{ {
if (source_bytes.length <= GlyphHeader::static_size || if (source_bytes.length <= GlyphHeader::static_size ||
@ -346,7 +319,7 @@ struct CompositeGlyph
/* try to allocate more memories than source glyph bytes /* try to allocate more memories than source glyph bytes
* in case that there might be an overflow for int8 value * in case that there might be an overflow for int8 value
* and we would need to use int16 instead */ * and we would need to use int16 instead */
char *o = (char *) hb_calloc (source_len * 2, sizeof (char)); char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
if (unlikely (!o)) return false; if (unlikely (!o)) return false;
const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size); const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
@ -356,8 +329,8 @@ struct CompositeGlyph
unsigned i = 0, source_comp_len = 0; unsigned i = 0, source_comp_len = 0;
for (const auto &component : it) for (const auto &component : it)
{ {
/* last 4 points in points_with_deltas are phantom points and should not be included */ /* last 4 points in deltas are phantom points and should not be included */
if (i >= points_with_deltas.length - 4) { if (i >= deltas.length - 4) {
free (o); free (o);
return false; return false;
} }
@ -370,7 +343,7 @@ struct CompositeGlyph
} }
else else
{ {
unsigned new_len = component.compile_with_point (points_with_deltas[i], p); unsigned new_len = component.compile_with_deltas (deltas[i], p);
p += new_len; p += new_len;
} }
i++; i++;

View File

@ -29,14 +29,7 @@ enum phantom_point_index_t
struct Glyph struct Glyph
{ {
enum glyph_type_t { enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
EMPTY,
SIMPLE,
COMPOSITE,
#ifndef HB_NO_VAR_COMPOSITES
VAR_COMPOSITE,
#endif
};
public: public:
composite_iter_t get_composite_iterator () const composite_iter_t get_composite_iterator () const
@ -46,23 +39,15 @@ struct Glyph
} }
var_composite_iter_t get_var_composite_iterator () const var_composite_iter_t get_var_composite_iterator () const
{ {
#ifndef HB_NO_VAR_COMPOSITES
if (type != VAR_COMPOSITE) return var_composite_iter_t (); if (type != VAR_COMPOSITE) return var_composite_iter_t ();
return VarCompositeGlyph (*header, bytes).iter (); return VarCompositeGlyph (*header, bytes).iter ();
#else
return var_composite_iter_t ();
#endif
} }
const hb_bytes_t trim_padding () const const hb_bytes_t trim_padding () const
{ {
switch (type) { 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 COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
case EMPTY: return bytes;
default: return bytes; default: return bytes;
} }
} }
@ -70,36 +55,27 @@ struct Glyph
void drop_hints () void drop_hints ()
{ {
switch (type) { switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
case EMPTY: return; default: return;
} }
} }
void set_overlaps_flag () void set_overlaps_flag ()
{ {
switch (type) { 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 COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
case EMPTY: return; default: return;
} }
} }
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
{ {
switch (type) { 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 COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
case EMPTY: return; default: return;
} }
} }
@ -205,7 +181,7 @@ struct Glyph
hb_bytes_t &dest_start, /* IN/OUT */ hb_bytes_t &dest_start, /* IN/OUT */
hb_bytes_t &dest_end /* OUT */) hb_bytes_t &dest_end /* OUT */)
{ {
contour_point_vector_t all_points, points_with_deltas; contour_point_vector_t all_points, deltas;
unsigned composite_contours = 0; unsigned composite_contours = 0;
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
unsigned *composite_contours_p = &composite_contours; unsigned *composite_contours_p = &composite_contours;
@ -219,7 +195,7 @@ struct Glyph
composite_contours_p = nullptr; composite_contours_p = nullptr;
} }
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false)) if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
return false; return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for // .notdef, set type to empty so we only update metrics and don't compile bytes for
@ -233,20 +209,11 @@ struct Glyph
} }
//dont compile bytes when pinned at default, just recalculate bounds //dont compile bytes when pinned at default, just recalculate bounds
if (!plan->pinned_at_default) if (!plan->pinned_at_default) {
{ switch (type) {
switch (type)
{
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
// TODO
dest_end = hb_bytes_t ();
break;
#endif
case COMPOSITE: case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
points_with_deltas, deltas,
dest_end)) dest_end))
return false; return false;
break; break;
@ -256,7 +223,7 @@ struct Glyph
dest_end)) dest_end))
return false; return false;
break; break;
case EMPTY: default:
/* set empty bytes for empty glyph /* set empty bytes for empty glyph
* do not use source glyph's pointers */ * do not use source glyph's pointers */
dest_start = hb_bytes_t (); dest_start = hb_bytes_t ();
@ -280,7 +247,7 @@ struct Glyph
template <typename accelerator_t> template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */, contour_point_vector_t &all_points /* OUT */,
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */ contour_point_vector_t *deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */ head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */ unsigned *composite_contours = nullptr, /* OUT */
bool shift_points_hori = true, bool shift_points_hori = true,
@ -320,8 +287,9 @@ struct Glyph
break; break;
case COMPOSITE: case COMPOSITE:
{ {
for (auto &item : get_composite_iterator ()) /* pseudo component points for each component in composite glyph */
if (unlikely (!item.get_points (points))) return false; unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
if (unlikely (!points.resize (num_points))) return false;
break; break;
} }
#ifndef HB_NO_VAR_COMPOSITES #ifndef HB_NO_VAR_COMPOSITES
@ -331,7 +299,7 @@ struct Glyph
if (unlikely (!item.get_points (points))) return false; if (unlikely (!item.get_points (points))) return false;
} }
#endif #endif
case EMPTY: default:
break; break;
} }
@ -359,11 +327,17 @@ struct Glyph
#endif #endif
; ;
phantoms[PHANTOM_LEFT].x = h_delta; phantoms[PHANTOM_LEFT].x = h_delta;
phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
phantoms[PHANTOM_TOP].y = v_orig; phantoms[PHANTOM_TOP].y = v_orig;
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 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 #ifndef HB_NO_VAR
glyf_accelerator.gvar->apply_deltas_to_points (gid, glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords, coords,
@ -372,10 +346,13 @@ struct Glyph
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
// with child glyphs' points // with child glyphs' points
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) if (deltas != nullptr && depth == 0 && type == COMPOSITE)
{ {
if (unlikely (!points_with_deltas->resize (points.length))) return false; for (unsigned i = 0 ; i < points.length; i++)
points_with_deltas->copy_vector (points); {
deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
}
} }
switch (type) { switch (type) {
@ -396,7 +373,7 @@ struct Glyph
.get_points (font, .get_points (font,
glyf_accelerator, glyf_accelerator,
comp_points, comp_points,
points_with_deltas, deltas,
head_maxp_info, head_maxp_info,
composite_contours, composite_contours,
shift_points_hori, shift_points_hori,
@ -412,12 +389,11 @@ struct Glyph
for (unsigned int i = 0; i < PHANTOM_COUNT; i++) for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
float matrix[4]; /* Apply component transformation & translation */
contour_point_t default_trans; item.transform_points (comp_points);
item.get_transformation (matrix, default_trans);
/* Apply component transformation & translation (with deltas applied) */ /* Apply translation from gvar */
item.transform_points (comp_points, matrix, points[comp_index]); comp_points.translate (points[comp_index]);
if (item.is_anchored ()) if (item.is_anchored ())
{ {
@ -472,7 +448,7 @@ struct Glyph
.get_points (font, .get_points (font,
glyf_accelerator, glyf_accelerator,
comp_points, comp_points,
points_with_deltas, deltas,
head_maxp_info, head_maxp_info,
nullptr, nullptr,
shift_points_hori, shift_points_hori,
@ -501,7 +477,7 @@ struct Glyph
all_points.extend (phantoms); all_points.extend (phantoms);
} break; } break;
#endif #endif
case EMPTY: default:
all_points.extend (phantoms); all_points.extend (phantoms);
break; break;
} }
@ -527,8 +503,6 @@ struct Glyph
} }
hb_bytes_t get_bytes () const { return bytes; } 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 (), Glyph () : bytes (),
header (bytes.as<GlyphHeader> ()), header (bytes.as<GlyphHeader> ()),
@ -544,9 +518,7 @@ struct Glyph
int num_contours = header->numberOfContours; int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY; if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE; else if (num_contours > 0) type = SIMPLE;
#ifndef HB_NO_VAR_COMPOSITES
else if (num_contours == -2) type = VAR_COMPOSITE; else if (num_contours == -2) type = VAR_COMPOSITE;
#endif
else type = COMPOSITE; /* negative numbers */ else type = COMPOSITE; /* negative numbers */
} }
@ -554,7 +526,7 @@ struct Glyph
hb_bytes_t bytes; hb_bytes_t bytes;
const GlyphHeader *header; const GlyphHeader *header;
hb_codepoint_t gid; hb_codepoint_t gid;
glyph_type_t type; unsigned type;
}; };

View File

@ -34,11 +34,6 @@ struct SimpleGlyph
unsigned int length (unsigned int instruction_len) const unsigned int length (unsigned int instruction_len) const
{ return instruction_len_offset () + 2 + instruction_len; } { 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 instructions_length () const
{ {
unsigned int instruction_length_offset = instruction_len_offset (); unsigned int instruction_length_offset = instruction_len_offset ();
@ -99,7 +94,6 @@ struct SimpleGlyph
/* zero instruction length */ /* zero instruction length */
void drop_hints () void drop_hints ()
{ {
if (!has_instructions_length ()) return;
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header); GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
} }

View File

@ -27,12 +27,7 @@ struct SubsetGlyph
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
hb_bytes_t dest_glyph = dest_start.copy (c); hb_bytes_t dest_glyph = dest_start.copy (c);
hb_bytes_t end_copy = dest_end.copy (c); dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
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; 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); DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
@ -46,68 +41,13 @@ struct SubsetGlyph
if (unlikely (!dest_glyph.length)) return_trace (true); if (unlikely (!dest_glyph.length)) return_trace (true);
/* update components gids. */ /* update components gids */
for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
{ {
hb_codepoint_t new_gid; hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<CompositeGlyphRecord &> (_).set_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) if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
Glyph (dest_glyph).drop_hints (); Glyph (dest_glyph).drop_hints ();

View File

@ -71,14 +71,6 @@ struct VarCompositeGlyphRecord
return StructAfter<const HBGlyphID16> (numAxes); 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 unsigned get_numAxes () const
{ {
return numAxes; return numAxes;
@ -352,13 +344,6 @@ struct VarCompositeGlyph
var_composite_iter_t iter () const var_composite_iter_t iter () const
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); } { 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);
}
}; };

View File

@ -241,8 +241,6 @@ struct glyf_accelerator_t
return true; return true;
} }
public:
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
struct points_aggregator_t struct points_aggregator_t
{ {
@ -306,6 +304,7 @@ struct glyf_accelerator_t
contour_point_t *get_phantoms_sink () { return phantoms; } contour_point_t *get_phantoms_sink () { return phantoms; }
}; };
public:
unsigned unsigned
get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
{ {
@ -347,15 +346,6 @@ struct glyf_accelerator_t
} }
#endif #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: public:
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
{ {

View File

@ -464,8 +464,7 @@ enum { DELETED_GLYPH = 0xFFFF };
template <typename T> template <typename T>
struct Entry struct Entry
{ {
// This does seem like it's ever called. bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
/* Note, we don't recurse-sanitize data because we don't access it. /* Note, we don't recurse-sanitize data because we don't access it.
@ -493,8 +492,7 @@ struct Entry
template <> template <>
struct Entry<void> struct Entry<void>
{ {
// This does seem like it's ever called. bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this)); return_trace (c->check_struct (this));

View File

@ -38,10 +38,6 @@
/* /*
* Atomic integers and pointers. * 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.
*/ */

View File

@ -194,7 +194,7 @@ struct hb_bit_set_t
unsigned int end = major_start (m + 1); unsigned int end = major_start (m + 1);
do do
{ {
if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ if (v || page) /* The v check is to optimize out the page check if v is true. */
page->set (g, v); page->set (g, v);
array = &StructAtOffsetUnaligned<T> (array, stride); array = &StructAtOffsetUnaligned<T> (array, stride);
@ -238,7 +238,7 @@ struct hb_bit_set_t
if (g < last_g) return false; if (g < last_g) return false;
last_g = g; last_g = g;
if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ if (v || page) /* The v check is to optimize out the page check if v is true. */
page->add (g); page->add (g);
array = &StructAtOffsetUnaligned<T> (array, stride); array = &StructAtOffsetUnaligned<T> (array, stride);

View File

@ -40,11 +40,6 @@
* Buffers serve a dual role in HarfBuzz; before shaping, they hold * Buffers serve a dual role in HarfBuzz; before shaping, they hold
* the input characters that are passed to hb_shape(), and after * the input characters that are passed to hb_shape(), and after
* shaping they hold the output glyphs. * 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.
**/ **/

View File

@ -30,19 +30,7 @@
#include "hb.hh" #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, template <unsigned int key_bits=16,
unsigned int value_bits=8 + 32 - key_bits, unsigned int value_bits=8 + 32 - key_bits,

View File

@ -47,12 +47,6 @@
* More precisely, a font face represents a single face in a binary font file. * 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 typically built from a binary blob and a face index.
* Font faces are used to create fonts. * 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.
**/ **/
@ -203,7 +197,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
* a face index into that blob. * a face index into that blob.
* *
* The face index is used for blobs of file formats such as TTC and * The face index is used for blobs of file formats such as TTC and
* DFont that can contain more than one face. Face indices within * and DFont that can contain more than one face. Face indices within
* such collections are zero-based. * such collections are zero-based.
* *
* <note>Note: If the blob font format is not a collection, @index * <note>Note: If the blob font format is not a collection, @index

View File

@ -76,7 +76,7 @@ struct hb_face_t
if (unlikely (!reference_table_func)) if (unlikely (!reference_table_func))
return hb_blob_get_empty (); return hb_blob_get_empty ();
blob = reference_table_func (/*Oh, well.*/const_cast<hb_face_t *> (this), tag, user_data); blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
if (unlikely (!blob)) if (unlikely (!blob))
return hb_blob_get_empty (); return hb_blob_get_empty ();

View File

@ -59,11 +59,6 @@
* *
* HarfBuzz provides a built-in set of lightweight default * HarfBuzz provides a built-in set of lightweight default
* functions for each method in #hb_font_funcs_t. * 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.
**/ **/

View File

@ -290,7 +290,8 @@ struct hb_hashmap_t
uint32_t hash () const uint32_t hash () const
{ {
return return
+ iter_items () + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
| hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u) | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u)
; ;
} }
@ -321,40 +322,41 @@ struct hb_hashmap_t
* Iterator * Iterator
*/ */
auto iter_items () const HB_AUTO_RETURN auto iter_ref () const HB_AUTO_RETURN
( (
+ hb_iter (items, size ()) + hb_iter (items, size ())
| hb_filter (&item_t::is_real) | hb_filter (&item_t::is_real)
)
auto iter_ref () const HB_AUTO_RETURN
(
+ iter_items ()
| hb_map (&item_t::get_pair_ref) | hb_map (&item_t::get_pair_ref)
) )
auto iter () const HB_AUTO_RETURN auto iter () const HB_AUTO_RETURN
( (
+ iter_items () + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
| hb_map (&item_t::get_pair) | hb_map (&item_t::get_pair)
) )
auto keys_ref () const HB_AUTO_RETURN auto keys_ref () const HB_AUTO_RETURN
( (
+ iter_items () + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
| hb_map (&item_t::key) | hb_map (&item_t::key)
) )
auto keys () const HB_AUTO_RETURN auto keys () const HB_AUTO_RETURN
( (
+ iter_items () + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
| hb_map (&item_t::key) | hb_map (&item_t::key)
| hb_map (hb_ridentity) | hb_map (hb_ridentity)
) )
auto values_ref () const HB_AUTO_RETURN auto values_ref () const HB_AUTO_RETURN
( (
+ iter_items () + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
| hb_map (&item_t::value) | hb_map (&item_t::value)
) )
auto values () const HB_AUTO_RETURN auto values () const HB_AUTO_RETURN
( (
+ iter_items () + hb_iter (items, size ())
| hb_filter (&item_t::is_real)
| hb_map (&item_t::value) | hb_map (&item_t::value)
| hb_map (hb_ridentity) | hb_map (hb_ridentity)
) )

View File

@ -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->sbix->get_extents (font, glyph, extents)) return true;
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif #endif
#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) #if !defined(HB_NO_COLOR)
if (ot_face->COLR->get_extents (font, glyph, extents)) return true; if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
#endif #endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true; if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
@ -633,4 +633,20 @@ hb_ot_font_set_funcs (hb_font_t *font)
_hb_ot_font_destroy); _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 #endif

View File

@ -76,7 +76,7 @@ struct DeviceRecord
HBUINT8 maxWidth; /* Maximum width. */ HBUINT8 maxWidth; /* Maximum width. */
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */ UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
public: public:
DEFINE_SIZE_UNBOUNDED (2); DEFINE_SIZE_ARRAY (2, widthsZ);
}; };
@ -87,6 +87,14 @@ struct hdmx
unsigned int get_size () const unsigned int get_size () const
{ return min_size + numRecords * sizeDeviceRecord; } { 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, template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))> hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)

View File

@ -63,25 +63,7 @@ struct head
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
head *out = c->serializer->embed (this); return_trace (serialize (c->serializer));
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 { enum mac_style_flag_t {

View File

@ -50,9 +50,6 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly
HB_INTERNAL unsigned HB_INTERNAL unsigned
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); _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 { namespace OT {
@ -95,7 +92,7 @@ struct hmtxvmtx
unsigned int length; unsigned int length;
H *table = (H *) hb_blob_get_data (dest_blob, &length); H *table = (H *) hb_blob_get_data (dest_blob, &length);
c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW); table->numberOfLongMetrics = num_hmetrics;
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
if (c->plan->normalized_coords) if (c->plan->normalized_coords)
@ -168,19 +165,12 @@ struct hmtxvmtx
lm.sb = _.second; lm.sb = _.second;
if (unlikely (!c->embed<LongMetric> (&lm))) return; if (unlikely (!c->embed<LongMetric> (&lm))) return;
} }
else if (idx < 0x10000u) else
{ {
FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size); FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
if (unlikely (!sb)) return; if (unlikely (!sb)) return;
*sb = _.second; *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++; idx++;
} }
} }
@ -199,7 +189,7 @@ struct hmtxvmtx
/* Determine num_long_metrics to encode. */ /* Determine num_long_metrics to encode. */
auto& plan = c->plan; auto& plan = c->plan;
num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); num_long_metrics = plan->num_output_glyphs ();
unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
while (num_long_metrics > 1 && while (num_long_metrics > 1 &&
last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
@ -218,8 +208,7 @@ struct hmtxvmtx
if (!c->plan->old_gid_for_new_gid (_, &old_gid)) if (!c->plan->old_gid_for_new_gid (_, &old_gid))
return hb_pair (0u, 0); return hb_pair (0u, 0);
int lsb = 0; int lsb = 0;
if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) (void) _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 hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
} }
return mtx_map->get (_); return mtx_map->get (_);

View File

@ -64,8 +64,6 @@ using OT::Layout::GPOS;
* @include: hb-ot.h * @include: hb-ot.h
* *
* Functions for querying OpenType Layout features in the font face. * 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.
**/ **/

View File

@ -100,7 +100,7 @@ struct maxp
maxp *maxp_prime = c->serializer->embed (this); maxp *maxp_prime = c->serializer->embed (this);
if (unlikely (!maxp_prime)) return_trace (false); if (unlikely (!maxp_prime)) return_trace (false);
maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu); maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
if (maxp_prime->version.major == 1) if (maxp_prime->version.major == 1)
{ {
const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this); const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);

View File

@ -181,4 +181,6 @@ 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); return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
} }
#include "hb-ot-name-language-static.hh"
#endif #endif

View File

@ -1067,15 +1067,12 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
base = i; base = i;
while (base < end && is_halant (info[base])) while (base < end && is_halant (info[base]))
base++; base++;
if (base < end) info[base].indic_position() = POS_BASE_C;
info[base].indic_position() = POS_BASE_C;
try_pref = false; try_pref = false;
} }
break; break;
} }
if (base == end)
break;
} }
/* For Malayalam, skip over unformed below- (but NOT post-) forms. */ /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
if (buffer->props.script == HB_SCRIPT_MALAYALAM) if (buffer->props.script == HB_SCRIPT_MALAYALAM)

View File

@ -222,20 +222,18 @@ struct DeltaSetIndexMap
struct VarStoreInstancer struct VarStoreInstancer
{ {
VarStoreInstancer (const VariationStore *varStore, VarStoreInstancer (const VariationStore &varStore,
const DeltaSetIndexMap *varIdxMap, const DeltaSetIndexMap &varIdxMap,
hb_array_t<int> coords) : hb_array_t<int> coords) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords) {} varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
operator bool () const { return varStore && bool (coords); } operator bool () const { return bool (coords); }
/* according to the spec, if colr table has varStore but does not have
* varIdxMap, then an implicit identity mapping is used */
float operator() (uint32_t varIdx, unsigned short offset = 0) const float operator() (uint32_t varIdx, unsigned short offset = 0) const
{ return varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords); } { return varStore.get_delta (varIdxMap.map (VarIdx::add (varIdx, offset)), coords); }
const VariationStore *varStore; const VariationStore &varStore;
const DeltaSetIndexMap *varIdxMap; const DeltaSetIndexMap &varIdxMap;
hb_array_t<int> coords; hb_array_t<int> coords;
}; };
@ -360,12 +358,9 @@ struct TupleVariationData
{ {
unsigned total_size = min_size; unsigned total_size = min_size;
unsigned count = tupleVarCount; unsigned count = tupleVarCount;
const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header()); const TupleVariationHeader& tuple_var_header = get_tuple_var_header();
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
{ total_size += tuple_var_header.get_size (axis_count) + tuple_var_header.get_data_size ();
total_size += tuple_var_header->get_size (axis_count) + tuple_var_header->get_data_size ();
tuple_var_header = &tuple_var_header->get_next (axis_count);
}
return total_size; return total_size;
} }

View File

@ -265,9 +265,6 @@ struct HVARVVAR
rsbMap.sanitize (c, this)); 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 void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
{ {
index_maps.push (&(this+advMap)); index_maps.push (&(this+advMap));

View File

@ -616,7 +616,7 @@ typedef enum {
HB_PAINT_COMPOSITE_MODE_HSL_HUE, HB_PAINT_COMPOSITE_MODE_HSL_HUE,
HB_PAINT_COMPOSITE_MODE_HSL_SATURATION, HB_PAINT_COMPOSITE_MODE_HSL_SATURATION,
HB_PAINT_COMPOSITE_MODE_HSL_COLOR, HB_PAINT_COMPOSITE_MODE_HSL_COLOR,
HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY,
} hb_paint_composite_mode_t; } hb_paint_composite_mode_t;
/** /**

View File

@ -29,16 +29,7 @@
#include "hb.hh" #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> template <typename T, unsigned ChunkLen = 32>
struct hb_pool_t struct hb_pool_t

View File

@ -35,12 +35,6 @@
* *
* Priority queue implemented as a binary heap. Supports extract minimum * Priority queue implemented as a binary heap. Supports extract minimum
* and insert operations. * 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 struct hb_priority_queue_t
{ {

View File

@ -36,11 +36,9 @@
#include "OT/Color/COLR/COLR.hh" #include "OT/Color/COLR/COLR.hh"
#include "hb-ot-glyf-table.hh" #include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh" #include "hb-ot-head-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-maxp-table.hh" #include "hb-ot-maxp-table.hh"
#ifndef HB_NO_VISIBILITY #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)] = {}; 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)] = {}; /*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
@ -110,26 +108,4 @@ 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 #endif

View File

@ -125,7 +125,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
return result_t{}; // No overlap return result_t{}; // No overlap
/* case 2: Only the peak and outermost bound fall outside the new limit; /* case 2: Only the peak and outermost bound fall outside the new limit;
* we keep the deltaset, update peak and outermost bound and scale deltas * we keep the deltaset, update peak and outermost bound and and scale deltas
* by the scalar value for the restricted axis at the new limit, and solve * by the scalar value for the restricted axis at the new limit, and solve
* recursively. * recursively.
* *

View File

@ -36,7 +36,6 @@
#include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-cff1-table.hh" #include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "OT/Color/COLR/COLR.hh" #include "OT/Color/COLR/COLR.hh"
#include "OT/Color/COLR/colrv1-closure.hh" #include "OT/Color/COLR/colrv1-closure.hh"
#include "OT/Color/CPAL/CPAL.hh" #include "OT/Color/CPAL/CPAL.hh"
@ -295,7 +294,7 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
feature_record_cond_idx_map, feature_record_cond_idx_map,
feature_substitutes_map); feature_substitutes_map);
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) if (table_tag == HB_OT_TAG_GSUB)
hb_ot_layout_lookups_substitute_closure (plan->source, hb_ot_layout_lookups_substitute_closure (plan->source,
&lookup_indices, &lookup_indices,
gids_to_retain); gids_to_retain);
@ -347,10 +346,7 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
hb_font_t *font = hb_font_create (plan->source); hb_font_t *font = hb_font_create (plan->source);
hb_vector_t<hb_variation_t> vars; hb_vector_t<hb_variation_t> vars;
if (!vars.alloc (plan->user_axes_location.get_population ())) { vars.alloc (plan->user_axes_location.get_population ());
hb_font_destroy (font);
return nullptr;
}
for (auto _ : plan->user_axes_location) for (auto _ : plan->user_axes_location)
{ {
@ -386,13 +382,7 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
bool collect_delta = plan->pinned_at_default ? false : true; bool collect_delta = plan->pinned_at_default ? false : true;
if (collect_delta) if (collect_delta)
{ {
if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan)))) { font = _get_hb_font_with_variations (plan);
hb_font_destroy (font);
gdef.destroy ();
gpos.destroy ();
return;
}
if (gdef->has_var_store ()) if (gdef->has_var_store ())
{ {
var_store = &(gdef->get_var_store ()); var_store = &(gdef->get_var_store ());
@ -566,12 +556,9 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
if (plan->codepoint_to_glyph->has (cp)) if (plan->codepoint_to_glyph->has (cp))
continue; continue;
hb_codepoint_t *gid; hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
if (!unicode_glyphid_map->has(cp, &gid)) plan->codepoint_to_glyph->set (cp, gid);
continue; plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
plan->codepoint_to_glyph->set (cp, *gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid));
} }
plan->unicode_to_new_gid_list.qsort (); plan->unicode_to_new_gid_list.qsort ();
} }
@ -623,7 +610,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
gids_to_retain->add (gid); 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 = operation_count =
_glyf_add_gid_and_children (glyf, _glyf_add_gid_and_children (glyf,
item.get_gid (), item.get_gid (),
@ -631,18 +618,6 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
operation_count, operation_count,
depth); 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; return operation_count;
} }
@ -657,10 +632,9 @@ _nameid_closure (hb_subset_plan_t* plan,
if (!plan->all_axes_pinned) if (!plan->all_axes_pinned)
plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids); plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
#endif #endif
#ifndef HB_NO_COLOR
if (!drop_tables->has (HB_OT_TAG_CPAL)) if (!drop_tables->has (HB_OT_TAG_CPAL))
plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids); plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
#endif
#ifndef HB_NO_SUBSET_LAYOUT #ifndef HB_NO_SUBSET_LAYOUT
if (!drop_tables->has (HB_OT_TAG_GPOS)) if (!drop_tables->has (HB_OT_TAG_GPOS))
@ -827,15 +801,12 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
bool has_avar = face->table.avar->has_data (); bool has_avar = face->table.avar->has_data ();
const OT::SegmentMaps *seg_maps = nullptr; const OT::SegmentMaps *seg_maps = nullptr;
unsigned avar_axis_count = 0;
if (has_avar) if (has_avar)
{
seg_maps = face->table.avar->get_segment_maps (); seg_maps = face->table.avar->get_segment_maps ();
avar_axis_count = face->table.avar->get_axis_count();
}
bool axis_not_pinned = false; bool axis_not_pinned = false;
unsigned old_axis_idx = 0, new_axis_idx = 0; unsigned old_axis_idx = 0, new_axis_idx = 0;
unsigned int i = 0;
for (const auto& axis : axes) for (const auto& axis : axes)
{ {
hb_tag_t axis_tag = axis.get_axis_tag (); hb_tag_t axis_tag = axis.get_axis_tag ();
@ -850,7 +821,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
else else
{ {
int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag)); int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag));
if (has_avar && old_axis_idx < avar_axis_count) if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
{ {
normalized_v = seg_maps->map (normalized_v); normalized_v = seg_maps->map (normalized_v);
} }
@ -858,99 +829,17 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
if (normalized_v != 0) if (normalized_v != 0)
plan->pinned_at_default = false; plan->pinned_at_default = false;
plan->normalized_coords[old_axis_idx] = normalized_v; plan->normalized_coords[i] = normalized_v;
} }
if (has_avar)
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
old_axis_idx++; old_axis_idx++;
if (has_avar && old_axis_idx < avar_axis_count) i++;
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
} }
plan->all_axes_pinned = !axis_not_pinned; 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 #endif
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
@ -1013,8 +902,6 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this); _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this);
_populate_gids_to_retain (this, input->sets.drop_tables); _populate_gids_to_retain (this, input->sets.drop_tables);
if (unlikely (in_error ()))
return;
_create_old_gid_to_new_gid_map (face, _create_old_gid_to_new_gid_map (face,
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS, input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
@ -1039,10 +926,6 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
if (unlikely (in_error ())) if (unlikely (in_error ()))
return; return;
#ifndef HB_NO_VAR
_update_instance_metrics_map_from_cff2 (this);
#endif
if (attach_accelerator_data) if (attach_accelerator_data)
{ {
hb_multimap_t gid_to_unicodes; hb_multimap_t gid_to_unicodes;

View File

@ -211,7 +211,7 @@ struct hb_subset_plan_t
template<typename T> template<typename T>
hb_blob_ptr_t<T> source_table() hb_blob_ptr_t<T> source_table()
{ {
hb_lock_t lock (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr); hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache; auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache;
if (cache if (cache

View File

@ -637,3 +637,8 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
end: end:
return success ? hb_face_reference (plan->dest) : nullptr; 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

View File

@ -71,8 +71,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* in the final subset. * in the final subset.
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
* OS/2 will not be recalculated. * 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. * List of boolean properties that can be configured on the subset input.
* *
@ -89,7 +87,6 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u, HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
} hb_subset_flags_t; } hb_subset_flags_t;
/** /**

View File

@ -137,29 +137,5 @@ main (int argc, char **argv)
assert (s.has (HB_SET_VALUE_INVALID)); assert (s.has (HB_SET_VALUE_INVALID));
} }
/* Adding HB_SET_VALUE_INVALID */
{
hb_set_t s;
s.add(HB_SET_VALUE_INVALID);
assert(!s.has(HB_SET_VALUE_INVALID));
s.clear();
assert(!s.add_range(HB_SET_VALUE_INVALID - 2, HB_SET_VALUE_INVALID));
assert(!s.has(HB_SET_VALUE_INVALID));
hb_codepoint_t array[] = {(unsigned) HB_SET_VALUE_INVALID, 0, 2};
s.clear();
s.add_array(array, 3);
assert(!s.has(HB_SET_VALUE_INVALID));
assert(s.has(2));
hb_codepoint_t sorted_array[] = {0, 2, (unsigned) HB_SET_VALUE_INVALID};
s.clear();
s.add_sorted_array(sorted_array, 3);
assert(!s.has(HB_SET_VALUE_INVALID));
assert(s.has(2));
}
return 0; return 0;
} }

View File

@ -10,7 +10,6 @@ EXTRA_DIST += \
$(DISABLED_TESTS) \ $(DISABLED_TESTS) \
expected/32bit_var_store \ expected/32bit_var_store \
expected/basics \ expected/basics \
expected/preprocess \
expected/full-font \ expected/full-font \
expected/glyf_bug_3131 \ expected/glyf_bug_3131 \
expected/cff-full-font \ expected/cff-full-font \
@ -44,7 +43,6 @@ EXTRA_DIST += \
expected/layout.duplicate_features \ expected/layout.duplicate_features \
expected/layout.unsorted_featurelist \ expected/layout.unsorted_featurelist \
expected/layout.drop_feature \ expected/layout.drop_feature \
expected/no_layout_closure \
expected/cmap \ expected/cmap \
expected/cmap14 \ expected/cmap14 \
expected/sbix \ expected/sbix \
@ -70,8 +68,6 @@ EXTRA_DIST += \
expected/post_apply_mvar_delta \ expected/post_apply_mvar_delta \
expected/apply_cvar_delta \ expected/apply_cvar_delta \
expected/collect_name_ids \ expected/collect_name_ids \
expected/instantiate_colrv1 \
expected/instantiate_cff2_update_metrics \
fonts \ fonts \
profiles \ profiles \
$(NULL) $(NULL)

View File

@ -1,7 +1,6 @@
TESTS = \ TESTS = \
tests/32bit_var_store.tests \ tests/32bit_var_store.tests \
tests/basics.tests \ tests/basics.tests \
tests/preprocess.tests \
tests/cbdt.tests \ tests/cbdt.tests \
tests/cff-full-font.tests \ tests/cff-full-font.tests \
tests/cff-japanese.tests \ tests/cff-japanese.tests \
@ -43,7 +42,6 @@ TESTS = \
tests/layout.duplicate_features.tests \ tests/layout.duplicate_features.tests \
tests/layout.unsorted_featurelist.tests \ tests/layout.unsorted_featurelist.tests \
tests/layout.drop_feature.tests \ tests/layout.drop_feature.tests \
tests/no_layout_closure.tests \
tests/sbix.tests \ tests/sbix.tests \
tests/variable.tests \ tests/variable.tests \
tests/glyph_names.tests \ tests/glyph_names.tests \
@ -61,8 +59,6 @@ TESTS = \
tests/post_apply_mvar_delta.tests \ tests/post_apply_mvar_delta.tests \
tests/apply_cvar_delta.tests \ tests/apply_cvar_delta.tests \
tests/collect_name_ids.tests \ tests/collect_name_ids.tests \
tests/instantiate_colrv1.tests \
tests/instantiate_cff2_update_metrics.tests \
$(NULL) $(NULL)
# TODO: re-enable once colrv1 subsetting is stabilized. # TODO: re-enable once colrv1 subsetting is stabilized.

Binary file not shown.

View File

@ -1,2 +0,0 @@
--no-layout-closure
--gids=74,77,446

View File

@ -1,3 +0,0 @@
--no-layout-closure
--gids=74,87,88,443,448
--layout-features+=dlig

View File

@ -1,6 +1,5 @@
FONTS: FONTS:
Comfortaa-Regular-new.ttf Comfortaa-Regular-new.ttf
Muli-ABC.ttf
PROFILES: PROFILES:
default.txt default.txt

View File

@ -1,15 +0,0 @@
FONTS:
Cantarell-VF-ABC.otf
PROFILES:
default.txt
retain-gids.txt
SUBSETS:
*
INSTANCES:
wght=800
OPTIONS:
no_fonttools

View File

@ -1,14 +0,0 @@
FONTS:
Foldit.ttf
PROFILES:
default.txt
SUBSETS:
*
INSTANCES:
wght=900
OPTIONS:
no_fonttools

View File

@ -1,9 +0,0 @@
FONTS:
Roboto-Regular.ttf
PROFILES:
no-layout-closure-gids.txt
no-layout-closure-gids2.txt
SUBSETS:
no-unicodes

View File

@ -1,8 +0,0 @@
FONTS:
Roboto-Regular.ttf
PROFILES:
gids.txt
SUBSETS:
abcベ

View File

@ -47,10 +47,8 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
args.extend(["--drop-tables+=DSIG", args.extend(["--drop-tables+=DSIG",
"--drop-tables-=sbix", "--drop-tables-=sbix",
"--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself. "--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself.
"--unicodes=%s" % unicodes,
"--output-file=%s" % fonttools_path]) "--output-file=%s" % fonttools_path])
if unicodes != "":
args.extend(["--unicodes=%s" % unicodes,])
args.extend(profile_flags) args.extend(profile_flags)
if not no_fonttools: if not no_fonttools:
check_call(args) check_call(args)
@ -65,10 +63,9 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
hb_subset, hb_subset,
"--font-file=" + input_file, "--font-file=" + input_file,
"--output-file=" + harfbuzz_path, "--output-file=" + harfbuzz_path,
"--unicodes=%s" % unicodes,
"--drop-tables+=DSIG", "--drop-tables+=DSIG",
"--drop-tables-=sbix"] "--drop-tables-=sbix"]
if unicodes != "":
args.extend(["--unicodes=%s" % unicodes,])
args.extend(profile_flags) args.extend(profile_flags)
if instance_flags: if instance_flags:
args.extend(["--instance=%s" % ','.join(instance_flags)]) args.extend(["--instance=%s" % ','.join(instance_flags)])

View File

@ -1,6 +1,5 @@
tests = [ tests = [
'basics', 'basics',
'preprocess',
'full-font', 'full-font',
'cff-full-font', 'cff-full-font',
'japanese', 'japanese',
@ -34,7 +33,6 @@ tests = [
'layout.duplicate_features', 'layout.duplicate_features',
'layout.unsorted_featurelist', 'layout.unsorted_featurelist',
'layout.drop_feature', 'layout.drop_feature',
'no_layout_closure',
'cmap', 'cmap',
'cmap14', 'cmap14',
'sbix', 'sbix',
@ -63,8 +61,6 @@ tests = [
'post_apply_mvar_delta', 'post_apply_mvar_delta',
'apply_cvar_delta', 'apply_cvar_delta',
'collect_name_ids', 'collect_name_ids',
'instantiate_colrv1',
'instantiate_cff2_update_metrics',
] ]
repack_tests = [ repack_tests = [

View File

@ -16,8 +16,6 @@ class Test:
import re import re
if self.subset == '*': if self.subset == '*':
return self.subset[0] return self.subset[0]
elif self.subset == "no-unicodes":
return ""
elif re.match("^U\+", self.subset): elif re.match("^U\+", self.subset):
s = re.sub (r"U\+", "", self.subset) s = re.sub (r"U\+", "", self.subset)
return s return s
@ -51,11 +49,6 @@ class Test:
profile_name, profile_name,
self.instance_name(), self.instance_name(),
font_base_name_parts[1]) 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: else:
return "%s.%s.%s%s%s" % (font_base_name_parts[0], return "%s.%s.%s%s%s" % (font_base_name_parts[0],
profile_name, profile_name,

View File

@ -941,7 +941,6 @@ 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}, {"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}, {"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-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}, {"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}, {"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, {"preprocess-face", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->preprocess,