Merge branch 'master' into bitops

This commit is contained in:
Behdad Esfahbod 2018-02-18 10:45:33 -08:00 committed by GitHub
commit fe8f40a418
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 255 additions and 116 deletions

29
TODO
View File

@ -1,24 +1,14 @@
General fixes:
=============
- AAT 'morx' implementation.
- Return "safe-to-break" bit from shaping.
- Implement 'rand' feature.
- mask propagation? (when ligation, "or" the masks).
API issues:
===========
- API to accept a list of languages?
- Add init_func to font_funcs. Adjust ft.
- 'const' for getter APIs? (use mutable internally)
- Remove hb_ot_shape_glyphs_closure()?
@ -39,7 +29,7 @@ API additions
- Add query / enumeration API for aalt-like features?
- SFNT api? get_num_faces? get_table_tags? (there's something in stash)
- SFNT api? get_num_faces?
- Add segmentation API
@ -50,20 +40,3 @@ hb-view / hb-shape enhancements:
===============================
- Add --width, --height, --auto-size, --ink-box, --align, etc?
Tests to write:
==============
- ot-layout enumeration API (needs font)
- Finish test-shape.c, grep for TODO
- Finish test-unicode.c, grep for TODO
- GObject, FreeType, etc
- hb_cache_t and relatives
- hb_feature_to/from_string
- hb_buffer_[sg]et_contents

View File

@ -344,8 +344,7 @@ struct hb_buffer_t {
inline void
unsafe_to_break_all (void)
{
for (unsigned int i = 0; i < len; i++)
info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
unsafe_to_break_impl (0, len);
}
inline void
safe_to_break_all (void)

View File

@ -1244,8 +1244,6 @@ resize_and_retry:
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
info++, pos++;
}
else
@ -1255,8 +1253,6 @@ resize_and_retry:
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
info++, pos++;
}

View File

@ -878,8 +878,6 @@ retry_getglyphs:
pos->x_offset =
x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
pos->y_offset = y_mult * info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
if (isRightToLeft)

View File

@ -360,7 +360,6 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
info->codepoint = gids[clusters[i].base_glyph + j];
info->cluster = clusters[i].cluster;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
}
}

View File

