Bug 1832194 - Update harfbuzz to 7.3.0 r=gfx-reviewers,lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D177574
This commit is contained in:
Jonathan Kew 2023-05-16 14:40:39 +00:00
parent 0638b18b45
commit 4fca70d35e
120 changed files with 2573 additions and 5436 deletions

View File

@ -1,3 +1,52 @@
Overview of changes leading to 7.3.0
Tuesday, May 9, 2023
====================================
- Speedup applying glyph variation in VarComposites fonts (over 40% speedup).
(Behdad Esfahbod)
- Speedup instancing some fonts (over 20% speedup in instancing RobotoFlex).
(Behdad Esfahbod)
- Speedup shaping some fonts (over 30% speedup in shaping Roboto).
(Behdad Esfahbod)
- Support subsetting VarComposites and beyond-64k fonts. (Behdad Esfahbod)
- New configuration macro HB_MINIMIZE_MEMORY_USAGE to favor optimizing memory
usage over speed. (Behdad Esfahbod)
- Supporting setting the mapping between old and new glyph indices during
subsetting. (Garret Rieger)
- Various fixes and improvements.
(Behdad Esfahbod, Denis Rochette, Garret Rieger, Han Seung Min, Qunxin Liu)
- New API:
+hb_subset_input_old_to_new_glyph_mapping()
Overview of changes leading to 7.2.0
Thursday, April 27, 2023
====================================
- Add Tifinagh to the list of scripts that can natively be either right-to-left
or left-to-right, to improve handling of its glyph positioning.
(Simon Cozens)
- Return also single substitution from hb_ot_layout_lookup_get_glyph_alternates()
(Behdad Esfahbod)
- Fix 4.2.0 regression in applying across syllables in syllabic scripts.
(Behdad Esfahbod)
- Add flag to avoid glyph substitution closure during subsetting, and the
corresponding “--no-layout-closure” option to “hb-subset” command line tool.
(Garret Rieger)
- Support instancing COLRv1 table. (Qunxin Liu)
- Dont drop used user-defined name table entries during subsetting.
(Qunxin Liu)
- Optimize handling of “gvar” table. (Behdad Esfahbod)
- Various subsetter bug fixes and improvements. (Garret Rieger, Qunxin Liu)
- Various documentation improvements. (Behdad Esfahbod, Josef Friedrich)
- New API:
+HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE
+HB_UNICODE_COMBINING_CLASS_CCC132
- Deprecated API:
+HB_UNICODE_COMBINING_CLASS_CCC133
Overview of changes leading to 7.1.0
Friday, March 3, 2023
====================================
@ -8,6 +57,7 @@ Friday, March 3, 2023
- New API:
+hb_font_set_variation()
Overview of changes leading to 7.0.1
Monday, February 20, 2023
====================================

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[7.1.0],
[7.3.0],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@ -68,7 +68,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
])
# Functions and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale)
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale sincosf)
AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h)
# Compiler flags

View File

@ -20,11 +20,11 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: 7.1.0 (2023-03-03T01:01:49+02:00).
release: 7.3.0 (2023-05-10T00:20:25+03:00).
# Revision to pull in
# Must be a long or short commit SHA (long preferred)
revision: 7.1.0
revision: 7.3.0
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/
@ -60,6 +60,7 @@ vendoring:
- "**/.*"
- ".*"
- ".*/**"
- "src/test*"
- src/hb-ucdn
updatebot:

View File

@ -382,6 +382,7 @@ noinst_PROGRAMS = \
test-ot-name \
test-ot-glyphname \
test-gpos-size-params \
test-gsub-get-alternates \
test-gsub-would-substitute \
test-use-table \
$(NULL)
@ -419,6 +420,10 @@ test_gpos_size_params_SOURCES = test-gpos-size-params.cc
test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
test_gsub_get_alternates_SOURCES = test-gsub-get-alternates.cc
test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS)
test_gsub_get_alternates_LDADD = libharfbuzz.la $(HBLIBS)
test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)

View File

@ -362,6 +362,7 @@ HB_SUBSET_sources = \
hb-subset-accelerator.hh \
hb-subset-plan.cc \
hb-subset-plan.hh \
hb-subset-plan-member-list.hh \
hb-subset-repacker.cc \
hb-subset.cc \
hb-subset.hh \

View File

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

View File

@ -73,6 +73,30 @@ struct CPALV1Tail
}
public:
void collect_name_ids (const void *base,
unsigned palette_count,
unsigned color_count,
const hb_map_t *color_index_map,
hb_set_t *nameids_to_retain /* OUT */) const
{
if (paletteLabelsZ)
{
+ (base+paletteLabelsZ).as_array (palette_count)
| hb_sink (nameids_to_retain)
;
}
if (colorLabelsZ)
{
const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
for (unsigned i = 0; i < color_count; i++)
{
if (!color_index_map->has (i)) continue;
nameids_to_retain->add (colorLabels[i]);
}
}
}
bool serialize (hb_serialize_context_t *c,
unsigned palette_count,
unsigned color_count,
@ -95,13 +119,10 @@ struct CPALV1Tail
if (colorLabelsZ)
{
c->push ();
for (const auto _ : colorLabels)
for (unsigned i = 0; i < color_count; i++)
{
const hb_codepoint_t *v;
if (!color_index_map->has (_, &v)) continue;
NameID new_color_idx;
new_color_idx = *v;
if (!c->copy<NameID> (new_color_idx))
if (!color_index_map->has (i)) continue;
if (!c->copy<NameID> (colorLabels[i]))
{
c->pop_discard ();
return_trace (false);
@ -189,6 +210,13 @@ struct CPAL
return numColors;
}
void collect_name_ids (const hb_map_t *color_index_map,
hb_set_t *nameids_to_retain /* OUT */) const
{
if (version == 1)
v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
}
private:
const CPALV1Tail& v1 () const
{

View File

@ -113,22 +113,33 @@ struct Coverage
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned count = 0;
unsigned count = hb_len (glyphs);
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
hb_codepoint_t max = 0;
bool unsorted = false;
for (auto g: glyphs)
{
if (last != (hb_codepoint_t) -2 && g < last)
unsorted = true;
if (last + 1 != g)
num_ranges++;
num_ranges++;
last = g;
count++;
if (g > max) max = g;
}
u.format = count <= num_ranges * 3 ? 1 : 2;
u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
#ifndef HB_NO_BEYOND_64K
if (count && last > 0xFFFFu)
if (max > 0xFFFFu)
u.format += 2;
if (unlikely (max > 0xFFFFFFu))
#else
if (unlikely (max > 0xFFFFu))
#endif
{
c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
return_trace (false);
}
switch (u.format)
{
@ -148,8 +159,8 @@ struct Coverage
auto it =
+ iter ()
| hb_take (c->plan->source->get_num_glyphs ())
| hb_filter (c->plan->glyph_map_gsub)
| hb_map_retains_sorting (c->plan->glyph_map_gsub)
| hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
// Cache the iterator result as it will be iterated multiple times

View File

@ -95,19 +95,26 @@ struct CoverageFormat2_4
unsigned count = 0;
unsigned range = (unsigned) -1;
last = (hb_codepoint_t) -2;
unsigned unsorted = false;
for (auto g: glyphs)
{
if (last + 1 != g)
{
if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g))
unsorted = true;
range++;
rangeRecord[range].first = g;
rangeRecord[range].value = count;
rangeRecord.arrayZ[range].first = g;
rangeRecord.arrayZ[range].value = count;
}
rangeRecord[range].last = g;
rangeRecord.arrayZ[range].last = g;
last = g;
count++;
}
if (unlikely (unsorted))
rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
return_trace (true);
}
@ -185,8 +192,8 @@ struct CoverageFormat2_4
if (__more__ ())
{
unsigned int old = coverage;
j = c->rangeRecord[i].first;
coverage = c->rangeRecord[i].value;
j = c->rangeRecord.arrayZ[i].first;
coverage = c->rangeRecord.arrayZ[i].value;
if (unlikely (coverage != old + 1))
{
/* Broken table. Skip. Important to avoid DoS.

View File

@ -51,6 +51,18 @@ struct RangeRecord
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
HB_INTERNAL static int cmp_range (const void *pa, const void *pb) {
const RangeRecord *a = (const RangeRecord *) pa;
const RangeRecord *b = (const RangeRecord *) pb;
if (a->first < b->first) return -1;
if (a->first > b->first) return +1;
if (a->last < b->last) return -1;
if (a->last > b->last) return +1;
if (a->value < b->value) return -1;
if (a->value > b->value) return +1;
return 0;
}
unsigned get_population () const
{
if (unlikely (last < first)) return 0;

View File

@ -32,6 +32,7 @@
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-font.hh"
#include "../../../hb-cache.hh"
namespace OT {
@ -861,7 +862,30 @@ struct GDEF
}
~accelerator_t () { table.destroy (); }
unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
unsigned v;
#ifndef HB_NO_GDEF_CACHE
if (glyph_props_cache.get (glyph, &v))
return v;
#endif
v = table->get_glyph_props (glyph);
#ifndef HB_NO_GDEF_CACHE
if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
glyph_props_cache.set (glyph, v);
#endif
return v;
}
hb_blob_ptr_t<GDEF> table;
#ifndef HB_NO_GDEF_CACHE
mutable hb_cache_t<21, 3, 8> glyph_props_cache;
#endif
};
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const

View File

@ -122,9 +122,9 @@ struct CursivePosFormat1
if (!this_record.entryAnchor) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.reset_fast (buffer->idx, 1);
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
if (unlikely (!skippy_iter.prev (&unsafe_from)))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);

View File

@ -156,7 +156,7 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
for (unsigned i = 0; i < len; i++)
if (unlikely (pos[i].y_offset))
pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);
}
}

View File

@ -100,16 +100,16 @@ struct MarkMarkPosFormat1_2
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.reset_fast (buffer->idx, 1);
skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
if (unlikely (!skippy_iter.prev (&unsafe_from)))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);

View File

@ -55,7 +55,7 @@ struct PairPosFormat1_3
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
{
for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
for (hb_codepoint_t g : glyphs->iter())
{
unsigned i = cov.get_coverage (g);
if ((this+pairSet[i]).intersects (glyphs, valueFormat))
@ -110,9 +110,9 @@ struct PairPosFormat1_3
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.reset_fast (buffer->idx, 1);
unsigned unsafe_to;
if (!skippy_iter.next (&unsafe_to))
if (unlikely (!skippy_iter.next (&unsafe_to)))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);

View File

@ -50,11 +50,10 @@ struct PairPosFormat2_4
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int stride = HBUINT16::static_size * (len1 + len2);
unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_range ((const void *) values,
count,
record_size) &&
stride) &&
valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
}
@ -131,26 +130,32 @@ struct PairPosFormat2_4
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.reset_fast (buffer->idx, 1);
unsigned unsafe_to;
if (!skippy_iter.next (&unsafe_to))
if (unlikely (!skippy_iter.next (&unsafe_to)))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
}
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (!klass2)
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
return_trace (false);
}
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
return_trace (false);
}
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int record_len = len1 + len2;
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
return_trace (false);
}
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
bool applied_first = false, applied_second = false;
@ -164,7 +169,7 @@ struct PairPosFormat2_4
* https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
*/
#ifndef HB_SPLIT_KERN
if (0)
if (false)
#endif
{
if (!len2)
@ -224,8 +229,8 @@ struct PairPosFormat2_4
c->buffer->idx, skippy_iter.idx);
}
applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos());
applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())

View File

@ -120,8 +120,8 @@ struct PairSet
c->buffer->idx, pos);
}
bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())

View File

@ -10,7 +10,7 @@ namespace GSUB_impl {
template <typename Types>
struct Ligature
{
protected:
public:
typename Types::HBGlyphID
ligGlyph; /* GlyphID of ligature to substitute */
HeadlessArrayOf<typename Types::HBGlyphID>
@ -29,6 +29,9 @@ struct Ligature
bool intersects (const hb_set_t *glyphs) const
{ return hb_all (component, glyphs); }
bool intersects_lig_glyph (const hb_set_t *glyphs) const
{ return glyphs->has(ligGlyph); }
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;

View File

@ -34,6 +34,18 @@ struct LigatureSet
;
}
bool intersects_lig_glyph (const hb_set_t *glyphs) const
{
return
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_map ([glyphs] (const Ligature<Types> &_) {
return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
})
| hb_any
;
}
void closure (hb_closure_context_t *c) const
{
+ hb_iter (ligature)
@ -60,15 +72,73 @@ struct LigatureSet
;
}
static bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED)
{
return true;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
unsigned int num_ligs = ligature.len;
#ifndef HB_NO_OT_LIGATURES_FAST_PATH
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 2)
#endif
{
slow:
for (unsigned int i = 0; i < num_ligs; i++)
{
const auto &lig = this+ligature.arrayZ[i];
if (lig.apply (c)) return_trace (true);
}
return_trace (false);
}
/* This version is optimized for speed by matching the first component
* of the ligature here, instead of calling into the ligation code. */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (c->buffer->idx, 1);
skippy_iter.set_match_func (match_always, nullptr);
skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
unsigned unsafe_to;
hb_codepoint_t first = (unsigned) -1;
bool matched = skippy_iter.next (&unsafe_to);
if (likely (matched))
{
first = c->buffer->info[skippy_iter.idx].codepoint;
unsafe_to = skippy_iter.idx + 1;
if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
{
/* Can't use the fast path if eg. the next char is a default-ignorable
* or other skippable. */
goto slow;
}
}
bool unsafe_to_concat = false;
for (unsigned int i = 0; i < num_ligs; i++)
{
const auto &lig = this+ligature[i];
if (lig.apply (c)) return_trace (true);
const auto &lig = this+ligature.arrayZ[i];
if (unlikely (lig.component.lenP1 <= 1) ||
lig.component[1] == first)
{
if (lig.apply (c))
{
if (unsafe_to_concat)
c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
return_trace (true);
}
}
else if (likely (lig.component.lenP1 > 1))
unsafe_to_concat = true;
}
if (likely (unsafe_to_concat))
c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
return_trace (false);
}

View File

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

View File

@ -57,7 +57,7 @@ struct SingleSubst
#ifndef HB_NO_BEYOND_64K
if (+ glyphs
| hb_map_retains_sorting (hb_first)
| hb_map_retains_sorting (hb_second)
| hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
{
format += 2;

View File

@ -95,6 +95,34 @@ struct SingleSubstFormat1_3
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
unsigned
get_glyph_alternates (hb_codepoint_t glyph_id,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED))
{
if (alternate_count)
*alternate_count = 0;
return 0;
}
if (alternate_count && *alternate_count)
{
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
glyph_id = (glyph_id + d) & mask;
*alternate_glyphs = glyph_id;
*alternate_count = 1;
}
return 1;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View File

@ -75,6 +75,31 @@ struct SingleSubstFormat2_4
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
unsigned
get_glyph_alternates (hb_codepoint_t glyph_id,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED))
{
if (alternate_count)
*alternate_count = 0;
return 0;
}
if (alternate_count && *alternate_count)
{
glyph_id = substitute[index];
*alternate_glyphs = glyph_id;
*alternate_count = 1;
}
return 1;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View File

