Merge pull request #845 from googlefonts/drophints
[subset] drop hints from composites
This commit is contained in:
commit
588a4e0f9b
|
@ -402,17 +402,17 @@ struct glyf
|
||||||
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
|
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
|
||||||
if (num_contours < 0)
|
if (num_contours < 0)
|
||||||
{
|
{
|
||||||
CompositeGlyphHeader::Iterator *composite_it;
|
CompositeGlyphHeader::Iterator composite_it;
|
||||||
if (unlikely (!CompositeGlyphHeader::get_iterator (
|
if (unlikely (!CompositeGlyphHeader::get_iterator (
|
||||||
(const char*) this->glyf_table + start_offset,
|
(const char*) this->glyf_table + start_offset,
|
||||||
end_offset - start_offset, composite_it))) return false;
|
end_offset - start_offset, &composite_it))) return false;
|
||||||
const CompositeGlyphHeader *last;
|
const CompositeGlyphHeader *last;
|
||||||
do {
|
do {
|
||||||
last = composite_it->current;
|
last = composite_it.current;
|
||||||
} while (composite_it->move_to_next());
|
} while (composite_it.move_to_next());
|
||||||
|
|
||||||
if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
|
if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
|
||||||
*instruction_start = start_offset + ((char *) last - (char *) glyf_table->dataX) + last->get_size();
|
*instruction_start = ((char *) last - (char *) glyf_table->dataX) + last->get_size();
|
||||||
else
|
else
|
||||||
*instruction_start = end_offset;
|
*instruction_start = end_offset;
|
||||||
*instruction_end = end_offset;
|
*instruction_end = end_offset;
|
||||||
|
|
|
@ -136,6 +136,20 @@ _update_components (hb_subset_plan_t * plan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _remove_composite_instruction_flag(char *glyf_prime, unsigned int length)
|
||||||
|
{
|
||||||
|
/* remove WE_HAVE_INSTRUCTIONS from flags in dest */
|
||||||
|
OT::glyf::CompositeGlyphHeader::Iterator composite_it;
|
||||||
|
if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime, length, &composite_it))) return false;
|
||||||
|
const OT::glyf::CompositeGlyphHeader *glyph;
|
||||||
|
do {
|
||||||
|
glyph = composite_it.current;
|
||||||
|
OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags);
|
||||||
|
flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS);
|
||||||
|
} while (composite_it.move_to_next());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
_write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
||||||
const OT::glyf::accelerator_t &glyf,
|
const OT::glyf::accelerator_t &glyf,
|
||||||
|
@ -178,9 +192,11 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
||||||
{
|
{
|
||||||
memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset);
|
memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset);
|
||||||
memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end);
|
memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end);
|
||||||
/* if the instructions end at the end this was a composite glyph */
|
/* if the instructions end at the end this was a composite glyph, else simple */
|
||||||
if (instruction_end == end_offset)
|
if (instruction_end == end_offset)
|
||||||
; // TODO(rsheeter) remove WE_HAVE_INSTRUCTIONS from last flags
|
{
|
||||||
|
if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
/* zero instruction length, which is just before instruction_start */
|
/* zero instruction length, which is just before instruction_start */
|
||||||
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
|
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
|
||||||
|
|
Binary file not shown.
|
@ -121,7 +121,7 @@ test_subset_glyf_noop (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_subset_glyf_strip_hints (void)
|
test_subset_glyf_strip_hints_simple (void)
|
||||||
{
|
{
|
||||||
hb_face_t *face_abc = hb_subset_test_open_font ("fonts/Roboto-Regular.abc.ttf");
|
hb_face_t *face_abc = hb_subset_test_open_font ("fonts/Roboto-Regular.abc.ttf");
|
||||||
hb_face_t *face_ac = hb_subset_test_open_font ("fonts/Roboto-Regular.ac.nohints.ttf");
|
hb_face_t *face_ac = hb_subset_test_open_font ("fonts/Roboto-Regular.ac.nohints.ttf");
|
||||||
|
@ -143,7 +143,28 @@ test_subset_glyf_strip_hints (void)
|
||||||
hb_face_destroy (face_ac);
|
hb_face_destroy (face_ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rsheeter): test strip hints from composite
|
static void
|
||||||
|
test_subset_glyf_strip_hints_composite (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.1fc.nohints.ttf");
|
||||||
|
|
||||||
|
hb_set_t *codepoints = hb_set_create();
|
||||||
|
hb_set_add (codepoints, 0x1fc);
|
||||||
|
hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
|
||||||
|
*hb_subset_input_drop_hints(input) = true;
|
||||||
|
|
||||||
|
hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, input);
|
||||||
|
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'));
|
||||||
|
check_maxp_num_glyphs(face_generated_subset, 4, false);
|
||||||
|
|
||||||
|
hb_face_destroy (face_generated_subset);
|
||||||
|
hb_face_destroy (face_subset);
|
||||||
|
hb_face_destroy (face_components);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(grieger): test for long loca generation.
|
// TODO(grieger): test for long loca generation.
|
||||||
|
|
||||||
|
@ -154,7 +175,8 @@ main (int argc, char **argv)
|
||||||
|
|
||||||
hb_test_add (test_subset_glyf_noop);
|
hb_test_add (test_subset_glyf_noop);
|
||||||
hb_test_add (test_subset_glyf);
|
hb_test_add (test_subset_glyf);
|
||||||
hb_test_add (test_subset_glyf_strip_hints);
|
hb_test_add (test_subset_glyf_strip_hints_simple);
|
||||||
|
hb_test_add (test_subset_glyf_strip_hints_composite);
|
||||||
hb_test_add (test_subset_glyf_with_components);
|
hb_test_add (test_subset_glyf_with_components);
|
||||||
|
|
||||||
return hb_test_run();
|
return hb_test_run();
|
||||||
|
|
|
@ -8,6 +8,7 @@ SUBDIRS =
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
$(TESTS) \
|
$(TESTS) \
|
||||||
expected/basics \
|
expected/basics \
|
||||||
|
expected/full-font \
|
||||||
fonts \
|
fonts \
|
||||||
profiles \
|
profiles \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
TESTS = \
|
TESTS = \
|
||||||
tests/basics.tests \
|
tests/basics.tests \
|
||||||
|
tests/full-font.tests \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
XFAIL_TESTS = \
|
XFAIL_TESTS = \
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
--no-hinting
|
|
@ -3,6 +3,11 @@ Roboto-Regular.abc.ttf
|
||||||
|
|
||||||
PROFILES:
|
PROFILES:
|
||||||
default.txt
|
default.txt
|
||||||
|
drop-hints.txt
|
||||||
|
|
||||||
SUBSETS:
|
SUBSETS:
|
||||||
|
abc
|
||||||
b
|
b
|
||||||
|
c
|
||||||
|
ac
|
||||||
|
a
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
FONTS:
|
||||||
|
Roboto-Regular.ttf
|
||||||
|
|
||||||
|
PROFILES:
|
||||||
|
default.txt
|
||||||
|
drop-hints.txt
|
||||||
|
|
||||||
|
SUBSETS:
|
||||||
|
abc
|
||||||
|
Ǽ!A bc
|
||||||
|
|
|
@ -15,12 +15,17 @@ def usage():
|
||||||
print "Usage: generate-expected-outputs.py <test suite file> ..."
|
print "Usage: generate-expected-outputs.py <test suite file> ..."
|
||||||
|
|
||||||
|
|
||||||
def generate_expected_output(input_file, unicodes, output_path):
|
def generate_expected_output(input_file, unicodes, profile_flags, output_path):
|
||||||
check_call(["fonttools", "subset",
|
args = ["fonttools", "subset", input_file]
|
||||||
input_file,
|
args.extend(profile_flags)
|
||||||
"--drop-tables+=DSIG,GPOS,GSUB,GDEF",
|
args.extend(["--notdef-outline",
|
||||||
"--unicodes=%s" % unicodes,
|
"--name-IDs=*",
|
||||||
"--output-file=%s" % output_path])
|
"--name-languages=*",
|
||||||
|
"--name-legacy",
|
||||||
|
"--drop-tables+=DSIG,GPOS,GSUB,GDEF",
|
||||||
|
"--unicodes=%s" % unicodes,
|
||||||
|
"--output-file=%s" % output_path])
|
||||||
|
check_call(args)
|
||||||
|
|
||||||
|
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
|
@ -37,6 +42,6 @@ for path in args:
|
||||||
unicodes = test.unicodes()
|
unicodes = test.unicodes()
|
||||||
font_name = test.get_font_name()
|
font_name = test.get_font_name()
|
||||||
print "Creating subset %s/%s" % (output_directory, font_name)
|
print "Creating subset %s/%s" % (output_directory, font_name)
|
||||||
generate_expected_output(test.font_path, unicodes,
|
generate_expected_output(test.font_path, unicodes, test.get_profile_flags(),
|
||||||
os.path.join(output_directory,
|
os.path.join(output_directory,
|
||||||
font_name))
|
font_name))
|
||||||
|
|
|
@ -44,6 +44,7 @@ def run_test(test):
|
||||||
"--font-file=" + test.font_path,
|
"--font-file=" + test.font_path,
|
||||||
"--output-file=" + out_file,
|
"--output-file=" + out_file,
|
||||||
"--unicodes=%s" % test.unicodes()]
|
"--unicodes=%s" % test.unicodes()]
|
||||||
|
cli_args.extend (test.get_profile_flags())
|
||||||
print (' '.join(cli_args))
|
print (' '.join(cli_args))
|
||||||
_, return_code = cmd(cli_args)
|
_, return_code = cmd(cli_args)
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ def run_ttx(file):
|
||||||
|
|
||||||
def strip_check_sum (ttx_string):
|
def strip_check_sum (ttx_string):
|
||||||
return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
|
return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
|
||||||
'checkSumAdjustment value="0x00000000"',
|
'checkSumAdjustment value="0x00000000"',
|
||||||
ttx_string, count=1)
|
ttx_string, count=1)
|
||||||
|
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# A single test in a subset test suite. Identifies a font
|
# A single test in a subset test suite. Identifies a font
|
||||||
|
@ -13,15 +14,19 @@ class Test:
|
||||||
def unicodes(self):
|
def unicodes(self):
|
||||||
return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
|
return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
|
||||||
|
|
||||||
|
def get_profile_flags(self):
|
||||||
|
with io.open(self.profile_path, mode="r", encoding="utf-8") as f:
|
||||||
|
return f.read().splitlines();
|
||||||
|
|
||||||
def get_font_name(self):
|
def get_font_name(self):
|
||||||
font_base_name = os.path.basename(self.font_path)
|
font_base_name = os.path.basename(self.font_path)
|
||||||
font_base_name_parts = os.path.splitext(font_base_name)
|
font_base_name_parts = os.path.splitext(font_base_name)
|
||||||
profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
|
profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
|
||||||
|
|
||||||
return "%s.%s.%s%s" % (font_base_name_parts[0],
|
return "%s.%s.%s%s" % (font_base_name_parts[0],
|
||||||
profile_name,
|
profile_name,
|
||||||
self.unicodes(),
|
self.unicodes(),
|
||||||
font_base_name_parts[1])
|
font_base_name_parts[1])
|
||||||
|
|
||||||
# A group of tests to perform on the subsetter. Each test
|
# A group of tests to perform on the subsetter. Each test
|
||||||
# Identifies a font a subsetting profile, and a subset to be cut.
|
# Identifies a font a subsetting profile, and a subset to be cut.
|
||||||
|
|
Loading…
Reference in New Issue