@ -81,9 +81,9 @@ struct glyf
struct GlyphHeader
{
HBINT16 numberOfContours; /* If the number of contours is
* greater than or equal to zero,
* this is a simple glyph; if negative,
* this is a composite glyph. */
* greater than or equal to zero,
* this is a simple glyph; if negative,
* this is a composite glyph. */
FWORD xMin; /* Minimum x for coordinate data. */
FWORD yMin; /* Minimum y for coordinate data. */
FWORD xMax; /* Maximum x for coordinate data. */
@ -92,6 +92,102 @@ struct glyf
DEFINE_SIZE_STATIC (10);
};
struct CompositeGlyphHeader
{
static const uint16_t ARG_1_AND_2_ARE_WORDS = 0x0001;
static const uint16_t ARGS_ARE_XY_VALUES = 0x0002;
static const uint16_t ROUND_XY_TO_GRID = 0x0004;
static const uint16_t WE_HAVE_A_SCALE = 0x0008;
static const uint16_t MORE_COMPONENTS = 0x0020;
static const uint16_t WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
static const uint16_t WE_HAVE_A_TWO_BY_TWO = 0x0080;
static const uint16_t WE_HAVE_INSTRUCTIONS = 0x0100;
static const uint16_t USE_MY_METRICS = 0x0200;
static const uint16_t OVERLAP_COMPOUND = 0x0400;
static const uint16_t SCALED_COMPONENT_OFFSET = 0x0800;
static const uint16_t UNSCALED_COMPONENT_OFFSET = 0x1000;
HBUINT16 flags;
HBUINT16 glyphIndex;
inline unsigned int get_size (void) const
{
unsigned int size = min_size;
if (flags & ARG_1_AND_2_ARE_WORDS) {
// arg1 and 2 are int16
size += 4;
} else {
// arg1 and 2 are int8
size += 2;
}
if (flags & WE_HAVE_A_SCALE) {
// One x 16 bit (scale)
size += 2;
} else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
// Two x 16 bit (xscale, yscale)
size += 4;
} else if (flags & WE_HAVE_A_TWO_BY_TWO) {
// Four x 16 bit (xscale, scale01, scale10, yscale)
size += 8;
}
return size;
}
struct Iterator
{
const char *glyph_start;
const char *glyph_end;
const CompositeGlyphHeader *current;
inline bool move_to_next ()
{
if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
{
const CompositeGlyphHeader *possible =
&StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
if (!in_range (possible))
return false;
current = possible;
return true;
}
return false;
}
inline bool in_range (const CompositeGlyphHeader *composite) const
{
return (const char *) composite >= glyph_start
&& ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
&& ((const char *) composite + composite->get_size()) <= glyph_end;
}
};
static inline bool get_iterator (const char * glyph_data,
unsigned int length,
CompositeGlyphHeader::Iterator *iterator /* OUT */)
{
if (length < GlyphHeader::static_size)
return false; /* Empty glyph; zero extents. */
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
if (glyph_header.numberOfContours < 0)
{
const CompositeGlyphHeader *possible =
&StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
iterator->glyph_start = glyph_data;
iterator->glyph_end = (const char *) glyph_data + length;
if (!iterator->in_range (possible))
return false;
iterator->current = possible;
return true;
}
return false;
}
DEFINE_SIZE_MIN (4);
};
struct accelerator_t
{
inline void init (hb_face_t *face)
@ -122,6 +218,23 @@ struct glyf
hb_blob_destroy (glyf_blob);
}
/*
* Returns true if the referenced glyph is a valid glyph and a composite glyph.
* If true is returned a pointer to the composite glyph will be written into
* composite.
*/
inline bool get_composite (hb_codepoint_t glyph,
CompositeGlyphHeader::Iterator *composite /* OUT */) const
{
unsigned int start_offset, end_offset;
if (!get_offsets (glyph, &start_offset, &end_offset))
return false; /* glyph not found */
return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset,
end_offset - start_offset,
composite);
}
inline bool get_offsets (hb_codepoint_t glyph,
unsigned int *start_offset /* OUT */,
unsigned int *end_offset /* OUT */) const

View File

@ -100,47 +100,47 @@ struct os2
HBUINT16 version;
/* Version 0 */
HBINT16 xAvgCharWidth;
HBINT16 xAvgCharWidth;
HBUINT16 usWeightClass;
HBUINT16 usWidthClass;
HBUINT16 fsType;
HBINT16 ySubscriptXSize;
HBINT16 ySubscriptYSize;
HBINT16 ySubscriptXOffset;
HBINT16 ySubscriptYOffset;
HBINT16 ySuperscriptXSize;
HBINT16 ySuperscriptYSize;
HBINT16 ySuperscriptXOffset;
HBINT16 ySuperscriptYOffset;
HBINT16 yStrikeoutSize;
HBINT16 yStrikeoutPosition;
HBINT16 sFamilyClass;
HBUINT8 panose[10];
HBUINT32 ulUnicodeRange[4];
HBINT16 ySubscriptXSize;
HBINT16 ySubscriptYSize;
HBINT16 ySubscriptXOffset;
HBINT16 ySubscriptYOffset;
HBINT16 ySuperscriptXSize;
HBINT16 ySuperscriptYSize;
HBINT16 ySuperscriptXOffset;
HBINT16 ySuperscriptYOffset;
HBINT16 yStrikeoutSize;
HBINT16 yStrikeoutPosition;
HBINT16 sFamilyClass;
HBUINT8 panose[10];
HBUINT32 ulUnicodeRange[4];
Tag achVendID;
HBUINT16 fsSelection;
HBUINT16 usFirstCharIndex;
HBUINT16 usLastCharIndex;
HBINT16 sTypoAscender;
HBINT16 sTypoDescender;
HBINT16 sTypoLineGap;
HBINT16 sTypoAscender;
HBINT16 sTypoDescender;
HBINT16 sTypoLineGap;
HBUINT16 usWinAscent;
HBUINT16 usWinDescent;
/* Version 1 */
//HBUINT32 ulCodePageRange1;
//HBUINT32 ulCodePageRange2;
//HBUINT32 ulCodePageRange1;
//HBUINT32 ulCodePageRange2;
/* Version 2 */
//HBINT16 sxHeight;
//HBINT16 sCapHeight;
//HBUINT16 usDefaultChar;
//HBUINT16 usBreakChar;
//HBUINT16 usMaxContext;
//HBINT16 sxHeight;
//HBINT16 sCapHeight;
//HBUINT16 usDefaultChar;
//HBUINT16 usBreakChar;
//HBUINT16 usMaxContext;
/* Version 5 */
//HBUINT16 usLowerOpticalPointSize;
//HBUINT16 usUpperOpticalPointSize;
//HBUINT16 usLowerOpticalPointSize;
//HBUINT16 usUpperOpticalPointSize;
public:
DEFINE_SIZE_STATIC (78);