@ -87,27 +87,58 @@ struct CompositeGlyphRecord
}
}
void transform_points (contour_point_vector_t &points) const
static void transform (const float (&matrix)[4],
hb_array_t<contour_point_t> points)
{
float matrix[4];
contour_point_t trans;
if (get_transformation (matrix, trans))
auto arrayZ = points.arrayZ;
unsigned count = points.length;
if (matrix[0] != 1.f || matrix[1] != 0.f ||
matrix[2] != 0.f || matrix[3] != 1.f)
for (unsigned i = 0; i < count; i++)
arrayZ[i].transform (matrix);
}
static void translate (const contour_point_t &trans,
hb_array_t<contour_point_t> points)
{
auto arrayZ = points.arrayZ;
unsigned count = points.length;
if (trans.x != 0.f || trans.y != 0.f)
for (unsigned i = 0; i < count; i++)
arrayZ[i].translate (trans);
}
void transform_points (hb_array_t<contour_point_t> points,
const float (&matrix)[4],
const contour_point_t &trans) const
{
if (scaled_offsets ())
{
if (scaled_offsets ())
{
points.translate (trans);
points.transform (matrix);
}
else
{
points.transform (matrix);
points.translate (trans);
}
translate (trans, points);
transform (matrix, points);
}
else
{
transform (matrix, points);
translate (trans, points);
}
}
unsigned compile_with_deltas (const contour_point_t &p_delta,
char *out) const
bool get_points (contour_point_vector_t &points) const
{
float matrix[4];
contour_point_t trans;
get_transformation (matrix, trans);
points.alloc (points.length + 4); // For phantom points
if (unlikely (!points.resize (points.length + 1))) return false;
points.arrayZ[points.length - 1] = trans;
return true;
}
unsigned compile_with_point (const contour_point_t &point,
char *out) const
{
const HBINT8 *p = &StructAfter<const HBINT8> (flags);
#ifndef HB_NO_BEYOND_64K
@ -121,18 +152,17 @@ struct CompositeGlyphRecord
unsigned len_before_val = (const char *)p - (const char *)this;
if (flags & ARG_1_AND_2_ARE_WORDS)
{
// no overflow, copy and update value with deltas
// no overflow, copy value
hb_memcpy (out, this, len);
const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
o[0] = px[0] + roundf (p_delta.x);
o[1] = px[1] + roundf (p_delta.y);
o[0] = roundf (point.x);
o[1] = roundf (point.y);
}
else
{
int new_x = p[0] + roundf (p_delta.x);
int new_y = p[1] + roundf (p_delta.y);
int new_x = roundf (point.x);
int new_y = roundf (point.y);
if (new_x <= 127 && new_x >= -128 &&
new_y <= 127 && new_y >= -128)
{
@ -143,7 +173,7 @@ struct CompositeGlyphRecord
}
else
{
// int8 overflows after deltas applied
// new point value has an int8 overflow
hb_memcpy (out, this, len_before_val);
//update flags
@ -171,6 +201,7 @@ struct CompositeGlyphRecord
bool scaled_offsets () const
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
public:
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
{
matrix[0] = matrix[3] = 1.f;
@ -225,7 +256,6 @@ struct CompositeGlyphRecord
return tx || ty;
}
public:
hb_codepoint_t get_gid () const
{
#ifndef HB_NO_BEYOND_64K
@ -246,6 +276,27 @@ struct CompositeGlyphRecord
StructAfter<HBGlyphID16> (flags) = gid;
}
#ifndef HB_NO_BEYOND_64K
void lower_gid_24_to_16 ()
{
hb_codepoint_t gid = get_gid ();
if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
return;
/* Lower the flag and move the rest of the struct down. */
unsigned size = get_size ();
char *end = (char *) this + size;
char *p = &StructAfter<char> (flags);
p += HBGlyphID24::static_size;
flags = flags & ~GID_IS_24BIT;
set_gid (gid);
memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
}
#endif
protected:
HBUINT16 flags;
HBUINT24 pad;
@ -304,7 +355,7 @@ struct CompositeGlyph
}
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
const contour_point_vector_t &deltas,
const contour_point_vector_t &points_with_deltas,
hb_bytes_t &dest_bytes /* OUT */)
{
if (source_bytes.length <= GlyphHeader::static_size ||
@ -319,7 +370,7 @@ struct CompositeGlyph
/* try to allocate more memories than source glyph bytes
* in case that there might be an overflow for int8 value
* and we would need to use int16 instead */
char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
if (unlikely (!o)) return false;
const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
@ -329,8 +380,11 @@ struct CompositeGlyph
unsigned i = 0, source_comp_len = 0;
for (const auto &component : it)
{
/* last 4 points in deltas are phantom points and should not be included */
if (i >= deltas.length - 4) return false;
/* last 4 points in points_with_deltas are phantom points and should not be included */
if (i >= points_with_deltas.length - 4) {
free (o);
return false;
}
unsigned comp_len = component.get_size ();
if (component.is_anchored ())
@ -340,7 +394,7 @@ struct CompositeGlyph
}
else
{
unsigned new_len = component.compile_with_deltas (deltas[i], p);
unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
p += new_len;
}
i++;

View File

@ -29,7 +29,14 @@ enum phantom_point_index_t
struct Glyph
{
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
enum glyph_type_t {
EMPTY,
SIMPLE,
COMPOSITE,
#ifndef HB_NO_VAR_COMPOSITES
VAR_COMPOSITE,
#endif
};
public:
composite_iter_t get_composite_iterator () const
@ -39,15 +46,23 @@ struct Glyph
}
var_composite_iter_t get_var_composite_iterator () const
{
#ifndef HB_NO_VAR_COMPOSITES
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
return VarCompositeGlyph (*header, bytes).iter ();
#else
return var_composite_iter_t ();
#endif
}
const hb_bytes_t trim_padding () const
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
#endif
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
case EMPTY: return bytes;
default: return bytes;
}
}
@ -55,27 +70,36 @@ struct Glyph
void drop_hints ()
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
default: return;
case EMPTY: return;
}
}
void set_overlaps_flag ()
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No overlaps flag
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
default: return;
case EMPTY: return;
}
}
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
default: return;
case EMPTY: return;
}
}
@ -131,24 +155,28 @@ struct Glyph
{
xMin = xMax = all_points[0].x;
yMin = yMax = all_points[0].y;
unsigned count = all_points.length - 4;
for (unsigned i = 1; i < count; i++)
{
float x = all_points[i].x;
float y = all_points[i].y;
xMin = hb_min (xMin, x);
xMax = hb_max (xMax, x);
yMin = hb_min (yMin, y);
yMax = hb_max (yMax, y);
}
}
for (unsigned i = 1; i < all_points.length - 4; i++)
{
float x = all_points[i].x;
float y = all_points[i].y;
xMin = hb_min (xMin, x);
xMax = hb_max (xMax, x);
yMin = hb_min (yMin, y);
yMax = hb_max (yMax, y);
}
update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points);
int rounded_xMin = roundf (xMin);
int rounded_xMax = roundf (xMax);
int rounded_yMin = roundf (yMin);
int rounded_yMax = roundf (yMax);
// These are destined for storage in a 16 bit field to clamp the values to
// fit into a 16 bit signed integer.
int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
if (type != EMPTY)
{
@ -181,7 +209,7 @@ struct Glyph
hb_bytes_t &dest_start, /* IN/OUT */
hb_bytes_t &dest_end /* OUT */)
{
contour_point_vector_t all_points, deltas;
contour_point_vector_t all_points, points_with_deltas;
unsigned composite_contours = 0;
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
unsigned *composite_contours_p = &composite_contours;
@ -195,7 +223,7 @@ struct Glyph
composite_contours_p = nullptr;
}
if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
@ -209,11 +237,20 @@ struct Glyph
}
//dont compile bytes when pinned at default, just recalculate bounds
if (!plan->pinned_at_default) {
switch (type) {
if (!plan->pinned_at_default)
{
switch (type)
{
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
// TODO
dest_end = hb_bytes_t ();
break;
#endif
case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
deltas,
points_with_deltas,
dest_end))
return false;
break;
@ -223,7 +260,7 @@ struct Glyph
dest_end))
return false;
break;
default:
case EMPTY:
/* set empty bytes for empty glyph
* do not use source glyph's pointers */
dest_start = hb_bytes_t ();
@ -247,7 +284,7 @@ struct Glyph
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
contour_point_vector_t *deltas = nullptr, /* OUT */
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
bool shift_points_hori = true,
@ -262,7 +299,7 @@ struct Glyph
if (!edge_count) edge_count = &stack_edge_count;
if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
(*edge_count)++;
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@ -272,9 +309,8 @@ struct Glyph
coords = hb_array (font->coords, font->num_coords);
contour_point_vector_t stack_points;
bool inplace = type == SIMPLE && all_points.length == 0;
/* Load into all_points if it's empty, as an optimization. */
contour_point_vector_t &points = inplace ? all_points : stack_points;
contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
unsigned old_length = points.length;
switch (type) {
case SIMPLE:
@ -282,14 +318,13 @@ struct Glyph
head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
if (depth > 0 && composite_contours)
*composite_contours += (unsigned) header->numberOfContours;
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
return false;
break;
case COMPOSITE:
{
/* pseudo component points for each component in composite glyph */
unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
if (unlikely (!points.resize (num_points))) return false;
for (auto &item : get_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
break;
}
#ifndef HB_NO_VAR_COMPOSITES
@ -297,9 +332,10 @@ struct Glyph
{
for (auto &item : get_var_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
break;
}
#endif
default:
case EMPTY:
break;
}
@ -327,53 +363,43 @@ struct Glyph
#endif
;
phantoms[PHANTOM_LEFT].x = h_delta;
phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
phantoms[PHANTOM_TOP].y = v_orig;
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
{
if (unlikely (!deltas->resize (points.length))) return false;
deltas->copy_vector (points);
}
#ifndef HB_NO_VAR
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ());
points.as_array ().sub_array (old_length));
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
// with child glyphs' points
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
{
for (unsigned i = 0 ; i < points.length; i++)
{
deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
}
if (unlikely (!points_with_deltas->resize (points.length))) return false;
points_with_deltas->copy_vector (points);
}
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
if (!inplace)
all_points.extend (points.as_array ());
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
break;
case COMPOSITE:
{
contour_point_vector_t comp_points;
unsigned int comp_index = 0;
for (auto &item : get_composite_iterator ())
{
comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
unsigned old_count = all_points.length;
if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font,
glyf_accelerator,
comp_points,
deltas,
all_points,
points_with_deltas,
head_maxp_info,
composite_contours,
shift_points_hori,
@ -384,16 +410,19 @@ struct Glyph
edge_count)))
return false;
auto comp_points = all_points.as_array ().sub_array (old_count);
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
/* Apply component transformation & translation */
item.transform_points (comp_points);
float matrix[4];
contour_point_t default_trans;
item.get_transformation (matrix, default_trans);
/* Apply translation from gvar */
comp_points.translate (points[comp_index]);
/* Apply component transformation & translation (with deltas applied) */
item.transform_points (comp_points, matrix, points[comp_index]);
if (item.is_anchored ())
{
@ -405,11 +434,11 @@ struct Glyph
delta.init (all_points[p1].x - comp_points[p2].x,
all_points[p1].y - comp_points[p2].y);
comp_points.translate (delta);
item.translate (delta, comp_points);
}
}
all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
all_points.resize (all_points.length - PHANTOM_COUNT);
if (all_points.length > HB_GLYF_MAX_POINTS)
return false;
@ -429,13 +458,12 @@ struct Glyph
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
contour_point_vector_t comp_points;
hb_array_t<contour_point_t> points_left = points.as_array ();
for (auto &item : get_var_composite_iterator ())
{
hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ());
comp_points.reset ();
unsigned item_num_points = item.get_num_points ();
hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
assert (record_points.length == item_num_points);
auto component_coords = coords;
if (item.is_reset_unspecified_axes ())
@ -444,11 +472,14 @@ struct Glyph
coord_setter_t coord_setter (component_coords);
item.set_variations (coord_setter, record_points);
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
unsigned old_count = all_points.length;
if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font,
glyf_accelerator,
comp_points,
deltas,
all_points,
points_with_deltas,
head_maxp_info,
nullptr,
shift_points_hori,
@ -459,25 +490,28 @@ struct Glyph
edge_count)))
return false;
auto comp_points = all_points.as_array ().sub_array (old_count);
/* Apply component transformation */
item.transform_points (record_points, comp_points);
if (comp_points) // Empty in case of phantom_only
item.transform_points (record_points, comp_points);
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
all_points.resize (all_points.length - PHANTOM_COUNT);
if (all_points.length > HB_GLYF_MAX_POINTS)
return false;
points_left += item.get_num_points ();
points_left += item_num_points;
}
all_points.extend (phantoms);
} break;
#endif
default:
case EMPTY:
all_points.extend (phantoms);
break;
}
@ -487,9 +521,10 @@ struct Glyph
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
contour_point_t delta;
delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
if (delta.x) all_points.translate (delta);
int v = -phantoms[PHANTOM_LEFT].x;
if (v)
for (auto &point : all_points)
point.x += v;
}
return !all_points.in_error ();
@ -503,6 +538,8 @@ struct Glyph
}
hb_bytes_t get_bytes () const { return bytes; }
glyph_type_t get_type () const { return type; }
const GlyphHeader *get_header () const { return header; }
Glyph () : bytes (),
header (bytes.as<GlyphHeader> ()),
@ -518,15 +555,18 @@ struct Glyph
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
else if (num_contours == -1) type = COMPOSITE;
#ifndef HB_NO_VAR_COMPOSITES
else if (num_contours == -2) type = VAR_COMPOSITE;
else type = COMPOSITE; /* negative numbers */
#endif
else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
}
protected:
hb_bytes_t bytes;
const GlyphHeader *header;
hb_codepoint_t gid;
unsigned type;
glyph_type_t type;
};

View File

@ -34,6 +34,11 @@ struct SimpleGlyph
unsigned int length (unsigned int instruction_len) const
{ return instruction_len_offset () + 2 + instruction_len; }
bool has_instructions_length () const
{
return instruction_len_offset () + 2 <= bytes.length;
}
unsigned int instructions_length () const
{
unsigned int instruction_length_offset = instruction_len_offset ();
@ -94,6 +99,7 @@ struct SimpleGlyph
/* zero instruction length */
void drop_hints ()
{
if (!has_instructions_length ()) return;
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
}
@ -118,7 +124,7 @@ struct SimpleGlyph
}
static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
contour_point_vector_t &points_ /* IN/OUT */,
hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end)
{
unsigned count = points_.length;
@ -140,7 +146,7 @@ struct SimpleGlyph
}
static bool read_points (const HBUINT8 *&p /* IN/OUT */,
contour_point_vector_t &points_ /* IN/OUT */,
hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end,
float contour_point_t::*m,
const simple_glyph_flag_t short_flag,
@ -151,7 +157,7 @@ struct SimpleGlyph
unsigned count = points_.length;
for (unsigned i = 0; i < count; i++)
{
unsigned flag = points_[i].flag;
unsigned flag = points_.arrayZ[i].flag;
if (flag & short_flag)
{
if (unlikely (p + 1 > end)) return false;
@ -174,18 +180,21 @@ struct SimpleGlyph
return true;
}
bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
bool get_contour_points (contour_point_vector_t &points /* OUT */,
bool phantom_only = false) const
{
const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
int num_contours = header.numberOfContours;
assert (num_contours);
assert (num_contours > 0);
/* One extra item at the end, for the instruction-count below. */
if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
if (!points_.resize (num_points)) return false;
unsigned old_length = points.length;
points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
if (!points.resize (points.length + num_points, false)) return false;
auto points_ = points.as_array ().sub_array (old_length);
hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
if (phantom_only) return true;
for (int i = 0; i < num_contours; i++)
@ -208,7 +217,7 @@ struct SimpleGlyph
}
static void encode_coord (int value,
uint8_t &flag,
unsigned &flag,
const simple_glyph_flag_t short_flag,
const simple_glyph_flag_t same_flag,
hb_vector_t<uint8_t> &coords /* OUT */)
@ -233,9 +242,9 @@ struct SimpleGlyph
}
}
static void encode_flag (uint8_t &flag,
uint8_t &repeat,
uint8_t lastflag,
static void encode_flag (unsigned flag,
unsigned &repeat,
unsigned lastflag,
hb_vector_t<uint8_t> &flags /* OUT */)
{
if (flag == lastflag && repeat != 255)
@ -256,7 +265,7 @@ struct SimpleGlyph
else
{
repeat = 0;
flags.push (flag);
flags.arrayZ[flags.length++] = flag;
}
}
@ -276,13 +285,13 @@ struct SimpleGlyph
if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
uint8_t lastflag = 255, repeat = 0;
unsigned lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0;
for (unsigned i = 0; i < num_points; i++)
{
uint8_t flag = all_points.arrayZ[i].flag;
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
unsigned flag = all_points.arrayZ[i].flag;
flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC;
int cur_x = roundf (all_points.arrayZ[i].x);
int cur_y = roundf (all_points.arrayZ[i].y);

View File

@ -18,6 +18,7 @@ struct SubsetGlyph
Glyph source_glyph;
hb_bytes_t dest_start; /* region of source_glyph to copy first */
hb_bytes_t dest_end; /* region of source_glyph to copy second */
bool allocated;
bool serialize (hb_serialize_context_t *c,
bool use_short_loca,
@ -26,7 +27,12 @@ struct SubsetGlyph
TRACE_SERIALIZE (this);
hb_bytes_t dest_glyph = dest_start.copy (c);
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
hb_bytes_t end_copy = dest_end.copy (c);
if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
return false;
}
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
unsigned int pad_length = use_short_loca ? padding () : 0;
DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
@ -40,13 +46,68 @@ struct SubsetGlyph
if (unlikely (!dest_glyph.length)) return_trace (true);
/* update components gids */
/* update components gids. */
for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
}
#ifndef HB_NO_VAR_COMPOSITES
for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
}
#endif
#ifndef HB_NO_BEYOND_64K
auto it = Glyph (dest_glyph).get_composite_iterator ();
if (it)
{
/* lower GID24 to GID16 in components if possible.
*
* TODO: VarComposite. Not as critical, since VarComposite supports
* gid24 from the first version. */
char *p = it ? (char *) &*it : nullptr;
char *q = p;
const char *end = dest_glyph.arrayZ + dest_glyph.length;
while (it)
{
auto &rec = const_cast<CompositeGlyphRecord &> (*it);
++it;
q += rec.get_size ();
rec.lower_gid_24_to_16 ();
unsigned size = rec.get_size ();
memmove (p, &rec, size);
p += size;
}
memmove (p, q, end - q);
p += end - q;
/* We want to shorten the glyph, but we can't do that without
* updating the length in the loca table, which is already
* written out :-(. So we just fill the rest of the glyph with
* harmless instructions, since that's what they will be
* interpreted as.
*
* Should move the lowering to _populate_subset_glyphs() to
* fix this issue. */
hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
p += end - p;
dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);
// TODO: Padding; & trim serialized bytes.
// TODO: Update length in loca. Ugh.
}
#endif
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
Glyph (dest_glyph).drop_hints ();
@ -60,12 +121,18 @@ struct SubsetGlyph
bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
hb_font_t *font,
const glyf_accelerator_t &glyf)
{ return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); }
{
allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end);
return allocated;
}
void free_compiled_bytes ()
{
dest_start.fini ();
dest_end.fini ();
if (likely (allocated)) {
allocated = false;
dest_start.fini ();
dest_end.fini ();
}
}
void drop_hints_bytes ()

View File

@ -27,7 +27,7 @@ struct VarCompositeGlyphRecord
HAVE_SKEW_Y = 0x0200,
HAVE_TCENTER_X = 0x0400,
HAVE_TCENTER_Y = 0x0800,
GID_IS_24 = 0x1000,
GID_IS_24BIT = 0x1000,
AXES_HAVE_VARIATION = 0x2000,
RESET_UNSPECIFIED_AXES = 0x4000,
};
@ -36,24 +36,21 @@ struct VarCompositeGlyphRecord
unsigned int get_size () const
{
unsigned fl = flags;
unsigned int size = min_size;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
size += numAxes * axis_width;
// gid
size += 2;
if (flags & GID_IS_24) size += 1;
if (fl & GID_IS_24BIT) size += 1;
if (flags & HAVE_TRANSLATE_X) size += 2;
if (flags & HAVE_TRANSLATE_Y) size += 2;
if (flags & HAVE_ROTATION) size += 2;
if (flags & HAVE_SCALE_X) size += 2;
if (flags & HAVE_SCALE_Y) size += 2;
if (flags & HAVE_SKEW_X) size += 2;
if (flags & HAVE_SKEW_Y) size += 2;
if (flags & HAVE_TCENTER_X) size += 2;
if (flags & HAVE_TCENTER_Y) size += 2;
// 2 bytes each for the following flags
fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y |
HAVE_ROTATION |
HAVE_SCALE_X | HAVE_SCALE_Y |
HAVE_SKEW_X | HAVE_SKEW_Y |
HAVE_TCENTER_X | HAVE_TCENTER_Y);
size += hb_popcount (fl) * 2;
return size;
}
@ -65,10 +62,18 @@ struct VarCompositeGlyphRecord
hb_codepoint_t get_gid () const
{
if (flags & GID_IS_24)
return StructAfter<const HBGlyphID24> (numAxes);
if (flags & GID_IS_24BIT)
return * (const HBGlyphID24 *) &pad;
else
return StructAfter<const HBGlyphID16> (numAxes);
return * (const HBGlyphID16 *) &pad;
}
void set_gid (hb_codepoint_t gid)
{
if (flags & GID_IS_24BIT)
* (HBGlyphID24 *) &pad = gid;
else
* (HBGlyphID16 *) &pad = gid;
}
unsigned get_numAxes () const
@ -78,26 +83,44 @@ struct VarCompositeGlyphRecord
unsigned get_num_points () const
{
unsigned fl = flags;
unsigned num = 0;
if (flags & AXES_HAVE_VARIATION) num += numAxes;
if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
if (flags & HAVE_ROTATION) num++;
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
if (fl & AXES_HAVE_VARIATION) num += numAxes;
/* Hopefully faster code, relying on the value of the flags. */
fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) &
(HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X);
num += hb_popcount (fl);
return num;
/* Slower but more readable code. */
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
if (fl & HAVE_ROTATION) num++;
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
return num;
}
void transform_points (hb_array_t<contour_point_t> record_points,
contour_point_vector_t &points) const
void transform_points (hb_array_t<const contour_point_t> record_points,
hb_array_t<contour_point_t> points) const
{
float matrix[4];
contour_point_t trans;
get_transformation_from_points (record_points, matrix, trans);
get_transformation_from_points (record_points.arrayZ, matrix, trans);
points.transform (matrix);
points.translate (trans);
auto arrayZ = points.arrayZ;
unsigned count = points.length;
if (matrix[0] != 1.f || matrix[1] != 0.f ||
matrix[2] != 0.f || matrix[3] != 1.f)
for (unsigned i = 0; i < count; i++)
arrayZ[i].transform (matrix);
if (trans.x != 0.f || trans.y != 0.f)
for (unsigned i = 0; i < count; i++)
arrayZ[i].translate (trans);
}
static inline void transform (float (&matrix)[4], contour_point_t &trans,
@ -128,26 +151,41 @@ struct VarCompositeGlyphRecord
static void translate (float (&matrix)[4], contour_point_t &trans,
float translateX, float translateY)
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213
float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY};
transform (matrix, trans, other);
if (!translateX && !translateY)
return;
trans.x += matrix[0] * translateX + matrix[2] * translateY;
trans.y += matrix[1] * translateX + matrix[3] * translateY;
}
static void scale (float (&matrix)[4], contour_point_t &trans,
float scaleX, float scaleY)
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224
float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f};
transform (matrix, trans, other);
if (scaleX == 1.f && scaleY == 1.f)
return;
matrix[0] *= scaleX;
matrix[1] *= scaleX;
matrix[2] *= scaleY;
matrix[3] *= scaleY;
}
static void rotate (float (&matrix)[4], contour_point_t &trans,
float rotation)
{
if (!rotation)
return;
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
rotation = rotation * float (M_PI);
float c = cosf (rotation);
float s = sinf (rotation);
rotation = rotation * HB_PI;
float c;
float s;
#ifdef HAVE_SINCOSF
sincosf (rotation, &s, &c);
#else
c = cosf (rotation);
s = sinf (rotation);
#endif
float other[6] = {c, s, -s, c, 0.f, 0.f};
transform (matrix, trans, other);
}
@ -155,99 +193,100 @@ struct VarCompositeGlyphRecord
static void skew (float (&matrix)[4], contour_point_t &trans,
float skewX, float skewY)
{
if (!skewX && !skewY)
return;
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
skewX = skewX * float (M_PI);
skewY = skewY * float (M_PI);
float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f};
skewX = skewX * HB_PI;
skewY = skewY * HB_PI;
float other[6] = {1.f,
skewY ? tanf (skewY) : 0.f,
skewX ? tanf (skewX) : 0.f,
1.f,
0.f, 0.f};
transform (matrix, trans, other);
}
bool get_points (contour_point_vector_t &points) const
{
float translateX = 0.f;
float translateY = 0.f;
float rotation = 0.f;
float scaleX = 1.f * (1 << 10);
float scaleY = 1.f * (1 << 10);
float skewX = 0.f;
float skewY = 0.f;
float tCenterX = 0.f;
float tCenterY = 0.f;
unsigned num_points = get_num_points ();
if (unlikely (!points.resize (points.length + get_num_points ()))) return false;
points.alloc (points.length + num_points + 4); // For phantom points
if (unlikely (!points.resize (points.length + num_points, false))) return false;
contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
memset (rec_points, 0, num_points * sizeof (rec_points[0]));
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
unsigned axes_size = numAxes * axis_width;
unsigned fl = flags;
unsigned num_axes = numAxes;
unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
unsigned axes_size = num_axes * axis_width;
const F2DOT14 *q = (const F2DOT14 *) (axes_size +
(flags & GID_IS_24 ? 3 : 2) +
&StructAfter<const HBUINT8> (numAxes));
(fl & GID_IS_24BIT ? 3 : 2) +
(const HBUINT8 *) &pad);
hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ());
unsigned count = numAxes;
if (flags & AXES_HAVE_VARIATION)
unsigned count = num_axes;
if (fl & AXES_HAVE_VARIATION)
{
for (unsigned i = 0; i < count; i++)
rec_points[i].x = q++->to_int ();
rec_points += count;
rec_points++->x = q++->to_int ();
}
else
q += count;
const HBUINT16 *p = (const HBUINT16 *) q;
if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++;
if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++;
if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int ();
if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int ();
if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++;
if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++;
if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y))
scaleY = scaleX;
if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
rec_points[0].x = translateX;
rec_points[0].y = translateY;
int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0;
int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0;
rec_points->x = translateX;
rec_points->y = translateY;
rec_points++;
}
if (flags & HAVE_ROTATION)
if (fl & HAVE_ROTATION)
{
rec_points[0].x = rotation;
int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0;
rec_points->x = rotation;
rec_points++;
}
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
rec_points[0].x = scaleX;
rec_points[0].y = scaleY;
int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y))
scaleY = scaleX;
rec_points->x = scaleX;
rec_points->y = scaleY;
rec_points++;
}
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
rec_points[0].x = skewX;
rec_points[0].y = skewY;
int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0;
int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0;
rec_points->x = skewX;
rec_points->y = skewY;
rec_points++;
}
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
rec_points[0].x = tCenterX;
rec_points[0].y = tCenterY;
int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0;
int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0;
rec_points->x = tCenterX;
rec_points->y = tCenterY;
rec_points++;
}
assert (!rec_points);
return true;
}
void get_transformation_from_points (hb_array_t<contour_point_t> rec_points,
void get_transformation_from_points (const contour_point_t *rec_points,
float (&matrix)[4], contour_point_t &trans) const
{
if (flags & AXES_HAVE_VARIATION)
unsigned fl = flags;
if (fl & AXES_HAVE_VARIATION)
rec_points += numAxes;
matrix[0] = matrix[3] = 1.f;
@ -264,36 +303,35 @@ struct VarCompositeGlyphRecord
float tCenterX = 0.f;
float tCenterY = 0.f;
if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
translateX = rec_points[0].x;
translateY = rec_points[0].y;
translateX = rec_points->x;
translateY = rec_points->y;
rec_points++;
}
if (flags & HAVE_ROTATION)
if (fl & HAVE_ROTATION)
{
rotation = rec_points[0].x / (1 << 12);
rotation = rec_points->x / (1 << 12);
rec_points++;
}
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
scaleX = rec_points[0].x / (1 << 10);
scaleY = rec_points[0].y / (1 << 10);
scaleX = rec_points->x / (1 << 10);
scaleY = rec_points->y / (1 << 10);
rec_points++;
}
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
skewX = rec_points[0].x / (1 << 12);
skewY = rec_points[0].y / (1 << 12);
skewX = rec_points->x / (1 << 12);
skewY = rec_points->y / (1 << 12);
rec_points++;
}
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
tCenterX = rec_points[0].x;
tCenterY = rec_points[0].y;
tCenterX = rec_points->x;
tCenterY = rec_points->y;
rec_points++;
}
assert (!rec_points);
translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
rotate (matrix, trans, rotation);
@ -307,18 +345,19 @@ struct VarCompositeGlyphRecord
{
bool have_variations = flags & AXES_HAVE_VARIATION;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
unsigned num_axes = numAxes;
const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes)));
const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes)));
unsigned count = numAxes;
unsigned count = num_axes;
for (unsigned i = 0; i < count; i++)
{
unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
signed v = have_variations ? rec_points[i].x : a++->to_int ();
signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int ();
v = hb_clamp (v, -(1<<14), (1<<14));
setter[axis_index] = v;
@ -328,8 +367,9 @@ struct VarCompositeGlyphRecord
protected:
HBUINT16 flags;
HBUINT8 numAxes;
HBUINT16 pad;
public:
DEFINE_SIZE_MIN (3);
DEFINE_SIZE_MIN (5);
};
using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
@ -344,6 +384,13 @@ struct VarCompositeGlyph
var_composite_iter_t iter () const
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
const hb_bytes_t trim_padding () const
{
unsigned length = GlyphHeader::static_size;
for (auto &comp : iter ())
length += comp.get_size ();
return bytes.sub_array (0, length);
}
};

View File

@ -31,6 +31,12 @@ struct glyf
static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
static bool has_valid_glyf_format(const hb_face_t* face)
{
const OT::head &head = *face->table.head;
return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1;
}
bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
{
TRACE_SANITIZE (this);
@ -72,6 +78,13 @@ struct glyf
{
TRACE_SUBSET (this);
if (!has_valid_glyf_format (c->plan->source)) {
// glyf format is unknown don't attempt to subset it.
DEBUG_MSG (SUBSET, nullptr,
"unkown glyf format, dropping from subset.");
return_trace (false);
}
glyf *glyf_prime = c->serializer->start_embed <glyf> ();
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
@ -85,11 +98,17 @@ struct glyf
hb_vector_t<unsigned> padded_offsets;
unsigned num_glyphs = c->plan->num_output_glyphs ();
if (unlikely (!padded_offsets.resize (num_glyphs)))
{
hb_font_destroy (font);
return false;
}
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
if (!_populate_subset_glyphs (c->plan, font, glyphs))
{
hb_font_destroy (font);
return false;
}
if (font)
hb_font_destroy (font);
@ -112,7 +131,7 @@ struct glyf
bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
if (c->plan->normalized_coords && !c->plan->pinned_at_default)
_free_compiled_subset_glyphs (glyphs, glyphs.length - 1);
_free_compiled_subset_glyphs (glyphs);
if (!result) return false;
@ -131,9 +150,9 @@ struct glyf
hb_font_t *
_create_font_for_instancing (const hb_subset_plan_t *plan) const;
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs, unsigned index) const
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const
{
for (unsigned i = 0; i <= index && i < glyphs.length; i++)
for (unsigned i = 0; i < glyphs.length; i++)
glyphs[i].free_compiled_bytes ();
}
@ -162,7 +181,7 @@ struct glyf_accelerator_t
vmtx = nullptr;
#endif
const OT::head &head = *face->table.head;
if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
if (!glyf::has_valid_glyf_format (face))
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
return;
short_offset = 0 == head.indexToLocFormat;
@ -222,6 +241,8 @@ struct glyf_accelerator_t
return true;
}
public:
#ifndef HB_NO_VAR
struct points_aggregator_t
{
@ -285,7 +306,6 @@ struct glyf_accelerator_t
contour_point_t *get_phantoms_sink () { return phantoms; }
};
public:
unsigned
get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
{
@ -327,6 +347,15 @@ struct glyf_accelerator_t
}
#endif
bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
{
if (unlikely (gid >= num_glyphs)) return false;
if (is_vertical) return false; // TODO Humm, what to do here?
*lsb = glyph_for_gid (gid).get_header ()->xMin;
return true;
}
public:
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
{
@ -405,7 +434,6 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
unsigned num_glyphs = plan->num_output_glyphs ();
if (!glyphs.resize (num_glyphs)) return false;
unsigned idx = 0;
for (auto p : plan->glyph_map->iter ())
{
unsigned new_gid = p.second;
@ -433,11 +461,10 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
{
// when pinned at default, only bounds are updated, thus no need to free
if (!plan->pinned_at_default && idx > 0)
_free_compiled_subset_glyphs (glyphs, idx - 1);
if (!plan->pinned_at_default)
_free_compiled_subset_glyphs (glyphs);
return false;
}
idx++;
}
}
return true;
@ -451,7 +478,10 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
hb_vector_t<hb_variation_t> vars;
if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
{
hb_font_destroy (font);
return nullptr;
}
for (auto _ : plan->user_axes_location)
{

View File

@ -28,12 +28,8 @@ struct path_builder_t
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
} first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{
font = font_;
draw_session = &draw_session_;
first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t ();
}
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) :
font (font_), draw_session (&draw_session_) {}
/* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
See also:

View File

@ -173,9 +173,10 @@ struct graph_t
void remove_parent (unsigned parent_index)
{
for (unsigned i = 0; i < parents.length; i++)
unsigned count = parents.length;
for (unsigned i = 0; i < count; i++)
{
if (parents[i] != parent_index) continue;
if (parents.arrayZ[i] != parent_index) continue;
parents.remove_unordered (i);
break;
}
@ -183,7 +184,8 @@ struct graph_t
void remove_real_link (unsigned child_index, const void* offset)
{
for (unsigned i = 0; i < obj.real_links.length; i++)
unsigned count = obj.real_links.length;
for (unsigned i = 0; i < count; i++)
{
auto& link = obj.real_links.arrayZ[i];
if (link.objidx != child_index)
@ -199,16 +201,18 @@ struct graph_t
void remap_parents (const hb_vector_t<unsigned>& id_map)
{
for (unsigned i = 0; i < parents.length; i++)
parents[i] = id_map[parents[i]];
unsigned count = parents.length;
for (unsigned i = 0; i < count; i++)
parents.arrayZ[i] = id_map[parents.arrayZ[i]];
}
void remap_parent (unsigned old_index, unsigned new_index)
{
for (unsigned i = 0; i < parents.length; i++)
unsigned count = parents.length;
for (unsigned i = 0; i < count; i++)
{
if (parents[i] == old_index)
parents[i] = new_index;
if (parents.arrayZ[i] == old_index)
parents.arrayZ[i] = new_index;
}
}
@ -328,11 +332,12 @@ struct graph_t
bool removed_nil = false;
vertices_.alloc (objects.length);
vertices_scratch_.alloc (objects.length);
for (unsigned i = 0; i < objects.length; i++)
unsigned count = objects.length;
for (unsigned i = 0; i < count; i++)
{
// If this graph came from a serialization buffer object 0 is the
// nil object. We don't need it for our purposes here so drop it.
if (i == 0 && !objects[i])
if (i == 0 && !objects.arrayZ[i])
{
removed_nil = true;
continue;
@ -340,9 +345,9 @@ struct graph_t
vertex_t* v = vertices_.push ();
if (check_success (!vertices_.in_error ()))
v->obj = *objects[i];
v->obj = *objects.arrayZ[i];
check_success (v->link_positions_valid (objects.length, removed_nil));
check_success (v->link_positions_valid (count, removed_nil));
if (!removed_nil) continue;
// Fix indices to account for removed nil object.
@ -579,8 +584,8 @@ struct graph_t
const auto& node = object (node_idx);
if (offset < node.head || offset >= node.tail) return -1;
unsigned length = node.real_links.length;
for (unsigned i = 0; i < length; i++)
unsigned count = node.real_links.length;
for (unsigned i = 0; i < count; i++)
{
// Use direct access for increased performance, this is a hot method.
const auto& link = node.real_links.arrayZ[i];
@ -1135,8 +1140,9 @@ struct graph_t
size_t total_size_in_bytes () const {
size_t total_size = 0;
for (unsigned i = 0; i < vertices_.length; i++) {
size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
unsigned count = vertices_.length;
for (unsigned i = 0; i < count; i++) {
size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
total_size += size;
}
return total_size;
@ -1183,21 +1189,23 @@ struct graph_t
{
if (!parents_invalid) return;
for (unsigned i = 0; i < vertices_.length; i++)
vertices_[i].parents.reset ();
unsigned count = vertices_.length;
for (unsigned p = 0; p < vertices_.length; p++)
for (unsigned i = 0; i < count; i++)
vertices_.arrayZ[i].parents.reset ();
for (unsigned p = 0; p < count; p++)
{
for (auto& l : vertices_[p].obj.all_links ())
for (auto& l : vertices_.arrayZ[p].obj.all_links ())
{
vertices_[l.objidx].parents.push (p);
}
}
for (unsigned i = 0; i < vertices_.length; i++)
for (unsigned i = 0; i < count; i++)
// parents arrays must be accurate or downstream operations like cycle detection
// and sorting won't work correctly.
check_success (!vertices_[i].parents.in_error ());
check_success (!vertices_.arrayZ[i].parents.in_error ());
parents_invalid = false;
}
@ -1239,12 +1247,13 @@ struct graph_t
// According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
// for practical performance this is faster then using a more advanced queue
// (such as a fibonacci queue) with a fast decrease priority.
for (unsigned i = 0; i < vertices_.length; i++)
unsigned count = vertices_.length;
for (unsigned i = 0; i < count; i++)
{
if (i == vertices_.length - 1)
vertices_[i].distance = 0;
vertices_.arrayZ[i].distance = 0;
else
vertices_[i].distance = hb_int_max (int64_t);
vertices_.arrayZ[i].distance = hb_int_max (int64_t);
}
hb_priority_queue_t queue;
@ -1332,10 +1341,11 @@ struct graph_t
void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
hb_vector_t<vertex_t>* sorted_graph) const
{
for (unsigned i = 0; i < sorted_graph->length; i++)
unsigned count = sorted_graph->length;
for (unsigned i = 0; i < count; i++)
{
(*sorted_graph)[i].remap_parents (id_map);
for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
{
link.objidx = id_map[link.objidx];
}

View File

@ -319,7 +319,8 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
hb_vector_t<class_info_t> class_to_info;
unsigned class_count= classCount;
class_to_info.resize (class_count);
if (!class_to_info.resize (class_count))
return hb_vector_t<class_info_t>();
auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray);
if (!mark_array) return hb_vector_t<class_info_t> ();
@ -327,6 +328,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
for (unsigned mark = 0; mark < mark_count; mark++)
{
unsigned klass = (*mark_array.table)[mark].get_class ();
if (klass >= class_count) continue;
class_to_info[klass].marks.add (mark);
}
@ -335,6 +337,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
unsigned mark = (link.position - 2) /
OT::Layout::GPOS_impl::MarkRecord::static_size;
unsigned klass = (*mark_array.table)[mark].get_class ();
if (klass >= class_count) continue;
class_to_info[klass].child_indices.push (link.objidx);
}

View File

@ -116,10 +116,10 @@ will_overflow (graph_t& graph,
for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
{
// Don't need to check virtual links for overflow
for (const auto& link : vertices[parent_idx].obj.real_links)
for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
{
int64_t offset = compute_offset (graph, parent_idx, link);
if (is_valid_offset (offset, link))
if (likely (is_valid_offset (offset, link)))
continue;
if (!overflows) return true;

View File

@ -12,13 +12,17 @@ list(GET _harfbuzz_version_info 2
_harfbuzz_age)
unset(_harfbuzz_version_info)
if (APPLE)
set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}")
elseif (UNIX)
set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}")
if ("@default_library@" MATCHES "static")
set(_harfbuzz_lib_suffix ".a")
else ()
# Unsupported.
set(harfbuzz_FOUND 0)
if (APPLE)
set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}")
elseif (UNIX)
set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}")
else ()
# Unsupported.
set(harfbuzz_FOUND 0)
endif ()
endif ()
# Add the libraries.

View File

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

View File

@ -55,7 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
buffer (buffer_),
sanitizer (),
ankr_table (&Null (AAT::ankr)),
gdef_table (face->table.GDEF->table),
gdef_table (
#ifndef HB_NO_OT_LAYOUT
face->table.GDEF->table
#else
&Null (GDEF)
#endif
),
lookup_index (0)
{
sanitizer.init (blob);

View File

@ -626,8 +626,10 @@ hb_popcount (T v)
if (sizeof (T) == 8)
{
unsigned int shift = 32;
return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
uint64_t y = (uint64_t) v;
y -= ((y >> 1) & 0x5555555555555555ull);
y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull);
return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56;
}
if (sizeof (T) == 16)

View File

@ -122,9 +122,13 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
uint32_t hash () const
{
uint32_t current = 0;
// FNV-1a hash function
uint32_t current = /*cbf29ce4*/0x84222325;
for (auto &v : *this)
current = current * 31 + hb_hash (v);
{
current = current ^ hb_hash (v);
current = current * 16777619;
}
return current;
}
@ -452,36 +456,50 @@ inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const
template <>
inline uint32_t hb_array_t<const char>::hash () const
{
uint32_t current = 0;
// FNV-1a hash function
uint32_t current = /*cbf29ce4*/0x84222325;
unsigned i = 0;
#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
for (; i + 4 <= this->length; i += 4)
current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
{
current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v);
current = current * 16777619;
}
#endif
for (; i < this->length; i++)
current = current * 31 + hb_hash (this->arrayZ[i]);
{
current = current ^ hb_hash (this->arrayZ[i]);
current = current * 16777619;
}
return current;
}
template <>
inline uint32_t hb_array_t<const unsigned char>::hash () const
{
uint32_t current = 0;
// FNV-1a hash function
uint32_t current = /*cbf29ce4*/0x84222325;
unsigned i = 0;
#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
for (; i + 4 <= this->length; i += 4)
current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
{
current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v);
current = current * 16777619;
}
#endif
for (; i < this->length; i++)
current = current * 31 + hb_hash (this->arrayZ[i]);
{
current = current ^ hb_hash (this->arrayZ[i]);
current = current * 16777619;
}
return current;
}