View File

@ -28,6 +28,7 @@
#include "hb-ot-glyf-table.hh"
#include "hb-set.h"
#include "hb-subset-glyf.hh"
#include "hb-subset-plan.hh"
static bool
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
@ -70,16 +71,41 @@ _write_loca_entry (unsigned int id, unsigned int offset, bool is_short, void *lo
}
}
static void
_update_components (hb_subset_plan_t * plan,
char * glyph_start,
unsigned int length)
{
OT::glyf::CompositeGlyphHeader::Iterator iterator;
if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
length,
&iterator))
{
do
{
hb_codepoint_t new_gid;
if (!hb_subset_plan_new_gid_for_old_id (plan,
iterator.current->glyphIndex,
&new_gid))
continue;
((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid);
} while (iterator.move_to_next());
}
}
static bool
_write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf,
_write_glyf_and_loca_prime (hb_subset_plan_t *plan,
const OT::glyf::accelerator_t &glyf,
const char *glyf_data,
hb_prealloced_array_t<hb_codepoint_t> &glyph_ids,
bool use_short_loca,
int glyf_prime_size,
char *glyf_prime_data /* OUT */,
int loca_prime_size,
char *loca_prime_data /* OUT */)
{
hb_prealloced_array_t<hb_codepoint_t> &glyph_ids = plan->gids_to_retain_sorted;
char *glyf_prime_data_next = glyf_prime_data;
for (unsigned int i = 0; i < glyph_ids.len; i++)
@ -92,6 +118,7 @@ _write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf,
memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
_write_loca_entry (i, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data);
_update_components (plan, glyf_prime_data_next, end_offset - start_offset);
glyf_prime_data_next += length;
}
@ -104,7 +131,7 @@ _write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf,
static bool
_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
const char *glyf_data,
hb_prealloced_array_t<hb_codepoint_t>&glyphs_to_retain,
hb_subset_plan_t *plan,
bool *use_short_loca,
hb_blob_t **glyf_prime /* OUT */,
hb_blob_t **loca_prime /* OUT */)
@ -112,6 +139,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
// TODO(grieger): Sanity check writes to make sure they are in-bounds.
// TODO(grieger): Sanity check allocation size for the new table.
// TODO(grieger): Don't fail on bad offsets, just dump them.
hb_prealloced_array_t<hb_codepoint_t> &glyphs_to_retain = plan->gids_to_retain_sorted;
unsigned int glyf_prime_size;
unsigned int loca_prime_size;
@ -126,7 +154,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
char *glyf_prime_data = (char *) malloc (glyf_prime_size);
char *loca_prime_data = (char *) malloc (loca_prime_size);
if (unlikely (!_write_glyf_and_loca_prime (glyf, glyf_data, glyphs_to_retain,
if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
*use_short_loca,
glyf_prime_size, glyf_prime_data,
loca_prime_size, loca_prime_data))) {
@ -168,7 +196,7 @@ hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
glyf.init(plan->source);
bool result = _hb_subset_glyf_and_loca (glyf,
glyf_data,
plan->gids_to_retain_sorted,
plan,
use_short_loca,
glyf_prime,
loca_prime);

View File

@ -28,6 +28,7 @@
#include "hb-subset-plan.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
static int
_hb_codepoint_t_cmp (const void *pa, const void *pb)
@ -62,10 +63,11 @@ hb_subset_plan_new_gid_for_old_id (hb_subset_plan_t *plan,
hb_codepoint_t *new_gid)
{
// the index in old_gids is the new gid; only up to codepoints.len are valid
for (unsigned int i = 0; i < plan->gids_to_retain.len; i++) {
if (plan->gids_to_retain[i] == old_gid) {
// +1: assign new gids from 1..N; 0 is special
*new_gid = i + 1;
for (unsigned int i = 0; i < plan->gids_to_retain_sorted.len; i++)
{
if (plan->gids_to_retain_sorted[i] == old_gid)
{
*new_gid = i;
return true;
}
}
@ -93,6 +95,27 @@ _populate_codepoints (hb_set_t *input_codepoints,
plan_codepoints.qsort (_hb_codepoint_t_cmp);
}
static void
_add_gid_and_children (const OT::glyf::accelerator_t &glyf,
hb_codepoint_t gid,
hb_set_t *gids_to_retain)
{
if (hb_set_has (gids_to_retain, gid))
// Already visited this gid, ignore.
return;
hb_set_add (gids_to_retain, gid);
OT::glyf::CompositeGlyphHeader::Iterator composite;
if (glyf.get_composite (gid, &composite))
{
do
{
_add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain);
} while (composite.move_to_next());
}
}
static void
_populate_gids_to_retain (hb_face_t *face,
hb_prealloced_array_t<hb_codepoint_t>& codepoints,
@ -100,26 +123,27 @@ _populate_gids_to_retain (hb_face_t *face,
hb_prealloced_array_t<hb_codepoint_t>& old_gids_sorted)
{
OT::cmap::accelerator_t cmap;
OT::glyf::accelerator_t glyf;
cmap.init (face);
glyf.init (face);
hb_auto_array_t<unsigned int> bad_indices;
old_gids.alloc (codepoints.len);
bool has_zero = false;
for (unsigned int i = 0; i < codepoints.len; i++) {
for (unsigned int i = 0; i < codepoints.len; i++)
{
hb_codepoint_t gid;
if (!cmap.get_nominal_glyph (codepoints[i], &gid)) {
if (!cmap.get_nominal_glyph (codepoints[i], &gid))
{
gid = -1;
*(bad_indices.push ()) = i;
}
if (gid == 0) {
has_zero = true;
}
*(old_gids.push ()) = gid;
}
/* Generally there shouldn't be any */
while (bad_indices.len > 0) {
while (bad_indices.len > 0)
{
unsigned int i = bad_indices[bad_indices.len - 1];
bad_indices.pop ();
DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", codepoints[i]);
@ -127,19 +151,21 @@ _populate_gids_to_retain (hb_face_t *face,
old_gids.remove (i);
}
// Populate a second glyph id array that is sorted by glyph id
// and is gauranteed to contain 0.
old_gids_sorted.alloc (old_gids.len + (has_zero ? 0 : 1));
for (unsigned int i = 0; i < old_gids.len; i++) {
*(old_gids_sorted.push ()) = old_gids[i];
}
if (!has_zero)
*(old_gids_sorted.push ()) = 0;
old_gids_sorted.qsort (_hb_codepoint_t_cmp);
// TODO(Q1) expand with glyphs that make up complex glyphs
// Populate a full set of glyphs to retain by adding all referenced
// composite glyphs.
// TODO expand with glyphs reached by G*
//
hb_set_t * all_gids_to_retain = hb_set_create ();
_add_gid_and_children (glyf, 0, all_gids_to_retain);
for (unsigned int i = 0; i < old_gids.len; i++)
_add_gid_and_children (glyf, old_gids[i], all_gids_to_retain);
// Transfer to a sorted list.
old_gids_sorted.alloc (hb_set_get_population (all_gids_to_retain));
hb_codepoint_t gid = HB_SET_VALUE_INVALID;
while (hb_set_next (all_gids_to_retain, &gid))
*(old_gids_sorted.push ()) = gid;
glyf.fini ();
cmap.fini ();
}

View File

@ -38,8 +38,14 @@ struct hb_subset_plan_t {
// TODO(Q1) actual map, drop this crap
// Look at me ma, I'm a poor mans map codepoint : new gid
// codepoints is sorted and aligned with gids_to_retain.
// These first two lists provide a mapping from cp -> gid
// As a result it does not list the full set of glyphs to retain.
hb_prealloced_array_t<hb_codepoint_t> codepoints;
hb_prealloced_array_t<hb_codepoint_t> gids_to_retain;
// This list contains the complete set of glyphs to retain and may contain
// more glyphs then the lists above.
hb_prealloced_array_t<hb_codepoint_t> gids_to_retain_sorted;
// Plan is only good for a specific source/dest so keep them with it

View File

@ -1025,8 +1025,6 @@ retry:
pos->x_advance = x_mult * (int32_t) info->mask;
pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
pos->y_offset = y_mult * info->var2.i32;
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
if (backward)

View File

@ -12,6 +12,8 @@ lib:
EXTRA_DIST += CMakeLists.txt
EXTRA_DIST += fonts
if HAVE_GLIB
AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS)
LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS)
@ -66,25 +68,6 @@ TEST_PROGS += \
$(NULL)
test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
EXTRA_DIST += \
fonts/Inconsolata-Regular.ab.ttf \
fonts/Inconsolata-Regular.abc.ttf \
fonts/Inconsolata-Regular.abc.widerc.ttf \
fonts/Inconsolata-Regular.ac.ttf \
fonts/Inconsolata-Regular.ac.widerc.ttf \
fonts/Roboto-Regular.abc.cmap-format12-only.ttf \
fonts/Roboto-Regular.ac.cmap-format12-only.ttf \
fonts/Roboto-Regular.b.ttf \
fonts/Roboto-Regular.abc.ttf \
fonts/Roboto-Regular.ac.ttf \
fonts/MathTestFontEmpty.otf \
fonts/MathTestFontFull.otf \
fonts/MathTestFontNone.otf \
fonts/MathTestFontPartial1.otf \
fonts/MathTestFontPartial2.otf \
fonts/MathTestFontPartial3.otf \
fonts/MathTestFontPartial4.otf \
$(NULL)
endif # HAVE_FREETYPE
endif # HAVE_OT

Binary file not shown.

Binary file not shown.

View File

@ -52,6 +52,26 @@ test_subset_glyf (void)
hb_face_destroy (face_ac);
}
static void
test_subset_glyf_with_components (void)
{
hb_face_t *face_components = hb_subset_test_open_font ("fonts/Roboto-Regular.components.ttf");
hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Roboto-Regular.components.subset.ttf");
hb_set_t *codepoints = hb_set_create();
hb_set_add (codepoints, 0x1fc);
hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, codepoints);
hb_set_destroy (codepoints);
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('m','a','x', 'p'));
hb_face_destroy (face_generated_subset);
hb_face_destroy (face_subset);
hb_face_destroy (face_components);
}
static void
test_subset_glyf_noop (void)
{
@ -79,6 +99,7 @@ main (int argc, char **argv)
hb_test_init (&argc, &argv);
hb_test_add (test_subset_glyf);
hb_test_add (test_subset_glyf_with_components);
hb_test_add (test_subset_glyf_noop);
return hb_test_run();

View File

@ -37,7 +37,6 @@ static void check_num_hmetrics(hb_face_t *face, uint16_t expected_num_hmetrics)
hb_blob_t *hmtx_blob = hb_face_reference_table (face, HB_TAG ('h','m','t','x'));
// TODO I sure wish I could just use the hmtx table struct!
unsigned int hmtx_len = hb_blob_get_length(hmtx_blob);
unsigned int hhea_len;
uint8_t *raw_hhea = (uint8_t *) hb_blob_get_data(hhea_blob, &hhea_len);
uint16_t num_hmetrics = (raw_hhea[hhea_len - 2] << 8) + raw_hhea[hhea_len - 1];