View File

@ -83,9 +83,15 @@ struct hb_bimap_t
unsigned int get_population () const { return forw_map.get_population (); }
protected:
hb_map_t forw_map;
hb_map_t back_map;
public:
auto keys () const HB_AUTO_RETURN (+ forw_map.keys())
auto values () const HB_AUTO_RETURN (+ forw_map.values())
auto iter () const HB_AUTO_RETURN (+ forw_map.iter())
};
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
@ -108,6 +114,9 @@ struct hb_inc_bimap_t : hb_bimap_t
hb_codepoint_t skip ()
{ return next_value++; }
hb_codepoint_t skip (unsigned count)
{ return next_value += count; }
hb_codepoint_t get_next_value () const
{ return next_value; }

View File

@ -194,7 +194,7 @@ struct hb_bit_set_t
unsigned int end = major_start (m + 1);
do
{
if (v || page) /* The v check is to optimize out the page check if v is true. */
if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
page->set (g, v);
array = &StructAtOffsetUnaligned<T> (array, stride);
@ -238,7 +238,7 @@ struct hb_bit_set_t
if (g < last_g) return false;
last_g = g;
if (v || page) /* The v check is to optimize out the page check if v is true. */
if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
page->add (g);
array = &StructAtOffsetUnaligned<T> (array, stride);
@ -402,7 +402,6 @@ struct hb_bit_set_t
uint32_t spm = page_map[spi].major;
uint32_t lpm = larger_set.page_map[lpi].major;
auto sp = page_at (spi);
auto lp = larger_set.page_at (lpi);
if (spm < lpm && !sp.is_empty ())
return false;
@ -410,6 +409,7 @@ struct hb_bit_set_t
if (lpm < spm)
continue;
auto lp = larger_set.page_at (lpi);
if (!sp.is_subset (lp))
return false;
@ -623,6 +623,7 @@ struct hb_bit_set_t
*codepoint = INVALID;
return false;
}
last_page_lookup = i;
}
const auto* pages_array = pages.arrayZ;
@ -632,7 +633,6 @@ struct hb_bit_set_t
if (pages_array[current.index].next (codepoint))
{
*codepoint += current.major * page_t::PAGE_BITS;
last_page_lookup = i;
return true;
}
i++;
@ -649,7 +649,6 @@ struct hb_bit_set_t
return true;
}
}
last_page_lookup = 0;
*codepoint = INVALID;
return false;
}
@ -921,7 +920,7 @@ struct hb_bit_set_t
memmove (page_map.arrayZ + i + 1,
page_map.arrayZ + i,
(page_map.length - 1 - i) * page_map.item_size);
page_map[i] = map;
page_map.arrayZ[i] = map;
}
last_page_lookup = i;

View File

@ -40,6 +40,11 @@
* Buffers serve a dual role in HarfBuzz; before shaping, they hold
* the input characters that are passed to hb_shape(), and after
* shaping they hold the output glyphs.
*
* The input buffer is a sequence of Unicode codepoints, with
* associated attributes such as direction and script. The output
* buffer is a sequence of glyphs, with associated attributes such
* as position and cluster.
**/
@ -263,7 +268,7 @@ hb_buffer_t::similar (const hb_buffer_t &src)
unicode = hb_unicode_funcs_reference (src.unicode);
flags = src.flags;
cluster_level = src.cluster_level;
replacement = src.invisible;
replacement = src.replacement;
invisible = src.invisible;
not_found = src.not_found;
}

View File

@ -553,7 +553,7 @@ struct hb_buffer_t
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
#ifdef HB_NO_BUFFER_MESSAGE
return true;
return true;
#else
if (likely (!messaging ()))
return true;

View File

@ -30,7 +30,19 @@
#include "hb.hh"
/* Implements a lockfree cache for int->int functions. */
/* Implements a lockfree cache for int->int functions.
*
* The cache is a fixed-size array of 16-bit or 32-bit integers.
* The key is split into two parts: the cache index and the rest.
*
* The cache index is used to index into the array. The rest is used
* to store the key and the value.
*
* The value is stored in the least significant bits of the integer.
* The key is stored in the most significant bits of the integer.
* The key is shifted by cache_bits to the left to make room for the
* value.
*/
template <unsigned int key_bits=16,
unsigned int value_bits=8 + 32 - key_bits,

View File

@ -1,5 +1,6 @@
/*
* Copyright © 2022 Red Hat, Inc
* Copyright © 2021, 2022 Black Foundry
*
* This is part of HarfBuzz, a text shaping library.
*
@ -32,9 +33,13 @@
#include <cairo.h>
#define PREALLOCATED_COLOR_STOPS 16
/* Some routines in this file were ported from BlackRenderer by Black Foundry.
* Used by permission to relicense to HarfBuzz license.
*
* https://github.com/BlackFoundryCom/black-renderer
*/
#define _2_M_PIf (2.f * float (M_PI))
#define PREALLOCATED_COLOR_STOPS 16
typedef struct {
float r, g, b, a;
@ -518,7 +523,7 @@ _hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cair
cairo_mesh_pattern_end_patch (pattern);
}
#define MAX_ANGLE ((float) M_PI / 8.f)
#define MAX_ANGLE (HB_PI / 8.f)
static void
_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius,
@ -601,7 +606,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
start_angle, &c,
pattern);
}
if (end_angle < _2_M_PIf)
if (end_angle < HB_2_PI)
{
c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.;
c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.;
@ -609,7 +614,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.;
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
end_angle, &c,
_2_M_PIf, &c,
HB_2_PI, &c,
pattern);
}
}
@ -673,7 +678,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
color0 = colors[n_stops-1];
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
0., &color0,
_2_M_PIf, &color0,
HB_2_PI, &color0,
pattern);
goto done;
}
@ -685,7 +690,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
for (pos++; pos < n_stops; pos++)
{
if (angles[pos] <= _2_M_PIf)
if (angles[pos] <= HB_2_PI)
{
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos-1],
@ -694,11 +699,11 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
}
else
{
float k = (_2_M_PIf - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
_hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos - 1],
_2_M_PIf, &color1,
HB_2_PI, &color1,
pattern);
break;
}
@ -710,7 +715,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
color0 = colors[n_stops - 1];
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[n_stops - 1], &color0,
_2_M_PIf, &color0,
HB_2_PI, &color0,
pattern);
goto done;
}
@ -794,14 +799,14 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
a1, c1,
pattern);
}
else if (a1 >= _2_M_PIf)
else if (a1 >= HB_2_PI)
{
hb_cairo_color_t color;
float f = (_2_M_PIf - a0)/(a1 - a0);
float f = (HB_2_PI - a0)/(a1 - a0);
_hb_cairo_interpolate_colors (c0, c1, f, &color);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
a0, c0,
_2_M_PIf, &color,
HB_2_PI, &color,
pattern);
goto done;
}

View File

@ -632,6 +632,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_OLD_HUNGARIAN:
case HB_SCRIPT_OLD_ITALIC:
case HB_SCRIPT_RUNIC:
case HB_SCRIPT_TIFINAGH:
return HB_DIRECTION_INVALID;
}

View File

@ -44,14 +44,14 @@
#ifdef HB_TINY
#define HB_LEAN
#define HB_MINI
#define HB_OPTIMIZE_SIZE
#define HB_OPTIMIZE_SIZE_MORE
#define HB_MINIMIZE_MEMORY_USAGE
#define HB_NO_MT
#define HB_NO_UCD_UNASSIGNED
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef __OPTIMIZE_SIZE__
#define __OPTIMIZE_SIZE__
#endif
#endif
#ifdef HB_LEAN
@ -97,6 +97,12 @@
#define HB_NO_BORING_EXPANSION
#endif
#ifdef __OPTIMIZE_SIZE__
#ifndef HB_OPTIMIZE_SIZE
#define HB_OPTIMIZE_SIZE
#endif
#endif
#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
#ifndef HB_CONFIG_OVERRIDE_H
#define HB_CONFIG_OVERRIDE_H "config-override.h"
@ -107,8 +113,10 @@
/* Closure of options. */
#ifdef HB_NO_BORING_EXPANSION
#define HB_NO_BEYOND_64K
#define HB_NO_AVAR2
#define HB_NO_BEYOND_64K
#define HB_NO_CUBIC_GLYF
#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_DISABLE_DEPRECATED
@ -175,21 +183,27 @@
#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
#endif
#ifdef NDEBUG
#ifndef HB_NDEBUG
#define HB_NDEBUG
#endif
#ifdef HB_OPTIMIZE_SIZE_MORE
#define HB_NO_OT_LIGATURES_FAST_PATH
#endif
#ifdef __OPTIMIZE_SIZE__
#ifndef HB_OPTIMIZE_SIZE
#define HB_OPTIMIZE_SIZE
#endif
#ifdef HB_MINIMIZE_MEMORY_USAGE
#define HB_NO_GDEF_CACHE
#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
#define HB_NO_OT_FONT_ADVANCE_CACHE
#define HB_NO_OT_FONT_CMAP_CACHE
#endif
#ifdef HB_OPTIMIZE_SIZE
#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
#define HB_OPTIMIZE_SIZE_VAL 1
#else
#define HB_OPTIMIZE_SIZE_VAL 0
#endif
#ifdef HB_MINIMIZE_MEMORY_USAGE
#define HB_MINIMIZE_MEMORY_USAGE_VAL 1
#else
#define HB_MINIMIZE_MEMORY_USAGE_VAL 0
#endif
#endif /* HB_CONFIG_HH */

View File

@ -108,6 +108,16 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
/* https://github.com/harfbuzz/harfbuzz/pull/4207 */
/**
* HB_UNICODE_COMBINING_CLASS_CCC133:
*
* [Tibetan]
*
* Deprecated: 7.2.0
**/
#define HB_UNICODE_COMBINING_CLASS_CCC133 133
/**
* hb_unicode_eastasian_width_func_t:
* @ufuncs: A Unicode-functions structure
@ -247,6 +257,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
#endif
HB_END_DECLS
#endif /* HB_DEPRECATED_H */

View File

@ -47,6 +47,12 @@
* More precisely, a font face represents a single face in a binary font file.
* Font faces are typically built from a binary blob and a face index.
* Font faces are used to create fonts.
*
* A font face can be created from a binary blob using hb_face_create().
* The face index is used to select a face from a binary blob that contains
* multiple faces. For example, a binary blob that contains both a regular
* and a bold face can be used to create two font faces, one for each face
* index.
**/
@ -197,7 +203,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
* a face index into that blob.
*
* The face index is used for blobs of file formats such as TTC and
* and DFont that can contain more than one face. Face indices within
* DFont that can contain more than one face. Face indices within
* such collections are zero-based.
*
* <note>Note: If the blob font format is not a collection, @index

View File

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

View File

@ -59,6 +59,11 @@
*
* HarfBuzz provides a built-in set of lightweight default
* functions for each method in #hb_font_funcs_t.
*
* The default font functions are implemented in terms of the
* #hb_font_funcs_t methods of the parent font object. This allows
* client programs to override only the methods they need to, and
* otherwise inherit the parent font's implementation, if any.
**/
@ -1387,7 +1392,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/**
* hb_font_get_glyph_shape:
* @font: #hb_font_t to work upon
* @glyph: : The glyph ID
* @glyph: The glyph ID
* @dfuncs: #hb_draw_funcs_t to draw to
* @draw_data: User data to pass to draw callbacks
*
@ -1409,7 +1414,7 @@ hb_font_get_glyph_shape (hb_font_t *font,
/**
* hb_font_draw_glyph:
* @font: #hb_font_t to work upon
* @glyph: : The glyph ID
* @glyph: The glyph ID
* @dfuncs: #hb_draw_funcs_t to draw to
* @draw_data: User data to pass to draw callbacks
*

View File

@ -301,8 +301,8 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
c->funcs->sweep_gradient (c->data, &cl,
paint.u.sweep_gradient.center.x / 65536.f,
paint.u.sweep_gradient.center.y / 65536.f,
(paint.u.sweep_gradient.start_angle / 65536.f + 1) * (float) M_PI,
(paint.u.sweep_gradient.end_angle / 65536.f + 1) * (float) M_PI);
(paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI,
(paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI);
}
break;
case FT_COLR_PAINTFORMAT_GLYPH:

View File

@ -343,7 +343,8 @@ struct hb_hashmap_t
)
auto keys () const HB_AUTO_RETURN
(
+ keys_ref ()
+ iter_items ()
| hb_map (&item_t::key)
| hb_map (hb_ridentity)
)
auto values_ref () const HB_AUTO_RETURN
@ -353,7 +354,8 @@ struct hb_hashmap_t
)
auto values () const HB_AUTO_RETURN
(
+ values_ref ()
+ iter_items ()
| hb_map (&item_t::value)
| hb_map (hb_ridentity)
)
@ -399,7 +401,8 @@ struct hb_hashmap_t
unsigned int tombstone = (unsigned) -1;
while (items[i].is_used ())
{
if (items[i].hash == hash && items[i] == key)
if ((hb_is_same (K, hb_codepoint_t) || items[i].hash == hash) &&
items[i] == key)
return items[i];
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
tombstone = i;

View File

@ -37,7 +37,7 @@
/* Global nul-content Null pool. Enlarge as necessary. */
#define HB_NULL_POOL_SIZE 448
#define HB_NULL_POOL_SIZE 520
template <typename T, typename>
struct _hb_has_min_size : hb_false_type {};

View File

@ -44,7 +44,7 @@ namespace CFF {
* CFF -- Compact Font Format (CFF)
* https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
*/
#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
#define HB_OT_TAG_CFF1 HB_TAG('C','F','F',' ')
#define CFF_UNDEF_SID CFF_UNDEF_CODE
@ -1019,7 +1019,7 @@ using namespace CFF;
struct cff1
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF1;
bool sanitize (hb_sanitize_context_t *c) const
{

View File

@ -38,7 +38,7 @@ namespace CFF {
* CFF2 -- Compact Font Format (CFF) Version 2
* https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
*/
#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
typedef CFFIndex<HBUINT32> CFF2Index;
template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
@ -379,7 +379,7 @@ using namespace CFF;
struct cff2
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2;
bool sanitize (hb_sanitize_context_t *c) const
{

View File

@ -404,7 +404,7 @@ struct CmapSubtableFormat4
unsigned distance) const
{
if (k > last) return +1;
if (k < (&last)[distance]) return -1;
if (k < (&last)[distance]/*first*/) return -1;
return 0;
}
HBUINT16 last;
@ -413,7 +413,7 @@ struct CmapSubtableFormat4
const HBUINT16 *found = hb_bsearch (codepoint,
this->endCount,
this->segCount,
2,
sizeof (CustomRange),
_hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
this->segCount + 1);
if (unlikely (!found))

View File

@ -64,13 +64,17 @@
using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>;
using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
#ifndef HB_NO_OT_FONT_CMAP_CACHE
static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key;
#endif
struct hb_ot_font_t
{
const hb_ot_face_t *ot_face;
#ifndef HB_NO_OT_FONT_CMAP_CACHE
hb_ot_font_cmap_cache_t *cmap_cache;
#endif
/* h_advance caching */
mutable hb_atomic_int_t cached_coords_serial;
@ -86,6 +90,7 @@ _hb_ot_font_create (hb_font_t *font)
ot_font->ot_face = &font->face->table;
#ifndef HB_NO_OT_FONT_CMAP_CACHE
// retry:
auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
&hb_ot_font_cmap_cache_user_data_key);
@ -112,6 +117,7 @@ _hb_ot_font_create (hb_font_t *font)
}
out:
ot_font->cmap_cache = cmap_cache;
#endif
return ot_font;
}
@ -136,7 +142,11 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
return ot_face->cmap->get_nominal_glyph (unicode, glyph, ot_font->cmap_cache);
hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
#ifndef HB_NO_OT_FONT_CMAP_CACHE
cmap_cache = ot_font->cmap_cache;
#endif
return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache);
}
static unsigned int
@ -151,10 +161,14 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
#ifndef HB_NO_OT_FONT_CMAP_CACHE
cmap_cache = ot_font->cmap_cache;
#endif
return ot_face->cmap->get_nominal_glyphs (count,
first_unicode, unicode_stride,
first_glyph, glyph_stride,
ot_font->cmap_cache);
cmap_cache);
}
static hb_bool_t
@ -167,9 +181,13 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
#ifndef HB_NO_OT_FONT_CMAP_CACHE
cmap_cache = ot_font->cmap_cache;
#endif
return ot_face->cmap->get_variation_glyph (unicode,
variation_selector, glyph,
ot_font->cmap_cache);
cmap_cache);
}
static void
@ -188,7 +206,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
hb_position_t *orig_first_advance = first_advance;
#ifndef HB_NO_VAR
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::HVAR &HVAR = *hmtx.var_table;
const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
@ -258,7 +276,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
}
#ifndef HB_NO_VAR
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
OT::VariationStore::destroy_cache (varStore_cache);
#endif
@ -293,7 +311,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
if (vmtx.has_data ())
{
#ifndef HB_NO_VAR
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::VVAR &VVAR = *vmtx.var_table;
const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
@ -308,7 +326,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
#ifndef HB_NO_VAR
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
OT::VariationStore::destroy_cache (varStore_cache);
#endif
}
@ -413,7 +431,7 @@ hb_ot_get_glyph_extents (hb_font_t *font,
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif
#if !defined(HB_NO_COLOR)
#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
#endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
@ -633,20 +651,4 @@ hb_ot_font_set_funcs (hb_font_t *font)
_hb_ot_font_destroy);
}
#ifndef HB_NO_VAR
bool
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
int *lsb)
{
return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
}
unsigned
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
{
return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
}
#endif
#endif

View File

@ -76,7 +76,7 @@ struct DeviceRecord
HBUINT8 maxWidth; /* Maximum width. */
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
public:
DEFINE_SIZE_ARRAY (2, widthsZ);
DEFINE_SIZE_UNBOUNDED (2);
};
@ -87,14 +87,6 @@ struct hdmx
unsigned int get_size () const
{ return min_size + numRecords * sizeDeviceRecord; }
const DeviceRecord& operator [] (unsigned int i) const
{
/* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed.
* https://github.com/harfbuzz/harfbuzz/issues/1300 */
if (unlikely (i >= numRecords)) return Null (DeviceRecord);
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)

View File

@ -63,7 +63,25 @@ struct head
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
return_trace (serialize (c->serializer));
head *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
if (c->plan->normalized_coords)
{
if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin,
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
return_trace (false);
if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax,
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
return_trace (false);
if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin,
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
return_trace (false);
if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax,
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
return_trace (false);
}
return_trace (true);
}
enum mac_style_flag_t {

View File

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

View File

@ -189,7 +189,7 @@ struct hb_collect_variation_indices_context_t :
hb_set_t *layout_variation_indices;
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map;
hb_font_t *font;
hb_vector_t<int> *normalized_coords;
const VariationStore *var_store;
const hb_set_t *glyph_set;
const hb_map_t *gpos_lookups;
@ -197,14 +197,14 @@ struct hb_collect_variation_indices_context_t :
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map_,
hb_font_t *font_,
hb_vector_t<int> *normalized_coords_,
const VariationStore *var_store_,
const hb_set_t *glyph_set_,
const hb_map_t *gpos_lookups_,
float *store_cache_) :
layout_variation_indices (layout_variation_indices_),
varidx_delta_map (varidx_delta_map_),
font (font_),
normalized_coords (normalized_coords_),
var_store (var_store_),
glyph_set (glyph_set_),
gpos_lookups (gpos_lookups_),
@ -529,6 +529,9 @@ struct FeatureParamsSize
return_trace (true);
}
void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
{ nameids_to_retain->add (subfamilyNameID); }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@ -585,6 +588,9 @@ struct FeatureParamsStylisticSet
return_trace (c->check_struct (this));
}
void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
{ nameids_to_retain->add (uiNameID); }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@ -632,6 +638,20 @@ struct FeatureParamsCharacterVariants
unsigned get_size () const
{ return min_size + characters.len * HBUINT24::static_size; }
void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
{
if (featUILableNameID) nameids_to_retain->add (featUILableNameID);
if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID);
if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID);
if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF)
return;
unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1;
if (last_name_id >= 256 && last_name_id <= 32767)
nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@ -694,6 +714,19 @@ struct FeatureParams
return_trace (true);
}
void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
{
#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
return;
#endif
if (tag == HB_TAG ('s','i','z','e'))
return (u.size.collect_name_ids (nameids_to_retain));
if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
return (u.stylisticSet.collect_name_ids (nameids_to_retain));
if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
return (u.characterVariants.collect_name_ids (nameids_to_retain));
}
bool subset (hb_subset_context_t *c, const Tag* tag) const
{
TRACE_SUBSET (this);
@ -762,6 +795,12 @@ struct Feature
bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
{ return lookupIndex.intersects (lookup_indexes); }
void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
{
if (featureParams)
get_feature_params ().collect_name_ids (tag, nameids_to_retain);
}
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
const Tag *tag = nullptr) const
@ -1730,6 +1769,7 @@ struct ClassDefFormat2_4
return_trace (true);
}
unsigned unsorted = false;
unsigned num_ranges = 1;
hb_codepoint_t prev_gid = (*it).first;
unsigned prev_klass = (*it).second;
@ -1750,6 +1790,10 @@ struct ClassDefFormat2_4
if (cur_gid != prev_gid + 1 ||
cur_klass != prev_klass)
{
if (unlikely (cur_gid < prev_gid))
unsorted = true;
if (unlikely (!record)) break;
record->last = prev_gid;
num_ranges++;
@ -1765,8 +1809,14 @@ struct ClassDefFormat2_4
prev_gid = cur_gid;
}
if (unlikely (c->in_error ())) return_trace (false);
if (likely (record)) record->last = prev_gid;
rangeRecord.len = num_ranges;
if (unlikely (unsorted))
rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
return_trace (true);
}
@ -2058,8 +2108,15 @@ struct ClassDef
#ifndef HB_NO_BEYOND_64K
if (glyph_max > 0xFFFFu)
format += 2;
u.format += 2;
if (unlikely (glyph_max > 0xFFFFFFu))
#else
if (unlikely (glyph_max > 0xFFFFu))
#endif
{
c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
return_trace (false);
}
u.format = format;
@ -2233,19 +2290,20 @@ struct VarRegionAxis
{
float evaluate (int coord) const
{
int start = startCoord.to_int (), peak = peakCoord.to_int (), end = endCoord.to_int ();
int peak = peakCoord.to_int ();
if (peak == 0 || coord == peak)
return 1.f;
int start = startCoord.to_int (), end = endCoord.to_int ();
/* TODO Move these to sanitize(). */
if (unlikely (start > peak || peak > end))
return 1.;
return 1.f;
if (unlikely (start < 0 && end > 0 && peak != 0))
return 1.;
if (peak == 0 || coord == peak)
return 1.;
return 1.f;
if (coord <= start || end <= coord)
return 0.;
return 0.f;
/* Interpolate */
if (coord < peak)
@ -2462,10 +2520,9 @@ struct VarData
{
for (r = 0; r < src_word_count; r++)
{
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
for (unsigned old_gid : inner_map.keys())
{
unsigned int old = inner_map.backward (i);
int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
if (delta < -65536 || 65535 < delta)
{
has_long = true;
@ -2482,10 +2539,9 @@ struct VarData
bool short_circuit = src_long_words == has_long && src_word_count <= r;
delta_sz[r] = kZero;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
for (unsigned old_gid : inner_map.keys())
{
unsigned int old = inner_map.backward (i);
int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
if (delta < min_threshold || max_threshold < delta)
{
delta_sz[r] = kWord;
@ -2546,8 +2602,8 @@ struct VarData
{
unsigned int region = regionIndices.arrayZ[r];
if (region_indices.has (region)) continue;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0)
for (hb_codepoint_t old_gid : inner_map.keys())
if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0)
{
region_indices.add (region);
break;
@ -3509,8 +3565,9 @@ struct VariationDevice
{
c->layout_variation_indices->add (varIdx);
int delta = 0;
if (c->font && c->var_store)
delta = roundf (get_delta (c->font, *c->var_store, c->store_cache));
if (c->normalized_coords && c->var_store)
delta = roundf (c->var_store->get_delta (varIdx, c->normalized_coords->arrayZ,
c->normalized_coords->length, c->store_cache));
/* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap
* varidx later*/

View File

@ -476,6 +476,7 @@ struct hb_ot_apply_context_t :
void init (hb_ot_apply_context_t *c_, bool context_match = false)
{
c = c_;
end = c->buffer->len;
match_glyph_data16 = nullptr;
#ifndef HB_NO_BEYOND_64K
match_glyph_data24 = nullptr;
@ -487,7 +488,9 @@ struct hb_ot_apply_context_t :
/* Ignore ZWJ if we are matching context, or asked to. */
matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask);
matcher.set_per_syllable (c->per_syllable);
/* Per syllable matching is only for GSUB. */
matcher.set_per_syllable (c->table_index == 0 && c->per_syllable);
matcher.set_syllable (0);
}
void set_lookup_props (unsigned int lookup_props)
{
@ -522,6 +525,14 @@ struct hb_ot_apply_context_t :
matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
}
void reset_fast (unsigned int start_index_,
unsigned int num_items_)
{
// Doesn't set end or syllable. Used by GPOS which doesn't care / change.
idx = start_index_;
num_items = num_items_;
}
void reject ()
{
num_items++;
@ -694,6 +705,7 @@ struct hb_ot_apply_context_t :
hb_buffer_t *buffer;
recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
const GDEF::accelerator_t &gdef_accel;
const VariationStore &var_store;
VariationStore::cache_t *var_store_cache;
hb_set_digest_t digest;
@ -725,6 +737,13 @@ struct hb_ot_apply_context_t :
*face->table.GDEF->table
#else
Null (GDEF)
#endif
),
gdef_accel (
#ifndef HB_NO_OT_LAYOUT
*face->table.GDEF
#else
Null (GDEF::accelerator_t)
#endif
),
var_store (gdef.get_var_store ()),
@ -753,10 +772,10 @@ struct hb_ot_apply_context_t :
iter_context.init (this, true);
}
void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; last_base = -1; last_base_until = 0; init_iters (); }
void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
void set_lookup_mask (hb_mask_t mask, bool init = true) { lookup_mask = mask; last_base = -1; last_base_until = 0; if (init) init_iters (); }
void set_auto_zwj (bool auto_zwj_, bool init = true) { auto_zwj = auto_zwj_; if (init) init_iters (); }
void set_auto_zwnj (bool auto_zwnj_, bool init = true) { auto_zwnj = auto_zwnj_; if (init) init_iters (); }
void set_per_syllable (bool per_syllable_, bool init = true) { per_syllable = per_syllable_; if (init) init_iters (); }
void set_random (bool random_) { random = random_; }
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
@ -792,7 +811,6 @@ struct hb_ot_apply_context_t :
bool check_glyph_property (const hb_glyph_info_t *info,
unsigned int match_props) const
{
hb_codepoint_t glyph = info->codepoint;
unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
/* Not covered, if, for example, glyph class is ligature and
@ -802,7 +820,7 @@ struct hb_ot_apply_context_t :
return false;
if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
return match_properties_mark (glyph, glyph_props, match_props);
return match_properties_mark (info->codepoint, glyph_props, match_props);
return true;
}
@ -835,7 +853,7 @@ struct hb_ot_apply_context_t :
if (likely (has_glyph_classes))
{
props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
_hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
_hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef_accel.get_glyph_props (glyph_index));
}
else if (class_guess)
{
@ -883,7 +901,7 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
template <typename T>
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) )
template <typename T>
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
template <typename Type>
@ -1240,7 +1258,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
*/
unsigned int total_component_count = 0;
total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
@ -1251,7 +1268,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
LIGBASE_MAY_SKIP
} ligbase = LIGBASE_NOT_CHECKED;
match_positions[0] = buffer->idx;
for (unsigned int i = 1; i < count; i++)
{
unsigned unsafe_to;
@ -1316,7 +1332,12 @@ static inline bool match_input (hb_ot_apply_context_t *c,
*end_position = skippy_iter.idx + 1;
if (p_total_component_count)
{
total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
*p_total_component_count = total_component_count;
}
match_positions[0] = buffer->idx;
return_trace (true);
}
@ -2430,7 +2451,9 @@ struct ContextFormat2_5
}
}
bool apply (hb_ot_apply_context_t *c, bool cached = false) const
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@ -3533,7 +3556,9 @@ struct ChainContextFormat2_5
}
}
bool apply (hb_ot_apply_context_t *c, bool cached = false) const
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@ -4461,6 +4486,18 @@ struct GSUBGPOS
}
}
void collect_name_ids (const hb_map_t *feature_index_map,
hb_set_t *nameids_to_retain /* OUT */) const
{
unsigned count = get_feature_count ();
for (unsigned i = 0 ; i < count; i++)
{
if (!feature_index_map->has (i)) continue;
hb_tag_t tag = get_feature_tag (i);
get_feature (i).collect_name_ids (tag, nameids_to_retain);
}
}
template <typename T>
struct accelerator_t
{

View File

@ -64,6 +64,8 @@ using OT::Layout::GPOS;
* @include: hb-ot.h
*
* Functions for querying OpenType Layout features in the font face.
* See the [OpenType specification](http://www.microsoft.com/typography/otspec/)
* for details.
**/
@ -255,12 +257,13 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
{
_hb_buffer_assert_gsubgpos_vars (buffer);
const OT::GDEF &gdef = *font->face->table.GDEF->table;
const auto &gdef = *font->face->table.GDEF;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
_hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
_hb_glyph_info_clear_lig_props (&buffer->info[i]);
_hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (info[i].codepoint));
_hb_glyph_info_clear_lig_props (&info[i]);
}
}
@ -1893,7 +1896,7 @@ apply_backward (OT::hb_ot_apply_context_t *c,
if (accel.digest.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
ret |= accel.apply (c, subtable_count, false);
ret |= accel.apply (c, subtable_count, false);
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@ -1975,11 +1978,12 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
if (accel->digest.may_have (c.digest))
{
c.set_lookup_index (lookup_index);
c.set_lookup_mask (lookup.mask);
c.set_auto_zwj (lookup.auto_zwj);
c.set_auto_zwnj (lookup.auto_zwnj);
c.set_lookup_mask (lookup.mask, false);
c.set_auto_zwj (lookup.auto_zwj, false);
c.set_auto_zwnj (lookup.auto_zwnj, false);
c.set_random (lookup.random);
c.set_per_syllable (lookup.per_syllable);
c.set_per_syllable (lookup.per_syllable, false);
/* apply_string's set_lookup_props initializes the iterators. */
apply_string<Proxy> (&c,
proxy.accel.table->get_lookup (lookup_index),

View File

@ -76,7 +76,7 @@ hb_ot_math_has_data (hb_face_t *face)
*
* However, if the requested constant is #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
* #HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
* #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, then the return value is
* #HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT, then the return value is
* an integer between 0 and 100 representing that percentage.
*
* Return value: the requested constant or zero

View File

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

View File

@ -196,7 +196,7 @@ hb_ot_metrics_get_position (hb_font_t *font,
*position *= mult;
if (font->slant)
*position += _hb_roundf (mult * font->slant_xy * rise);
*position += roundf (mult * font->slant_xy * rise);
}
return ret;

View File

@ -181,6 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t *face,
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
}
#include "hb-ot-name-language-static.hh"
#endif

View File

@ -383,14 +383,15 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
if (!all_simple && buffer->message(font, "start reorder"))
{
count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
if (_hb_glyph_info_get_modified_combining_class (&info[i]) == 0)
continue;
unsigned int end;
for (end = i + 1; end < count; end++)
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
if (_hb_glyph_info_get_modified_combining_class (&info[end]) == 0)
break;
/* We are going to do a O(n^2). Only do this if the sequence is short. */
@ -414,11 +415,13 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
* If it did NOT, then make it skippable.
* https://github.com/harfbuzz/harfbuzz/issues/554
*/
for (unsigned int i = 1; i + 1 < buffer->len; i++)
if (buffer->info[i].codepoint == 0x034Fu/*CGJ*/ &&
(info_cc(buffer->info[i+1]) == 0 || info_cc(buffer->info[i-1]) <= info_cc(buffer->info[i+1])))
unsigned count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i + 1 < count; i++)
if (info[i].codepoint == 0x034Fu/*CGJ*/ &&
(info_cc(info[i+1]) == 0 || info_cc(info[i-1]) <= info_cc(info[i+1])))
{
_hb_glyph_info_unhide (&buffer->info[i]);
_hb_glyph_info_unhide (&info[i]);
}
}

View File

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

View File

@ -536,6 +536,8 @@ struct STAT
| hb_map (&AxisValue::get_value_name_id)
| hb_sink (nameids_to_retain)
;
nameids_to_retain->add (elidedFallbackNameID);
}
bool subset (hb_subset_context_t *c) const

View File

@ -222,18 +222,20 @@ struct DeltaSetIndexMap
struct VarStoreInstancer
{
VarStoreInstancer (const VariationStore &varStore,
const DeltaSetIndexMap &varIdxMap,
VarStoreInstancer (const VariationStore *varStore,
const DeltaSetIndexMap *varIdxMap,
hb_array_t<int> coords) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
operator bool () const { return bool (coords); }
operator bool () const { return varStore && 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
{ return varStore.get_delta (varIdxMap.map (VarIdx::add (varIdx, offset)), coords); }
{ return varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords); }
const VariationStore &varStore;
const DeltaSetIndexMap &varIdxMap;
const VariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
hb_array_t<int> coords;
};
@ -249,36 +251,55 @@ struct TupleVariationHeader
{ return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
const hb_array_t<const F2DOT14> shared_tuples) const
const hb_array_t<const F2DOT14> shared_tuples,
const hb_vector_t<int> *shared_tuple_active_idx = nullptr) const
{
hb_array_t<const F2DOT14> peak_tuple;
const F2DOT14 *peak_tuple;
unsigned start_idx = 0;
unsigned end_idx = coord_count;
if (has_peak ())
peak_tuple = get_peak_tuple (coord_count);
peak_tuple = get_peak_tuple (coord_count).arrayZ;
else
{
unsigned int index = get_index ();
if (unlikely (index * coord_count >= shared_tuples.length))
if (unlikely ((index + 1) * coord_count > shared_tuples.length))
return 0.f;
peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count);
peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
if (shared_tuple_active_idx)
{
if (unlikely (index >= shared_tuple_active_idx->length))
return 0.f;
int v = (*shared_tuple_active_idx).arrayZ[index];
if (v != -1)
{
start_idx = v;
end_idx = start_idx + 1;
}
}
}
hb_array_t<const F2DOT14> start_tuple;
hb_array_t<const F2DOT14> end_tuple;
if (has_intermediate ())
const F2DOT14 *start_tuple = nullptr;
const F2DOT14 *end_tuple = nullptr;
bool has_interm = has_intermediate ();
if (has_interm)
{
start_tuple = get_start_tuple (coord_count);
end_tuple = get_end_tuple (coord_count);
start_tuple = get_start_tuple (coord_count).arrayZ;
end_tuple = get_end_tuple (coord_count).arrayZ;
}
float scalar = 1.f;
for (unsigned int i = 0; i < coord_count; i++)
for (unsigned int i = start_idx; i < end_idx; i++)
{
int v = coords[i];
int peak = peak_tuple[i].to_int ();
if (!peak || v == peak) continue;
if (!peak) continue;
if (has_intermediate ())
int v = coords[i];
if (v == peak) continue;
if (has_interm)
{
int start = start_tuple[i].to_int ();
int end = end_tuple[i].to_int ();
@ -358,9 +379,12 @@ struct TupleVariationData
{
unsigned total_size = min_size;
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++)
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;
}
@ -464,12 +488,12 @@ struct TupleVariationData
if (unlikely (p + 1 > end)) return false;
unsigned control = *p++;
unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
if (unlikely (i + run_count > count)) return false;
unsigned j;
unsigned stop = i + run_count;
if (unlikely (stop > count)) return false;
if (control & POINTS_ARE_WORDS)
{
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
for (j = 0; j < run_count; j++, i++)
for (; i < stop; i++)
{
n += *(const HBUINT16 *)p;
points.arrayZ[i] = n;
@ -479,7 +503,7 @@ struct TupleVariationData
else
{
if (unlikely (p + run_count > end)) return false;
for (j = 0; j < run_count; j++, i++)
for (; i < stop; i++)
{
n += *p++;
points.arrayZ[i] = n;
@ -507,17 +531,17 @@ struct TupleVariationData
if (unlikely (p + 1 > end)) return false;
unsigned control = *p++;
unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
if (unlikely (i + run_count > count)) return false;
unsigned j;
unsigned stop = i + run_count;
if (unlikely (stop > count)) return false;
if (control & DELTAS_ARE_ZERO)
{
for (j = 0; j < run_count; j++, i++)
for (; i < stop; i++)
deltas.arrayZ[i] = 0;
}
else if (control & DELTAS_ARE_WORDS)
{
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
for (j = 0; j < run_count; j++, i++)
for (; i < stop; i++)
{
deltas.arrayZ[i] = * (const HBINT16 *) p;
p += HBUINT16::static_size;
@ -526,7 +550,7 @@ struct TupleVariationData
else
{
if (unlikely (p + run_count > end)) return false;
for (j = 0; j < run_count; j++, i++)
for (; i < stop; i++)
{
deltas.arrayZ[i] = * (const HBINT8 *) p++;
}

View File

@ -126,7 +126,6 @@ struct cvar
hb_blob_destroy (cvt_prime_blob);
return false;
}
hb_memset (cvt_deltas.arrayZ, 0, cvt_deltas.get_size ());
if (!calculate_cvt_deltas (plan->normalized_coords.length, plan->normalized_coords.as_array (),
num_cvt_item, tuple_var_data, base, cvt_deltas))

View File

@ -44,8 +44,15 @@ struct contour_point_t
void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
{ flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
void transform (const float (&matrix)[4])
{
float x_ = x * matrix[0] + y * matrix[2];
y = x * matrix[1] + y * matrix[3];
x = x_;
}
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
float x = 0.f;
float y = 0.f;
uint8_t flag = 0;
@ -63,32 +70,6 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
unsigned count = a.length;
hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
}
void transform (const float (&matrix)[4])
{
if (matrix[0] == 1.f && matrix[1] == 0.f &&
matrix[2] == 0.f && matrix[3] == 1.f)
return;
auto arrayZ = this->arrayZ;
unsigned count = length;
for (unsigned i = 0; i < count; i++)
{
contour_point_t &p = arrayZ[i];
float x_ = p.x * matrix[0] + p.y * matrix[2];
p.y = p.x * matrix[1] + p.y * matrix[3];
p.x = x_;
}
}
void translate (const contour_point_t& delta)
{
if (delta.x == 0.f && delta.y == 0.f)
return;
auto arrayZ = this->arrayZ;
unsigned count = length;
for (unsigned i = 0; i < count; i++)
arrayZ[i].translate (delta);
}
};
struct GlyphVariationData : TupleVariationData
@ -104,8 +85,8 @@ struct gvar
return_trace (c->check_struct (this) && (version.major == 1) &&
sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
(is_long_offset () ?
c->check_array (get_long_offset_array (), glyphCount+1) :
c->check_array (get_short_offset_array (), glyphCount+1)));
c->check_array (get_long_offset_array (), c->get_num_glyphs () + 1) :
c->check_array (get_short_offset_array (), c->get_num_glyphs () + 1)));
}
/* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */
@ -116,6 +97,8 @@ struct gvar
{
TRACE_SUBSET (this);
unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
gvar *out = c->serializer->allocate_min<gvar> ();
if (unlikely (!out)) return_trace (false);
@ -125,7 +108,7 @@ struct gvar
out->sharedTupleCount = sharedTupleCount;
unsigned int num_glyphs = c->plan->num_output_glyphs ();
out->glyphCount = num_glyphs;
out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
unsigned int subset_data_size = 0;
for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
@ -134,7 +117,7 @@ struct gvar
{
hb_codepoint_t old_gid;
if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length;
subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
}
bool long_offset = subset_data_size & ~0xFFFFu;
@ -166,7 +149,9 @@ struct gvar
{
hb_codepoint_t old_gid;
hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
? get_glyph_var_data_bytes (c->source_blob, old_gid)
? get_glyph_var_data_bytes (c->source_blob,
glyph_count,
old_gid)
: hb_bytes_t ();
if (long_offset)
@ -188,10 +173,12 @@ struct gvar
}
protected:
const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const
const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob,
unsigned glyph_count,
hb_codepoint_t glyph) const
{
unsigned start_offset = get_offset (glyph);
unsigned end_offset = get_offset (glyph+1);
unsigned start_offset = get_offset (glyph_count, glyph);
unsigned end_offset = get_offset (glyph_count, glyph+1);
if (unlikely (end_offset < start_offset)) return hb_bytes_t ();
unsigned length = end_offset - start_offset;
hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length);
@ -200,9 +187,9 @@ struct gvar
bool is_long_offset () const { return flags & 1; }
unsigned get_offset (unsigned i) const
unsigned get_offset (unsigned glyph_count, unsigned i) const
{
if (unlikely (i > glyphCount)) return 0;
if (unlikely (i > glyph_count)) return 0;
_hb_compiler_memory_r_barrier ();
return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
}
@ -214,7 +201,38 @@ struct gvar
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{ table = hb_sanitize_context_t ().reference_table<gvar> (face); }
{
table = hb_sanitize_context_t ().reference_table<gvar> (face);
/* If sanitize failed, set glyphCount to 0. */
glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
/* For shared tuples that only have one axis active, shared the index of
* that axis as a cache. This will speed up caclulate_scalar() a lot
* for fonts with lots of axes and many "monovar" tuples. */
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
unsigned count = table->sharedTupleCount;
if (unlikely (!shared_tuple_active_idx.resize (count, false))) return;
unsigned axis_count = table->axisCount;
for (unsigned i = 0; i < count; i++)
{
hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count);
int idx = -1;
for (unsigned j = 0; j < axis_count; j++)
{
const F2DOT14 &peak = tuple.arrayZ[j];
if (peak.to_int () != 0)
{
if (idx != -1)
{
idx = -1;
break;
}
idx = j;
}
}
shared_tuple_active_idx.arrayZ[i] = idx;
}
}
~accelerator_t () { table.destroy (); }
private:
@ -252,9 +270,9 @@ struct gvar
{
if (!coords) return true;
if (unlikely (glyph >= table->glyphCount)) return true;
if (unlikely (glyph >= glyphCount)) return true;
hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph);
hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph);
if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
hb_vector_t<unsigned int> shared_indices;
GlyphVariationData::tuple_iterator_t iterator;
@ -264,35 +282,39 @@ struct gvar
return true; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
contour_point_vector_t orig_points_vec;
orig_points_vec.extend (points);
if (unlikely (orig_points_vec.in_error ())) return false;
contour_point_vector_t orig_points_vec; // Populated lazily
auto orig_points = orig_points_vec.as_array ();
contour_point_vector_t deltas_vec; /* flag is used to indicate referenced point */
if (unlikely (!deltas_vec.resize (points.length, false))) return false;
/* flag is used to indicate referenced point */
contour_point_vector_t deltas_vec; // Populated lazily
auto deltas = deltas_vec.as_array ();
hb_vector_t<unsigned> end_points;
for (unsigned i = 0; i < points.length; ++i)
if (points.arrayZ[i].is_end_point)
end_points.push (i);
hb_vector_t<unsigned> end_points; // Populated lazily
unsigned num_coords = table->axisCount;
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * num_coords);
hb_vector_t<unsigned int> private_indices;
hb_vector_t<int> x_deltas;
hb_vector_t<int> y_deltas;
bool flush = false;
do
{
float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples,
&shared_tuple_active_idx);
if (scalar == 0.f) continue;
const HBUINT8 *p = iterator.get_serialized_data ();
unsigned int length = iterator.current_tuple->get_data_size ();
if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
return false;
if (!deltas)
{
if (unlikely (!deltas_vec.resize (points.length, false))) return false;
deltas = deltas_vec.as_array ();
hb_memset (deltas.arrayZ, 0, deltas.get_size ()); // Faster than vector resize
}
const HBUINT8 *end = p + length;
bool has_private_points = iterator.current_tuple->has_private_points ();
@ -308,40 +330,106 @@ struct gvar
if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
hb_memset (deltas.arrayZ, 0, deltas.get_size ());
if (!apply_to_all)
{
if (!orig_points)
{
orig_points_vec.extend (points);
if (unlikely (orig_points_vec.in_error ())) return false;
orig_points = orig_points_vec.as_array ();
}
unsigned ref_points = 0;
if (scalar != 1.0f)
if (flush)
{
unsigned count = points.length;
for (unsigned int i = 0; i < count; i++)
points.arrayZ[i].translate (deltas.arrayZ[i]);
flush = false;
}
hb_memset (deltas.arrayZ, 0, deltas.get_size ());
}
if (HB_OPTIMIZE_SIZE_VAL)
{
for (unsigned int i = 0; i < num_deltas; i++)
{
unsigned int pt_index = apply_to_all ? i : indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
unsigned int pt_index;
if (apply_to_all)
pt_index = i;
else
{
pt_index = indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
}
auto &delta = deltas.arrayZ[pt_index];
ref_points += !delta.flag;
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
}
}
else
for (unsigned int i = 0; i < num_deltas; i++)
{
/* Ouch. Four cases... for optimization. */
if (scalar != 1.0f)
{
unsigned int pt_index = apply_to_all ? i : indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
auto &delta = deltas.arrayZ[pt_index];
ref_points += !delta.flag;
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
if (apply_to_all)
for (unsigned int i = 0; i < num_deltas; i++)
{
unsigned int pt_index = i;
auto &delta = deltas.arrayZ[pt_index];
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
}
else
for (unsigned int i = 0; i < num_deltas; i++)
{
unsigned int pt_index = indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
}
}
else
{
if (apply_to_all)
for (unsigned int i = 0; i < num_deltas; i++)
{
unsigned int pt_index = i;
auto &delta = deltas.arrayZ[pt_index];
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
}
else
for (unsigned int i = 0; i < num_deltas; i++)
{
unsigned int pt_index = indices[i];
if (unlikely (pt_index >= deltas.length)) continue;
auto &delta = deltas.arrayZ[pt_index];
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i];
delta.y += y_deltas.arrayZ[i];
}
}
}
/* infer deltas for unreferenced points */
if (ref_points && ref_points < orig_points.length)
if (!apply_to_all)
{
unsigned start_point = 0;
for (unsigned c = 0; c < end_points.length; c++)
if (!end_points)
{
unsigned end_point = end_points.arrayZ[c];
unsigned count = points.length;
for (unsigned i = 0; i < count; ++i)
if (points.arrayZ[i].is_end_point)
end_points.push (i);
if (unlikely (end_points.in_error ())) return false;
}
unsigned start_point = 0;
for (unsigned end_point : end_points)
{
/* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
unsigned unref_count = 0;
for (unsigned i = start_point; i < end_point + 1; i++)
@ -388,14 +476,17 @@ struct gvar
}
}
/* apply specified / inferred deltas to points */
for (unsigned int i = 0; i < points.length; i++)
{
points.arrayZ[i].x += deltas.arrayZ[i].x;
points.arrayZ[i].y += deltas.arrayZ[i].y;
}
flush = true;
} while (iterator.move_to_next ());
if (flush)
{
unsigned count = points.length;
for (unsigned int i = 0; i < count; i++)
points.arrayZ[i].translate (deltas.arrayZ[i]);
}
return true;
}
@ -403,6 +494,8 @@ struct gvar
private:
hb_blob_ptr_t<gvar> table;
unsigned glyphCount;
hb_vector_t<signed> shared_tuple_active_idx;
};
protected:
@ -418,7 +511,7 @@ struct gvar
NNOffset32To<UnsizedArrayOf<F2DOT14>>
sharedTuples; /* Offset from the start of this table to the shared tuple records.
* Array of tuple records shared across all glyph variation data tables. */
HBUINT16 glyphCount; /* The number of glyphs in this font. This must match the number of
HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of
* glyphs stored elsewhere in the font. */
HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows.
* If bit 0 is clear, the offsets are uint16; if bit 0 is set, the

View File

@ -185,12 +185,8 @@ struct hvarvvar_subset_plan_t
{
retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
outer_map.add (0);
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
{
hb_codepoint_t old_gid;
if (plan->old_gid_for_new_gid (gid, &old_gid))
inner_sets[0]->add (old_gid);
}
for (hb_codepoint_t old_gid : plan->glyphset()->iter())
inner_sets[0]->add (old_gid);
hb_set_union (adv_set, inner_sets[0]);
}
@ -202,10 +198,12 @@ struct hvarvvar_subset_plan_t
if (retain_adv_map)
{
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
{
if (inner_sets[0]->has (gid))
inner_maps[0].add (gid);
else
inner_maps[0].skip ();
}
}
else
{
@ -265,6 +263,9 @@ struct HVARVVAR
rsbMap.sanitize (c, this));
}
const VariationStore& get_var_store () const
{ return this+varStore; }
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
{
index_maps.push (&(this+advMap));

View File

@ -4,7 +4,6 @@
* Copyright © 2005 Werner Lemberg
* Copyright © 2013-2015 Alexei Podtelezhnikov
*
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without

View File

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

View File

@ -203,8 +203,8 @@ struct hb_paint_funcs_t
if (!a)
return false;
float cc = cosf (a * (float) M_PI);
float ss = sinf (a * (float) M_PI);
float cc = cosf (a * HB_PI);
float ss = sinf (a * HB_PI);
push_transform (paint_data, cc, ss, -ss, cc, 0.f, 0.f);
return true;
}
@ -216,8 +216,8 @@ struct hb_paint_funcs_t
if (!sx && !sy)
return false;
float x = tanf (-sx * (float) M_PI);
float y = tanf (+sy * (float) M_PI);
float x = tanf (-sx * HB_PI);
float y = tanf (+sy * HB_PI);
push_transform (paint_data, 1.f, y, x, 1.f, 0.f, 0.f);
return true;
}

View File

@ -29,7 +29,16 @@
#include "hb.hh"
/* Memory pool for persistent allocation of small objects. */
/* Memory pool for persistent allocation of small objects.
*
* Some AI musings on this, not necessarily true:
*
* This is a very simple implementation, but it's good enough for our
* purposes. It's not thread-safe. It's not very fast. It's not
* very memory efficient. It's not very cache efficient. It's not
* very anything efficient. But it's simple and it works. And it's
* good enough for our purposes. If you need something more
* sophisticated, use a real allocator. Or use a real language. */
template <typename T, unsigned ChunkLen = 32>
struct hb_pool_t

View File

@ -35,6 +35,12 @@
*
* Priority queue implemented as a binary heap. Supports extract minimum
* and insert operations.
*
* The priority queue is implemented as a binary heap, which is a complete
* binary tree. The root of the tree is the minimum element. The heap
* property is that the priority of a node is less than or equal to the
* priority of its children. The heap is stored in an array, with the
* children of node i stored at indices 2i + 1 and 2i + 2.
*/
struct hb_priority_queue_t
{

View File

@ -45,10 +45,16 @@
* a lookup's or subtable's Coverage table(s), and then when we
* want to apply the lookup or subtable to a glyph, before trying
* to apply, we ask the filter if the glyph may be covered. If it's
* not, we return early.
* not, we return early. We can also match a digest against another
* digest.
*
* We use these filters both at the lookup-level, and then again,
* at the subtable-level. Both have performance win.
* We use these filters at three levels:
* - If the digest for all the glyphs in the buffer as a whole
* does not match the digest for the lookup, skip the lookup.
* - For each glyph, if it doesn't match the lookup digest,
* skip it.
* - For each glyph, if it doesn't match the subtable digest,
* skip it.
*
* The main filter we use is a combination of three bits-pattern
* filters. A bits-pattern filter checks a number of bits (5 or 6)

View File

@ -271,9 +271,13 @@ hb_shape_justify (hb_font_t *font,
/* If default advance already matches target, nothing to do. Shape and return. */
if (min_target_advance <= *advance && *advance <= max_target_advance)
{
*var_tag = HB_TAG_NONE;
*var_value = 0.0f;
return hb_shape_full (font, buffer,
features, num_features,
shaper_list);
}
hb_face_t *face = font->face;
@ -297,6 +301,8 @@ hb_shape_justify (hb_font_t *font,
/* If no suitable variation axis found, can't justify. Just shape and return. */
if (!tag)
{
*var_tag = HB_TAG_NONE;
*var_value = 0.0f;
if (hb_shape_full (font, buffer,
features, num_features,
shaper_list))
@ -331,7 +337,11 @@ hb_shape_justify (hb_font_t *font,
* Do this again, in case advance was just calculated.
*/
if (min_target_advance <= *advance && *advance <= max_target_advance)
{
*var_tag = HB_TAG_NONE;
*var_value = 0.0f;
return true;
}
/* Prepare for running the solver. */
double a, b, ya, yb;
@ -355,6 +365,7 @@ hb_shape_justify (hb_font_t *font,
* there's nothing to solve for. Just return it. */
if (yb <= (double) max_target_advance)
{
*var_value = (float) b;
*advance = (float) yb;
return true;
}
@ -379,6 +390,7 @@ hb_shape_justify (hb_font_t *font,
* there's nothing to solve for. Just return it. */
if (ya >= (double) min_target_advance)
{
*var_value = (float) a;
*advance = (float) ya;
return true;
}

View File

@ -36,9 +36,11 @@
#include "OT/Color/COLR/COLR.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-maxp-table.hh"
#ifndef HB_NO_VISIBILITY
#include "hb-ot-name-language-static.hh"
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
@ -108,4 +110,26 @@ hb_face_t::load_upem () const
}
#ifndef HB_NO_VAR
bool
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
int *lsb)
{
return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
}
unsigned
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
{
return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
}
#endif
bool
_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb)
{
return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb);
}
#endif

View File

@ -46,13 +46,13 @@
static inline float
_hb_angle_to_ratio (float a)
{
return tanf (a * float (-M_PI / 180.));
return tanf (a * -HB_PI / 180.f);
}
static inline float
_hb_ratio_to_angle (float r)
{
return atanf (r) * float (-180. / M_PI);
return atanf (r) * -180.f / HB_PI;
}
/**

View File

@ -58,6 +58,8 @@ struct hb_subset_accelerator_t
hb_subset_accelerator_t* accel =
(hb_subset_accelerator_t*) hb_calloc (1, sizeof(hb_subset_accelerator_t));
if (unlikely (!accel)) return accel;
new (accel) hb_subset_accelerator_t (unicode_to_gid_,
gid_to_unicodes_,
unicodes_,

View File

@ -520,6 +520,37 @@ hb_subset_preprocess (hb_face_t *source)
return new_source;
}
/**
* hb_subset_input_old_to_new_glyph_mapping:
* @input: a #hb_subset_input_t object.
*
* Returns a map which can be used to provide an explicit mapping from old to new glyph
* id's in the produced subset. The caller should populate the map as desired.
* If this map is left empty then glyph ids will be automatically mapped to new
* values by the subsetter. If populated, the mapping must be unique. That
* is no two original glyph ids can be mapped to the same new id.
* Additionally, if a mapping is provided then the retain gids option cannot
* be enabled.
*
* Any glyphs that are retained in the subset which are not specified
* in this mapping will be assigned glyph ids after the highest glyph
* id in the mapping.
*
* Note: this will accept and apply non-monotonic mappings, however this
* may result in unsorted Coverage tables. Such fonts may not work for all
* use cases (for example ots will reject unsorted coverage tables). So it's
* recommended, if possible, to supply a monotonic mapping.
*
* Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map.
*
* Since: 7.3.0
**/
HB_EXTERN hb_map_t*
hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input)
{
return &input->glyph_map;
}
#ifdef HB_EXPERIMENTAL_API
/**
* hb_subset_input_override_name_table:

View File

@ -119,6 +119,7 @@ struct hb_subset_input_t
bool force_long_loca = false;
hb_hashmap_t<hb_tag_t, float> axes_location;
hb_map_t glyph_map;
#ifdef HB_EXPERIMENTAL_API
hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides;
#endif

View File

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

View File

@ -0,0 +1,128 @@
/*
* Copyright © 2018 Google, Inc.
* Copyright © 2023 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger, Roderick Sheeter
*/
#ifndef HB_SUBSET_PLAN_MEMBER_LIST_HH
#define HB_SUBSET_PLAN_MEMBER_LIST_HH
#endif /* HB_SUBSET_PLAN_MEMBER_LIST_HH */ /* Dummy header guards */
#define E(x, y) x, y
// For each cp that we'd like to retain maps to the corresponding gid.
HB_SUBSET_PLAN_MEMBER (hb_set_t, unicodes)
HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t E(<hb_pair_t<hb_codepoint_t, hb_codepoint_t>>), unicode_to_new_gid_list)
// name_ids we would like to retain
HB_SUBSET_PLAN_MEMBER (hb_set_t, name_ids)
// name_languages we would like to retain
HB_SUBSET_PLAN_MEMBER (hb_set_t, name_languages)
//layout features which will be preserved
HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_features)
// layout scripts which will be preserved.
HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_scripts)
//glyph ids requested to retain
HB_SUBSET_PLAN_MEMBER (hb_set_t, glyphs_requested)
// Tables which should not be processed, just pass them through.
HB_SUBSET_PLAN_MEMBER (hb_set_t, no_subset_tables)
// Tables which should be dropped.
HB_SUBSET_PLAN_MEMBER (hb_set_t, drop_tables)
// Old -> New glyph id mapping
HB_SUBSET_PLAN_MEMBER (hb_map_t, glyph_map_gsub)
HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset)
HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_gsub)
HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_mathed)
HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_colred)
//active lookups we'd like to retain
HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_lookups)
HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_lookups)
//active langsys we'd like to retain
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gsub_langsys)
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gpos_langsys)
//active features after removing redundant langsys and prune_features
HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features)
HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features)
//active feature variation records/condition index with variations
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::shared_ptr<hb_set_t>>), gsub_feature_record_cond_idx_map)
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::shared_ptr<hb_set_t>>), gpos_feature_record_cond_idx_map)
//feature index-> address of substituation feature table mapping with
//variations
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gsub_feature_substitutes_map)
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gpos_feature_substitutes_map)
//active layers/palettes we'd like to retain
HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
//Old layout item variation index -> (New varidx, delta) mapping
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
//gdef varstore retained varidx mapping
HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, gdef_varstore_inner_maps)
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, hb::unique_ptr<hb_blob_t>>), sanitized_table_cache)
//normalized axes location map
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, int>), axes_location)
HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords)
//user specified axes location map
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, float>), user_axes_location)
//retained old axis index -> new axis index mapping in fvar axis array
HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)
//axis_index->axis_tag mapping in fvar axis array
HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_old_index_tag_map)
//hmtx metrics map: new gid->(advance, lsb)
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), hmtx_map)
//vmtx metrics map: new gid->(advance, lsb)
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), vmtx_map)
//boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin
HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_width_map)
//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_height_map)
#ifdef HB_EXPERIMENTAL_API
// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
// None to indicate should remove
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_ot_name_record_ids_t, hb_bytes_t>), name_table_overrides)
#endif
#undef E

View File

@ -36,8 +36,10 @@
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "OT/Color/COLR/COLR.hh"
#include "OT/Color/COLR/colrv1-closure.hh"
#include "OT/Color/CPAL/CPAL.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-avar-table.hh"
#include "hb-ot-stat-table.hh"
@ -293,7 +295,7 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
feature_record_cond_idx_map,
feature_substitutes_map);
if (table_tag == HB_OT_TAG_GSUB)
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
hb_ot_layout_lookups_substitute_closure (plan->source,
&lookup_indices,
gids_to_retain);
@ -345,7 +347,10 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
hb_font_t *font = hb_font_create (plan->source);
hb_vector_t<hb_variation_t> vars;
vars.alloc (plan->user_axes_location.get_population ());
if (!vars.alloc (plan->user_axes_location.get_population ())) {
hb_font_destroy (font);
return nullptr;
}
for (auto _ : plan->user_axes_location)
{
@ -376,12 +381,10 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
const OT::VariationStore *var_store = nullptr;
hb_set_t varidx_set;
hb_font_t *font = nullptr;
float *store_cache = nullptr;
bool collect_delta = plan->pinned_at_default ? false : true;
if (collect_delta)
{
font = _get_hb_font_with_variations (plan);
if (gdef->has_var_store ())
{
var_store = &(gdef->get_var_store ());
@ -391,7 +394,8 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
OT::hb_collect_variation_indices_context_t c (&varidx_set,
&plan->layout_variation_idx_delta_map,
font, var_store,
plan->normalized_coords ? &(plan->normalized_coords) : nullptr,
var_store,
&plan->_glyphset_gsub,
&plan->gpos_lookups,
store_cache);
@ -400,7 +404,6 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
if (hb_ot_layout_has_positioning (plan->source))
gpos->collect_variation_indices (&c);
hb_font_destroy (font);
var_store->destroy_cache (store_cache);
gdef->remap_layout_variation_indices (&varidx_set, &plan->layout_variation_idx_delta_map);
@ -555,9 +558,12 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
if (plan->codepoint_to_glyph->has (cp))
continue;
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
plan->codepoint_to_glyph->set (cp, gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
hb_codepoint_t *gid;
if (!unicode_glyphid_map->has(cp, &gid))
continue;
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 ();
}
@ -602,14 +608,15 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
int operation_count,
unsigned depth = 0)
{
if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
if (unlikely (--operation_count < 0)) return operation_count;
/* Check if is already visited */
if (gids_to_retain->has (gid)) return operation_count;
gids_to_retain->add (gid);
for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ())
if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
if (unlikely (--operation_count < 0)) return operation_count;
for (auto &item : glyf.glyph_for_gid (gid).get_composite_iterator ())
operation_count =
_glyf_add_gid_and_children (glyf,
item.get_gid (),
@ -617,9 +624,53 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
operation_count,
depth);
#ifndef HB_NO_VAR_COMPOSITES
for (auto &item : glyf.glyph_for_gid (gid).get_var_composite_iterator ())
{
operation_count =
_glyf_add_gid_and_children (glyf,
item.get_gid (),
gids_to_retain,
operation_count,
depth);
}
#endif
return operation_count;
}
static void
_nameid_closure (hb_subset_plan_t* plan,
hb_set_t* drop_tables)
{
#ifndef HB_NO_STYLE
plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
#endif
#ifndef HB_NO_VAR
if (!plan->all_axes_pinned)
plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
#endif
#ifndef HB_NO_COLOR
if (!drop_tables->has (HB_OT_TAG_CPAL))
plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
#endif
#ifndef HB_NO_SUBSET_LAYOUT
if (!drop_tables->has (HB_OT_TAG_GPOS))
{
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids);
gpos.destroy ();
}
if (!drop_tables->has (HB_OT_TAG_GSUB))
{
hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> ();
gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids);
gsub.destroy ();
}
#endif
}
static void
_populate_gids_to_retain (hb_subset_plan_t* plan,
hb_set_t* drop_tables)
@ -673,6 +724,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
plan->_glyphset_colred = cur_glyphset;
_nameid_closure (plan, drop_tables);
/* Populate a full set of glyphs to retain by adding all referenced
* composite glyphs. */
if (glyf.has_data ())
@ -716,10 +768,11 @@ _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
;
}
static void
static bool
_create_old_gid_to_new_gid_map (const hb_face_t *face,
bool retain_gids,
const hb_set_t *all_gids_to_retain,
const hb_map_t *requested_glyph_map,
hb_map_t *glyph_map, /* OUT */
hb_map_t *reverse_glyph_map, /* OUT */
unsigned int *num_glyphs /* OUT */)
@ -728,7 +781,54 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
reverse_glyph_map->resize (pop);
glyph_map->resize (pop);
if (!retain_gids)
if (*requested_glyph_map)
{
hb_set_t new_gids(requested_glyph_map->values());
if (new_gids.get_population() != requested_glyph_map->get_population())
{
DEBUG_MSG (SUBSET, nullptr, "The provided custom glyph mapping is not unique.");
return false;
}
if (retain_gids)
{
DEBUG_MSG (SUBSET, nullptr,
"HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if "
"a custom glyph mapping has been provided.");
return false;
}
hb_codepoint_t max_glyph = 0;
hb_set_t remaining;
for (auto old_gid : all_gids_to_retain->iter ())
{
if (old_gid == 0) {
reverse_glyph_map->set(0, 0);
continue;
}
hb_codepoint_t* new_gid;
if (!requested_glyph_map->has (old_gid, &new_gid))
{
remaining.add(old_gid);
continue;
}
if (*new_gid > max_glyph)
max_glyph = *new_gid;
reverse_glyph_map->set (*new_gid, old_gid);
}
// Anything that wasn't mapped by the requested mapping should
// be placed after the requested mapping.
for (auto old_gid : remaining)
{
reverse_glyph_map->set(++max_glyph, old_gid);
}
*num_glyphs = max_glyph + 1;
}
else if (!retain_gids)
{
+ hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
| hb_sink (reverse_glyph_map)
@ -754,21 +854,8 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
| hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse)
| hb_sink (glyph_map)
;
}
static void
_nameid_closure (hb_face_t *face,
hb_set_t *nameids,
bool all_axes_pinned,
hb_hashmap_t<hb_tag_t, float> *user_axes_location)
{
#ifndef HB_NO_STYLE
face->table.STAT->collect_name_ids (user_axes_location, nameids);
#endif
#ifndef HB_NO_VAR
if (!all_axes_pinned)
face->table.fvar->collect_name_ids (user_axes_location, nameids);
#endif
return true;
}
#ifndef HB_NO_VAR
@ -783,12 +870,15 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
bool has_avar = face->table.avar->has_data ();
const OT::SegmentMaps *seg_maps = nullptr;
unsigned avar_axis_count = 0;
if (has_avar)
{
seg_maps = face->table.avar->get_segment_maps ();
avar_axis_count = face->table.avar->get_axis_count();
}
bool axis_not_pinned = false;
unsigned old_axis_idx = 0, new_axis_idx = 0;
unsigned int i = 0;
for (const auto& axis : axes)
{
hb_tag_t axis_tag = axis.get_axis_tag ();
@ -803,7 +893,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
else
{
int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag));
if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
if (has_avar && old_axis_idx < avar_axis_count)
{
normalized_v = seg_maps->map (normalized_v);
}
@ -811,17 +901,99 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
if (normalized_v != 0)
plan->pinned_at_default = false;
plan->normalized_coords[i] = normalized_v;
plan->normalized_coords[old_axis_idx] = normalized_v;
}
if (has_avar)
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
old_axis_idx++;
i++;
if (has_avar && old_axis_idx < avar_axis_count)
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
}
plan->all_axes_pinned = !axis_not_pinned;
}
static void
_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
{
if (!plan->normalized_coords) return;
OT::cff2::accelerator_t cff2 (plan->source);
if (!cff2.is_valid ()) return;
hb_font_t *font = nullptr;
if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
{
hb_font_destroy (font);
return;
}
hb_glyph_extents_t extents = {0x7FFF, -0x7FFF};
OT::hmtx_accelerator_t _hmtx (plan->source);
float *hvar_store_cache = nullptr;
if (_hmtx.has_data () && _hmtx.var_table.get_length ())
hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
OT::vmtx_accelerator_t _vmtx (plan->source);
float *vvar_store_cache = nullptr;
if (_vmtx.has_data () && _vmtx.var_table.get_length ())
vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache ();
for (auto p : *plan->glyph_map)
{
hb_codepoint_t old_gid = p.first;
hb_codepoint_t new_gid = p.second;
if (!cff2.get_extents (font, old_gid, &extents)) continue;
bool has_bounds_info = true;
if (extents.x_bearing == 0 && extents.width == 0 &&
extents.height == 0 && extents.y_bearing == 0)
has_bounds_info = false;
if (has_bounds_info)
{
plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing);
plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width);
plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing);
plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height);
}
if (_hmtx.has_data ())
{
int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid);
if (_hmtx.var_table.get_length ())
hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
hvar_store_cache));
int lsb = extents.x_bearing;
if (!has_bounds_info)
{
if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
continue;
}
plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
plan->bounds_width_map.set (new_gid, extents.width);
}
if (_vmtx.has_data ())
{
int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid);
if (_vmtx.var_table.get_length ())
vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
vvar_store_cache));
int tsb = extents.y_bearing;
if (!has_bounds_info)
{
if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb))
continue;
}
plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
plan->bounds_height_map.set (new_gid, extents.height);
}
}
hb_font_destroy (font);
if (hvar_store_cache)
_hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache);
if (vvar_store_cache)
_vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
}
#endif
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
@ -873,7 +1045,6 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
if (accel)
accelerator = (hb_subset_accelerator_t*) accel;
if (unlikely (in_error ()))
return;
@ -884,13 +1055,19 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this);
_populate_gids_to_retain (this, input->sets.drop_tables);
if (unlikely (in_error ()))
return;
_create_old_gid_to_new_gid_map (face,
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
&_glyphset,
glyph_map,
reverse_glyph_map,
&_num_output_glyphs);
if (!check_success(_create_old_gid_to_new_gid_map(
face,
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
&_glyphset,
&input->glyph_map,
glyph_map,
reverse_glyph_map,
&_num_output_glyphs))) {
return;
}
_create_glyph_map_gsub (
&_glyphset_gsub,
@ -905,10 +1082,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second);
}
_nameid_closure (face, &name_ids, all_axes_pinned, &user_axes_location);
if (unlikely (in_error ()))
return;
#ifndef HB_NO_VAR
_update_instance_metrics_map_from_cff2 (this);
#endif
if (attach_accelerator_data)
{
hb_multimap_t gid_to_unicodes;
@ -926,7 +1106,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
gid_to_unicodes,
unicodes,
has_seac);
check_success (inprogress_accelerator);
}
#define HB_SUBSET_PLAN_MEMBER(Type, Name) check_success (!Name.in_error ());
#include "hb-subset-plan-member-list.hh"
#undef HB_SUBSET_PLAN_MEMBER
}
/**

View File

@ -97,112 +97,30 @@ struct hb_subset_plan_t
bool attach_accelerator_data = false;
bool force_long_loca = false;
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t unicodes;
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
// name_ids we would like to retain
hb_set_t name_ids;
// name_languages we would like to retain
hb_set_t name_languages;
//layout features which will be preserved
hb_set_t layout_features;
// layout scripts which will be preserved.
hb_set_t layout_scripts;
//glyph ids requested to retain
hb_set_t glyphs_requested;
// Tables which should not be processed, just pass them through.
hb_set_t no_subset_tables;
// Tables which should be dropped.
hb_set_t drop_tables;
// The glyph subset
hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated
// Old -> New glyph id mapping
hb_map_t *glyph_map; // Needs to be heap-allocated
hb_map_t *reverse_glyph_map; // Needs to be heap-allocated
hb_map_t glyph_map_gsub;
// Plan is only good for a specific source/dest so keep them with it
hb_face_t *source;
hb_face_t *dest;
unsigned int _num_output_glyphs;
hb_set_t _glyphset;
hb_set_t _glyphset_gsub;
hb_set_t _glyphset_mathed;
hb_set_t _glyphset_colred;
//active lookups we'd like to retain
hb_map_t gsub_lookups;
hb_map_t gpos_lookups;
//active langsys we'd like to retain
hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> gsub_langsys;
hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> gpos_langsys;
//active features after removing redundant langsys and prune_features
hb_map_t gsub_features;
hb_map_t gpos_features;
//active feature variation records/condition index with variations
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> gsub_feature_record_cond_idx_map;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> gpos_feature_record_cond_idx_map;
//feature index-> address of substituation feature table mapping with
//variations
hb_hashmap_t<unsigned, const OT::Feature*> gsub_feature_substitutes_map;
hb_hashmap_t<unsigned, const OT::Feature*> gpos_feature_substitutes_map;
//active layers/palettes we'd like to retain
hb_map_t colrv1_layers;
hb_map_t colr_palettes;
//Old layout item variation index -> (New varidx, delta) mapping
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> layout_variation_idx_delta_map;
//gdef varstore retained varidx mapping
hb_vector_t<hb_inc_bimap_t> gdef_varstore_inner_maps;
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
//normalized axes location map
hb_hashmap_t<hb_tag_t, int> axes_location;
hb_vector_t<int> normalized_coords;
//user specified axes location map
hb_hashmap_t<hb_tag_t, float> user_axes_location;
//retained old axis index -> new axis index mapping in fvar axis array
hb_map_t axes_index_map;
//axis_index->axis_tag mapping in fvar axis array
hb_map_t axes_old_index_tag_map;
bool all_axes_pinned;
bool pinned_at_default;
bool has_seac;
//hmtx metrics map: new gid->(advance, lsb)
mutable hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> hmtx_map;
//vmtx metrics map: new gid->(advance, lsb)
mutable hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> vmtx_map;
//boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin
mutable hb_map_t bounds_width_map;
//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
mutable hb_map_t bounds_height_map;
#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
#include "hb-subset-plan-member-list.hh"
#undef HB_SUBSET_PLAN_MEMBER
//recalculated head/maxp table info after instancing
mutable head_maxp_info_t head_maxp_info;
#ifdef HB_EXPERIMENTAL_API
// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
// None to indicate should remove
hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides;
#endif
const hb_subset_accelerator_t* accelerator;
hb_subset_accelerator_t* inprogress_accelerator;
@ -211,7 +129,7 @@ struct hb_subset_plan_t
template<typename T>
hb_blob_ptr_t<T> source_table()
{
hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
hb_lock_t lock (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache;
if (cache

View File

@ -96,8 +96,8 @@ static hb_tag_t known_tables[] {
HB_OT_TAG_BASE,
HB_OT_TAG_CBDT,
HB_OT_TAG_CBLC,
HB_OT_TAG_cff1,
HB_OT_TAG_cff2,
HB_OT_TAG_CFF1,
HB_OT_TAG_CFF2,
HB_OT_TAG_cmap,
HB_OT_TAG_COLR,
HB_OT_TAG_CPAL,
@ -457,8 +457,8 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
#ifndef HB_NO_SUBSET_CFF
case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan, buf);
case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan, buf);
case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf);
case HB_OT_TAG_CFF2: return _subset<const OT::cff2> (plan, buf);
case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf);
#endif
@ -637,8 +637,3 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
end:
return success ? hb_face_reference (plan->dest) : nullptr;
}
#ifndef HB_NO_VISIBILITY
/* If NO_VISIBILITY, libharfbuzz has this. */
#include "hb-ot-name-language-static.hh"
#endif

View File

@ -71,6 +71,8 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* in the final subset.
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
* OS/2 will not be recalculated.
* @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
* substitution rules (GSUB). Since: 7.2.0.
*
* List of boolean properties that can be configured on the subset input.
*
@ -87,6 +89,7 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
} hb_subset_flags_t;
/**
@ -151,6 +154,9 @@ hb_subset_input_glyph_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type);
HB_EXTERN hb_map_t*
hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input);
HB_EXTERN hb_subset_flags_t
hb_subset_input_get_flags (hb_subset_input_t *input);

View File

@ -164,7 +164,7 @@ typedef enum
* @HB_UNICODE_COMBINING_CLASS_CCC122: [Lao]
* @HB_UNICODE_COMBINING_CLASS_CCC129: [Tibetan]
* @HB_UNICODE_COMBINING_CLASS_CCC130: [Tibetan]
* @HB_UNICODE_COMBINING_CLASS_CCC133: [Tibetan]
* @HB_UNICODE_COMBINING_CLASS_CCC132: [Tibetan] Since: 7.2.0
* @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: Marks attached at the bottom left
* @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: Marks attached directly below
* @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: Marks attached directly above
@ -246,7 +246,7 @@ typedef enum
/* Tibetan */
HB_UNICODE_COMBINING_CLASS_CCC129 = 129,
HB_UNICODE_COMBINING_CLASS_CCC130 = 130,
HB_UNICODE_COMBINING_CLASS_CCC133 = 132,
HB_UNICODE_COMBINING_CLASS_CCC132 = 132,
HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT = 200,

View File

@ -290,13 +290,11 @@ struct hb_vector_t
copy_vector (const hb_vector_t &other)
{
length = other.length;
#ifndef HB_OPTIMIZE_SIZE
if (sizeof (T) >= sizeof (long long))
if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long))
/* This runs faster because of alignment. */
for (unsigned i = 0; i < length; i++)
arrayZ[i] = other.arrayZ[i];
else
#endif
hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size);
}
template <typename T = Type,

View File

@ -47,7 +47,7 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
#define HB_VERSION_MINOR 1
#define HB_VERSION_MINOR 3
/**
* HB_VERSION_MICRO:
*
@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
#define HB_VERSION_STRING "7.1.0"
#define HB_VERSION_STRING "7.3.0"
/**
* HB_VERSION_ATLEAST:

View File

@ -255,8 +255,8 @@ extern "C" void hb_free_impl(void *ptr);
#endif
#if defined(__OPTIMIZE__) && hb_has_builtin(__builtin_expect)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
#define likely(expr) __builtin_expect (bool(expr), 1)
#define unlikely(expr) __builtin_expect (bool(expr), 0)
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
@ -509,6 +509,12 @@ static_assert ((sizeof (hb_mask_t) == 4), "");
static_assert ((sizeof (hb_var_int_t) == 4), "");
/* Pie time. */
// https://github.com/harfbuzz/harfbuzz/issues/4166
#define HB_PI 3.14159265358979f
#define HB_2_PI (2.f * HB_PI)
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include
* them directly.*/

288
gfx/harfbuzz/src/justify.py Normal file
View File

@ -0,0 +1,288 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, HarfBuzz as hb
POOL = {}
def move_to_f(funcs, draw_data, st, to_x, to_y, user_data):
context = POOL[draw_data]
context.move_to(to_x, to_y)
def line_to_f(funcs, draw_data, st, to_x, to_y, user_data):
context = POOL[draw_data]
context.line_to(to_x, to_y)
def cubic_to_f(
funcs,
draw_data,
st,
control1_x,
control1_y,
control2_x,
control2_y,
to_x,
to_y,
user_data,
):
context = POOL[draw_data]
context.curve_to(control1_x, control1_y, control2_x, control2_y, to_x, to_y)
def close_path_f(funcs, draw_data, st, user_data):
context = POOL[draw_data]
context.close_path()
DFUNCS = hb.draw_funcs_create()
hb.draw_funcs_set_move_to_func(DFUNCS, move_to_f, None)
hb.draw_funcs_set_line_to_func(DFUNCS, line_to_f, None)
hb.draw_funcs_set_cubic_to_func(DFUNCS, cubic_to_f, None)
hb.draw_funcs_set_close_path_func(DFUNCS, close_path_f, None)
def push_transform_f(funcs, paint_data, xx, yx, xy, yy, dx, dy, user_data):
raise NotImplementedError
def pop_transform_f(funcs, paint_data, user_data):
raise NotImplementedError
def color_f(funcs, paint_data, is_foreground, color, user_data):
context = POOL[paint_data]
r = hb.color_get_red(color) / 255
g = hb.color_get_green(color) / 255
b = hb.color_get_blue(color) / 255
a = hb.color_get_alpha(color) / 255
context.set_source_rgba(r, g, b, a)
context.paint()
def push_clip_rectangle_f(funcs, paint_data, xmin, ymin, xmax, ymax, user_data):
context = POOL[paint_data]
context.save()
context.rectangle(xmin, ymin, xmax, ymax)
context.clip()
def push_clip_glyph_f(funcs, paint_data, glyph, font, user_data):
context = POOL[paint_data]
context.save()
context.new_path()
hb.font_draw_glyph(font, glyph, DFUNCS, paint_data)
context.close_path()
context.clip()
def pop_clip_f(funcs, paint_data, user_data):
context = POOL[paint_data]
context.restore()
def push_group_f(funcs, paint_data, user_data):
raise NotImplementedError
def pop_group_f(funcs, paint_data, mode, user_data):
raise NotImplementedError
PFUNCS = hb.paint_funcs_create()
hb.paint_funcs_set_push_transform_func(PFUNCS, push_transform_f, None)
hb.paint_funcs_set_pop_transform_func(PFUNCS, pop_transform_f, None)
hb.paint_funcs_set_color_func(PFUNCS, color_f, None)
hb.paint_funcs_set_push_clip_glyph_func(PFUNCS, push_clip_glyph_f, None)
hb.paint_funcs_set_push_clip_rectangle_func(PFUNCS, push_clip_rectangle_f, None)
hb.paint_funcs_set_pop_clip_func(PFUNCS, pop_clip_f, None)
hb.paint_funcs_set_push_group_func(PFUNCS, push_group_f, None)
hb.paint_funcs_set_pop_group_func(PFUNCS, pop_group_f, None)
def makebuffer(words):
buf = hb.buffer_create()
text = " ".join(words)
hb.buffer_add_codepoints(buf, [ord(c) for c in text], 0, len(text))
hb.buffer_guess_segment_properties(buf)
return buf
def justify(face, words, advance, target_advance):
font = hb.font_create(face)
buf = makebuffer(words)
wiggle = 5
shrink = target_advance - wiggle < advance
expand = target_advance + wiggle > advance
ret, advance, tag, value = hb.shape_justify(
font,
buf,
None,
None,
target_advance,
target_advance,
advance,
)
if not ret:
return False, buf, None
if tag:
variation = hb.variation_t()
variation.tag = tag
variation.value = value
else:
variation = None
if shrink and advance > target_advance + wiggle:
return False, buf, variation
if expand and advance < target_advance - wiggle:
return False, buf, variation
return True, buf, variation
def shape(face, words):
font = hb.font_create(face)
buf = makebuffer(words)
hb.shape(font, buf)
positions = hb.buffer_get_glyph_positions(buf)
advance = sum(p.x_advance for p in positions)
return buf, advance
def typeset(face, text, target_advance):
lines = []
words = []
for word in text.split():
words.append(word)
buf, advance = shape(face, words)
if advance > target_advance:
# Shrink
ret, buf, variation = justify(face, words, advance, target_advance)
if ret:
lines.append((buf, variation))
words = []
# If if fails, pop the last word and shrink, and hope for the best.
# A too short line is better than too long.
elif len(words) > 1:
words.pop()
_, buf, variation = justify(face, words, advance, target_advance)
lines.append((buf, variation))
words = [word]
# But if it is one word, meh.
else:
lines.append((buf, variation))
words = []
# Justify last line
if words:
_, buf, variation = justify(face, words, advance, target_advance)
lines.append((buf, variation))
return lines
def render(face, text, context, width, height, fontsize):
font = hb.font_create(face)
margin = fontsize * 2
scale = fontsize / hb.face_get_upem(face)
target_advance = (width - (margin * 2)) / scale
lines = typeset(face, text, target_advance)
_, extents = hb.font_get_h_extents(font)
lineheight = extents.ascender - extents.descender + extents.line_gap
lineheight *= scale
context.save()
context.translate(0, margin)
context.set_font_size(12)
context.set_source_rgb(1, 0, 0)
for buf, variation in lines:
rtl = hb.buffer_get_direction(buf) == hb.direction_t.RTL
if rtl:
hb.buffer_reverse(buf)
infos = hb.buffer_get_glyph_infos(buf)
positions = hb.buffer_get_glyph_positions(buf)
advance = sum(p.x_advance for p in positions)
context.translate(0, lineheight)
context.save()
context.save()
context.move_to(0, -20)
if variation:
tag = hb.tag_to_string(variation.tag).decode("ascii")
context.show_text(f" {tag}={variation.value:g}")
context.move_to(0, 0)
context.show_text(f" {advance:g}/{target_advance:g}")
context.restore()
if variation:
hb.font_set_variations(font, [variation])
context.translate(margin, 0)
context.scale(scale, -scale)
if rtl:
context.translate(target_advance, 0)
for info, pos in zip(infos, positions):
if rtl:
context.translate(-pos.x_advance, pos.y_advance)
context.save()
context.translate(pos.x_offset, pos.y_offset)
hb.font_paint_glyph(font, info.codepoint, PFUNCS, id(context), 0, 0x0000FF)
context.restore()
if not rtl:
context.translate(+pos.x_advance, pos.y_advance)
context.restore()
context.restore()
def main(fontpath, textpath):
fontsize = 70
blob = hb.blob_create_from_file(fontpath)
face = hb.face_create(blob, 0)
with open(textpath) as f:
text = f.read()
def on_draw(da, context):
alloc = da.get_allocation()
POOL[id(context)] = context
render(face, text, context, alloc.width, alloc.height, fontsize)
del POOL[id(context)]
drawingarea = Gtk.DrawingArea()
drawingarea.connect("draw", on_draw)
win = Gtk.Window()
win.connect("destroy", Gtk.main_quit)
win.set_default_size(1000, 700)
win.add(drawingarea)
win.show_all()
Gtk.main()
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="HarfBuzz justification demo.")
parser.add_argument("fontfile", help="font file")
parser.add_argument("textfile", help="text")
args = parser.parse_args()
main(args.fontfile, args.textfile)

View File

@ -361,6 +361,7 @@ hb_subset_sources = files(
'hb-subset-instancer-solver.cc',
'hb-subset-plan.cc',
'hb-subset-plan.hh',
'hb-subset-plan-member-list.hh',
'hb-subset-repacker.cc',
'graph/gsubgpos-context.cc',
'graph/gsubgpos-context.hh',
@ -668,6 +669,7 @@ if get_option('tests').enabled()
'test-ot-name': 'test-ot-name.cc',
'test-ot-glyphname': 'test-ot-glyphname.cc',
'test-ot-gpos-size-params': 'test-gpos-size-params.cc',
'test-ot-gsub-get-alternates': 'test-gsub-get-alternates.cc',
'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc',
'test-use-table': 'test-use-table.cc',
}

View File

@ -1,110 +0,0 @@
/*
* Copyright © 2019 Facebook, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Facebook Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#include "hb-algs.hh"
#include "hb-set.hh"
static char *
test_func (int a, char **b)
{
return b ? b[a] : nullptr;
}
struct A
{
void a () {}
};
int
main (int argc, char **argv)
{
int i = 1;
auto p = hb_pair (1, i);
p.second = 2;
assert (i == 2);
const int c = 3;
auto pc = hb_pair (1, c);
assert (pc.second == 3);
auto q = p;
assert (&q != &p);
q.second = 4;
assert (i == 4);
hb_invoke (test_func, 0, nullptr);
A a;
hb_invoke (&A::a, a);
assert (1 == hb_min (8, 1));
assert (8 == hb_max (8, 1));
int x = 1, y = 2;
hb_min (x, 3);
hb_min (3, x);
hb_min (x, 4 + 3);
int &z = hb_min (x, y);
z = 3;
assert (x == 3);
hb_pair_t<const int*, int> xp = hb_pair_t<int *, long> (nullptr, 0);
xp = hb_pair_t<int *, double> (nullptr, 1);
xp = hb_pair_t<const int*, int> (nullptr, 1);
assert (3 == hb_partial (hb_min, 3) (4));
assert (3 == hb_partial<1> (hb_min, 4) (3));
auto M0 = hb_partial<2> (hb_max, 0);
assert (M0 (-2) == 0);
assert (M0 (+2) == 2);
assert (hb_add (2) (5) == 7);
assert (hb_add (5) (2) == 7);
x = 1;
assert (++hb_inc (x) == 3);
assert (x == 3);
hb_set_t set1 {1};
hb_set_t set2 {2};
assert (hb_hash (set1) != hb_hash (set2));
assert (hb_hash (set1) == hb_hash (hb_set_t {1}));
assert (hb_hash (set1) != hb_hash (hb_set_t {}));
assert (hb_hash (set1) != hb_hash (hb_set_t {2}));
assert (hb_hash (set2) == hb_hash (hb_set_t {2}));
/* hb_hash, unlike std::hash, dereferences pointers. */
assert (hb_hash (set1) == hb_hash (&set1));
assert (hb_hash (set1) == hb_hash (hb::shared_ptr<hb_set_t> {hb_set_reference (&set1)}));
assert (hb_hash (set1) == hb_hash (hb::unique_ptr<hb_set_t> {hb_set_reference (&set1)}));
return 0;
}

View File

@ -1,79 +0,0 @@
/*
* Copyright © 2020 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Garret Rieger
*/
#include "hb.hh"
#include "hb-array.hh"
static void
test_reverse ()
{
int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
hb_array_t<int> a (values, 9);
a.reverse();
int expected_values[] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
hb_array_t<int> expected (expected_values, 9);
assert (a == expected);
}
static void
test_reverse_range ()
{
int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
hb_array_t<int> a (values, 9);
a.reverse(2, 6);
int expected_values[] = {1, 2, 6, 5, 4, 3, 7, 8, 9};
hb_array_t<int> expected (expected_values, 9);
assert (a == expected);
}
static void
test_reverse_invalid ()
{
int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
hb_array_t<int> a (values, 9);
a.reverse(4, 3);
a.reverse(2, 3);
a.reverse(5, 5);
a.reverse(12, 15);
int expected_values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
hb_array_t<int> expected (expected_values, 9);
assert (a == expected);
}
int
main (int argc, char **argv)
{
/* The following fails on MSVC. */
// assert (sizeof (hb_array_t<int>) == sizeof (hb_sorted_array_t<int>));
test_reverse ();
test_reverse_range ();
test_reverse_invalid ();
}

Some files were not shown because too many files have changed in this diff Show More