commit
4a1d51ef15
|
@ -275,6 +275,91 @@ struct glyf
|
||||||
composite);
|
composite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* based on FontTools _g_l_y_f.py::trim */
|
||||||
|
inline bool remove_padding(unsigned int start_offset,
|
||||||
|
unsigned int *end_offset) const
|
||||||
|
{
|
||||||
|
static const int FLAG_X_SHORT = 0x02;
|
||||||
|
static const int FLAG_Y_SHORT = 0x04;
|
||||||
|
static const int FLAG_REPEAT = 0x08;
|
||||||
|
static const int FLAG_X_SAME = 0x10;
|
||||||
|
static const int FLAG_Y_SAME = 0x20;
|
||||||
|
|
||||||
|
if (*end_offset - start_offset < GlyphHeader::static_size)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const char *glyph = ((const char *) glyf_table) + start_offset;
|
||||||
|
const char * const glyph_end = glyph + (*end_offset - start_offset);
|
||||||
|
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0);
|
||||||
|
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
|
||||||
|
|
||||||
|
if (num_contours < 0)
|
||||||
|
/* Trimming for composites not implemented.
|
||||||
|
* If removing hints it falls out of that. */
|
||||||
|
return true;
|
||||||
|
else if (num_contours > 0)
|
||||||
|
{
|
||||||
|
unsigned int glyph_len = *end_offset - start_offset;
|
||||||
|
/* simple glyph w/contours, possibly trimmable */
|
||||||
|
glyph += GlyphHeader::static_size + 2 * num_contours;
|
||||||
|
|
||||||
|
if (unlikely (glyph + 2 >= glyph_end)) return false;
|
||||||
|
uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1;
|
||||||
|
uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0);
|
||||||
|
|
||||||
|
glyph += 2 + nInstructions;
|
||||||
|
if (unlikely (glyph + 2 >= glyph_end)) return false;
|
||||||
|
|
||||||
|
unsigned int coordBytes = 0;
|
||||||
|
unsigned int coordsWithFlags = 0;
|
||||||
|
while (glyph < glyph_end)
|
||||||
|
{
|
||||||
|
uint8_t flag = (uint8_t) *glyph;
|
||||||
|
glyph++;
|
||||||
|
|
||||||
|
unsigned int repeat = 1;
|
||||||
|
if (flag & FLAG_REPEAT)
|
||||||
|
{
|
||||||
|
if (glyph >= glyph_end)
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Bad flag");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
repeat = ((uint8_t) *glyph) + 1;
|
||||||
|
glyph++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int xBytes, yBytes;
|
||||||
|
xBytes = yBytes = 0;
|
||||||
|
if (flag & FLAG_X_SHORT)
|
||||||
|
xBytes = 1;
|
||||||
|
else if ((flag & FLAG_X_SAME) == 0)
|
||||||
|
xBytes = 2;
|
||||||
|
|
||||||
|
if (flag & FLAG_Y_SHORT)
|
||||||
|
yBytes = 1;
|
||||||
|
else if ((flag & FLAG_Y_SAME) == 0)
|
||||||
|
yBytes = 2;
|
||||||
|
|
||||||
|
coordBytes += (xBytes + yBytes) * repeat;
|
||||||
|
coordsWithFlags += repeat;
|
||||||
|
if (coordsWithFlags >= nCoordinates)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coordsWithFlags != nCoordinates)
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glyph += coordBytes;
|
||||||
|
|
||||||
|
if (glyph < glyph_end)
|
||||||
|
*end_offset -= glyph_end - glyph;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool get_offsets (hb_codepoint_t glyph,
|
inline bool get_offsets (hb_codepoint_t glyph,
|
||||||
unsigned int *start_offset /* OUT */,
|
unsigned int *start_offset /* OUT */,
|
||||||
unsigned int *end_offset /* OUT */) const
|
unsigned int *end_offset /* OUT */) const
|
||||||
|
@ -291,6 +376,7 @@ struct glyf
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataX;
|
const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataX;
|
||||||
|
|
||||||
*start_offset = offsets[glyph];
|
*start_offset = offsets[glyph];
|
||||||
*end_offset = offsets[glyph + 1];
|
*end_offset = offsets[glyph + 1];
|
||||||
}
|
}
|
||||||
|
@ -301,6 +387,51 @@ struct glyf
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool get_instruction_offsets(unsigned int start_offset,
|
||||||
|
unsigned int end_offset,
|
||||||
|
unsigned int *instruction_start /* OUT */,
|
||||||
|
unsigned int *instruction_end /* OUT */) const
|
||||||
|
{
|
||||||
|
if (end_offset - start_offset < GlyphHeader::static_size)
|
||||||
|
{
|
||||||
|
*instruction_start = 0;
|
||||||
|
*instruction_end = 0;
|
||||||
|
return true; /* Empty glyph; no instructions. */
|
||||||
|
}
|
||||||
|
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
|
||||||
|
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
|
||||||
|
if (num_contours < 0)
|
||||||
|
{
|
||||||
|
CompositeGlyphHeader::Iterator *composite_it;
|
||||||
|
if (unlikely (!CompositeGlyphHeader::get_iterator (
|
||||||
|
(const char*) this->glyf_table + start_offset,
|
||||||
|
end_offset - start_offset, composite_it))) return false;
|
||||||
|
const CompositeGlyphHeader *last;
|
||||||
|
do {
|
||||||
|
last = composite_it->current;
|
||||||
|
} while (composite_it->move_to_next());
|
||||||
|
|
||||||
|
if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
|
||||||
|
*instruction_start = start_offset + ((char *) last - (char *) glyf_table->dataX) + last->get_size();
|
||||||
|
else
|
||||||
|
*instruction_start = end_offset;
|
||||||
|
*instruction_end = end_offset;
|
||||||
|
if (unlikely (*instruction_start > *instruction_end))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
|
||||||
|
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
|
||||||
|
*instruction_start = instruction_length_offset + 2;
|
||||||
|
*instruction_end = *instruction_start + (uint16_t) instruction_length;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool get_extents (hb_codepoint_t glyph,
|
inline bool get_extents (hb_codepoint_t glyph,
|
||||||
hb_glyph_extents_t *extents) const
|
hb_glyph_extents_t *extents) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
*
|
*
|
||||||
* Google Author(s): Garret Rieger
|
* Google Author(s): Garret Rieger, Roderick Sheeter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hb-open-type-private.hh"
|
#include "hb-open-type-private.hh"
|
||||||
|
@ -33,26 +33,49 @@
|
||||||
static bool
|
static bool
|
||||||
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
|
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
|
||||||
hb_prealloced_array_t<hb_codepoint_t> &glyph_ids,
|
hb_prealloced_array_t<hb_codepoint_t> &glyph_ids,
|
||||||
bool *use_short_loca, /* OUT */
|
hb_bool_t drop_hints,
|
||||||
unsigned int *glyf_size, /* OUT */
|
bool *use_short_loca /* OUT */,
|
||||||
unsigned int *loca_size /* OUT */)
|
unsigned int *glyf_size /* OUT */,
|
||||||
|
unsigned int *loca_size /* OUT */,
|
||||||
|
hb_prealloced_array_t<unsigned int> *instruction_ranges /* OUT */)
|
||||||
{
|
{
|
||||||
unsigned int total = 0;
|
unsigned int total = 0;
|
||||||
unsigned int count = 0;
|
|
||||||
for (unsigned int i = 0; i < glyph_ids.len; i++)
|
for (unsigned int i = 0; i < glyph_ids.len; i++)
|
||||||
{
|
{
|
||||||
hb_codepoint_t next_glyph = glyph_ids[i];
|
hb_codepoint_t next_glyph = glyph_ids[i];
|
||||||
unsigned int start_offset, end_offset;
|
unsigned int *instruction_start = instruction_ranges->push();
|
||||||
if (unlikely (!glyf.get_offsets (next_glyph, &start_offset, &end_offset)))
|
unsigned int *instruction_end = instruction_ranges->push();
|
||||||
end_offset = start_offset = 0;
|
*instruction_start = 0;
|
||||||
|
*instruction_end = 0;
|
||||||
|
|
||||||
total += end_offset - start_offset;
|
unsigned int start_offset, end_offset;
|
||||||
count++;
|
if (unlikely (!(glyf.get_offsets(next_glyph, &start_offset, &end_offset)
|
||||||
|
&& glyf.remove_padding(start_offset, &end_offset))))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (end_offset - start_offset < OT::glyf::GlyphHeader::static_size)
|
||||||
|
continue; /* 0-length glyph */
|
||||||
|
|
||||||
|
if (drop_hints)
|
||||||
|
{
|
||||||
|
if (unlikely (!glyf.get_instruction_offsets(start_offset, end_offset,
|
||||||
|
instruction_start, instruction_end)))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total += end_offset - start_offset - (*instruction_end - *instruction_start);
|
||||||
|
/* round2 so short loca will work */
|
||||||
|
total += total % 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
*glyf_size = total;
|
*glyf_size = total;
|
||||||
*use_short_loca = (total <= 131070);
|
*use_short_loca = (total <= 131070);
|
||||||
*loca_size = (count + 1)
|
*loca_size = (glyph_ids.len + 1)
|
||||||
* (*use_short_loca ? sizeof(OT::HBUINT16) : sizeof(OT::HBUINT32));
|
* (*use_short_loca ? sizeof(OT::HBUINT16) : sizeof(OT::HBUINT32));
|
||||||
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
|
DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
|
||||||
|
@ -118,6 +141,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
||||||
const OT::glyf::accelerator_t &glyf,
|
const OT::glyf::accelerator_t &glyf,
|
||||||
const char *glyf_data,
|
const char *glyf_data,
|
||||||
bool use_short_loca,
|
bool use_short_loca,
|
||||||
|
hb_prealloced_array_t<unsigned int> &instruction_ranges,
|
||||||
unsigned int glyf_prime_size,
|
unsigned int glyf_prime_size,
|
||||||
char *glyf_prime_data /* OUT */,
|
char *glyf_prime_data /* OUT */,
|
||||||
unsigned int loca_prime_size,
|
unsigned int loca_prime_size,
|
||||||
|
@ -130,27 +154,44 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
||||||
for (unsigned int i = 0; i < glyph_ids.len; i++)
|
for (unsigned int i = 0; i < glyph_ids.len; i++)
|
||||||
{
|
{
|
||||||
unsigned int start_offset, end_offset;
|
unsigned int start_offset, end_offset;
|
||||||
if (unlikely (!glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset)))
|
if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset)
|
||||||
|
&& glyf.remove_padding(start_offset, &end_offset))))
|
||||||
end_offset = start_offset = 0;
|
end_offset = start_offset = 0;
|
||||||
|
unsigned int instruction_start = instruction_ranges[i * 2];
|
||||||
|
unsigned int instruction_end = instruction_ranges[i * 2 + 1];
|
||||||
|
|
||||||
int length = end_offset - start_offset;
|
int length = end_offset - start_offset - (instruction_end - instruction_start);
|
||||||
|
length += length % 2;
|
||||||
|
|
||||||
if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size)
|
if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size)
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET,
|
DEBUG_MSG (SUBSET,
|
||||||
nullptr,
|
nullptr,
|
||||||
"WARNING: Attempted to write an out of bounds glyph entry for gid %d",
|
"WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)",
|
||||||
i);
|
i, length);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
|
|
||||||
|
if (instruction_start == instruction_end)
|
||||||
|
memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
/* if the instructions end at the end this was a composite glyph */
|
||||||
|
if (instruction_end == end_offset)
|
||||||
|
; // TODO(rsheeter) remove WE_HAVE_INSTRUCTIONS from last flags
|
||||||
|
else
|
||||||
|
/* zero instruction length, which is just before instruction_start */
|
||||||
|
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
success = success && _write_loca_entry (i,
|
success = success && _write_loca_entry (i,
|
||||||
glyf_prime_data_next - glyf_prime_data,
|
glyf_prime_data_next - glyf_prime_data,
|
||||||
use_short_loca,
|
use_short_loca,
|
||||||
loca_prime_data,
|
loca_prime_data,
|
||||||
loca_prime_size);
|
loca_prime_size);
|
||||||
_update_components (plan, glyf_prime_data_next, end_offset - start_offset);
|
_update_components (plan, glyf_prime_data_next, length);
|
||||||
|
|
||||||
glyf_prime_data_next += length;
|
glyf_prime_data_next += length;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +207,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
||||||
static bool
|
static bool
|
||||||
_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
|
_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
|
||||||
const char *glyf_data,
|
const char *glyf_data,
|
||||||
hb_subset_plan_t *plan,
|
hb_subset_plan_t *plan,
|
||||||
bool *use_short_loca,
|
bool *use_short_loca,
|
||||||
hb_blob_t **glyf_prime /* OUT */,
|
hb_blob_t **glyf_prime /* OUT */,
|
||||||
hb_blob_t **loca_prime /* OUT */)
|
hb_blob_t **loca_prime /* OUT */)
|
||||||
|
@ -176,25 +217,33 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
|
||||||
|
|
||||||
unsigned int glyf_prime_size;
|
unsigned int glyf_prime_size;
|
||||||
unsigned int loca_prime_size;
|
unsigned int loca_prime_size;
|
||||||
|
hb_prealloced_array_t<unsigned int> instruction_ranges;
|
||||||
|
instruction_ranges.init();
|
||||||
|
|
||||||
if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
|
if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
|
||||||
glyphs_to_retain,
|
glyphs_to_retain,
|
||||||
|
plan->drop_hints,
|
||||||
use_short_loca,
|
use_short_loca,
|
||||||
&glyf_prime_size,
|
&glyf_prime_size,
|
||||||
&loca_prime_size))) {
|
&loca_prime_size,
|
||||||
|
&instruction_ranges))) {
|
||||||
|
instruction_ranges.finish();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *glyf_prime_data = (char *) malloc (glyf_prime_size);
|
char *glyf_prime_data = (char *) calloc (1, glyf_prime_size);
|
||||||
char *loca_prime_data = (char *) malloc (loca_prime_size);
|
char *loca_prime_data = (char *) calloc (1, loca_prime_size);
|
||||||
if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
|
if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
|
||||||
*use_short_loca,
|
*use_short_loca,
|
||||||
|
instruction_ranges,
|
||||||
glyf_prime_size, glyf_prime_data,
|
glyf_prime_size, glyf_prime_data,
|
||||||
loca_prime_size, loca_prime_data))) {
|
loca_prime_size, loca_prime_data))) {
|
||||||
free (glyf_prime_data);
|
free (glyf_prime_data);
|
||||||
free (loca_prime_data);
|
free (loca_prime_data);
|
||||||
|
instruction_ranges.finish();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
instruction_ranges.finish();
|
||||||
|
|
||||||
*glyf_prime = hb_blob_create (glyf_prime_data,
|
*glyf_prime = hb_blob_create (glyf_prime_data,
|
||||||
glyf_prime_size,
|
glyf_prime_size,
|
||||||
|
|
|
@ -53,9 +53,9 @@ hb_subset_input_create_or_fail (void)
|
||||||
* hb_subset_input_reference: (skip)
|
* hb_subset_input_reference: (skip)
|
||||||
* @subset_input: a subset_input.
|
* @subset_input: a subset_input.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* Return value:
|
*
|
||||||
|
* Return value:
|
||||||
*
|
*
|
||||||
* Since: 1.8.0
|
* Since: 1.8.0
|
||||||
**/
|
**/
|
||||||
|
@ -105,3 +105,15 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input)
|
||||||
{
|
{
|
||||||
return subset_input->glyphs;
|
return subset_input->glyphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_subset_input_drop_hints:
|
||||||
|
* @subset_input: a subset_input.
|
||||||
|
*
|
||||||
|
* Since: 1.8.0
|
||||||
|
**/
|
||||||
|
HB_EXTERN hb_bool_t *
|
||||||
|
hb_subset_input_drop_hints (hb_subset_input_t *subset_input)
|
||||||
|
{
|
||||||
|
return &subset_input->drop_hints;
|
||||||
|
}
|
||||||
|
|
|
@ -79,6 +79,9 @@ hb_subset_plan_add_table (hb_subset_plan_t *plan,
|
||||||
hb_tag_t tag,
|
hb_tag_t tag,
|
||||||
hb_blob_t *contents)
|
hb_blob_t *contents)
|
||||||
{
|
{
|
||||||
|
hb_blob_t *source_blob = plan->source->reference_table (tag);
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes", HB_UNTAG(tag), hb_blob_get_length (contents), hb_blob_get_length (source_blob));
|
||||||
|
hb_blob_destroy (source_blob);
|
||||||
return hb_subset_face_add_table(plan->dest, tag, contents);
|
return hb_subset_face_add_table(plan->dest, tag, contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +195,7 @@ hb_subset_plan_create (hb_face_t *face,
|
||||||
plan->gids_to_retain_sorted.init();
|
plan->gids_to_retain_sorted.init();
|
||||||
plan->source = hb_face_reference (face);
|
plan->source = hb_face_reference (face);
|
||||||
plan->dest = hb_subset_face_create ();
|
plan->dest = hb_subset_face_create ();
|
||||||
|
plan->drop_hints = input->drop_hints;
|
||||||
|
|
||||||
_populate_codepoints (input->unicodes, plan->codepoints);
|
_populate_codepoints (input->unicodes, plan->codepoints);
|
||||||
_populate_gids_to_retain (face,
|
_populate_gids_to_retain (face,
|
||||||
|
|
|
@ -37,6 +37,8 @@ struct hb_subset_plan_t {
|
||||||
hb_object_header_t header;
|
hb_object_header_t header;
|
||||||
ASSERT_POD ();
|
ASSERT_POD ();
|
||||||
|
|
||||||
|
hb_bool_t drop_hints;
|
||||||
|
|
||||||
// TODO(Q1) actual map, drop this crap
|
// TODO(Q1) actual map, drop this crap
|
||||||
// Look at me ma, I'm a poor mans map codepoint : new gid
|
// Look at me ma, I'm a poor mans map codepoint : new gid
|
||||||
// codepoints is sorted and aligned with gids_to_retain.
|
// codepoints is sorted and aligned with gids_to_retain.
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct hb_subset_input_t {
|
||||||
hb_set_t *unicodes;
|
hb_set_t *unicodes;
|
||||||
hb_set_t *glyphs;
|
hb_set_t *glyphs;
|
||||||
|
|
||||||
|
hb_bool_t drop_hints;
|
||||||
/* TODO
|
/* TODO
|
||||||
*
|
*
|
||||||
* features
|
* features
|
||||||
|
|
|
@ -242,11 +242,12 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
result = _subset<const OT::hdmx> (plan);
|
result = _subset<const OT::hdmx> (plan);
|
||||||
break;
|
break;
|
||||||
case HB_OT_TAG_head:
|
case HB_OT_TAG_head:
|
||||||
// SKIP head, it's handled by glyf
|
// TODO that won't work well if there is no glyf
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf");
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
case HB_OT_TAG_hhea:
|
case HB_OT_TAG_hhea:
|
||||||
// SKIP hhea, it's handled by hmtx
|
DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx");
|
||||||
return true;
|
return true;
|
||||||
case HB_OT_TAG_hmtx:
|
case HB_OT_TAG_hmtx:
|
||||||
result = _subset<const OT::hmtx> (plan);
|
result = _subset<const OT::hmtx> (plan);
|
||||||
|
@ -255,7 +256,7 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
result = _subset<const OT::maxp> (plan);
|
result = _subset<const OT::maxp> (plan);
|
||||||
break;
|
break;
|
||||||
case HB_OT_TAG_loca:
|
case HB_OT_TAG_loca:
|
||||||
// SKIP loca, it's handle by glyf
|
DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf");
|
||||||
return true;
|
return true;
|
||||||
case HB_OT_TAG_cmap:
|
case HB_OT_TAG_cmap:
|
||||||
result = _subset<const OT::cmap> (plan);
|
result = _subset<const OT::cmap> (plan);
|
||||||
|
@ -277,9 +278,16 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_should_drop_table(hb_tag_t tag)
|
_should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
|
||||||
{
|
{
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
|
case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */
|
||||||
|
case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */
|
||||||
|
case HB_TAG ('f', 'p', 'g', 'm'): /* hint table, fallthrough */
|
||||||
|
case HB_TAG ('p', 'r', 'e', 'p'): /* hint table, fallthrough */
|
||||||
|
case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */
|
||||||
|
case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
|
||||||
|
return plan->drop_hints;
|
||||||
case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */
|
case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */
|
||||||
case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */
|
case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */
|
||||||
case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */
|
case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */
|
||||||
|
@ -316,7 +324,7 @@ hb_subset (hb_face_t *source,
|
||||||
for (unsigned int i = 0; i < count; i++)
|
for (unsigned int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
hb_tag_t tag = table_tags[i];
|
hb_tag_t tag = table_tags[i];
|
||||||
if (_should_drop_table(tag))
|
if (_should_drop_table(plan, tag))
|
||||||
{
|
{
|
||||||
DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG(tag));
|
DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG(tag));
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -68,6 +68,8 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input);
|
||||||
HB_EXTERN hb_set_t *
|
HB_EXTERN hb_set_t *
|
||||||
hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
|
hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
|
||||||
|
|
||||||
|
HB_EXTERN hb_bool_t *
|
||||||
|
hb_subset_input_drop_hints (hb_subset_input_t *subset_input);
|
||||||
|
|
||||||
/* hb_subset() */
|
/* hb_subset() */
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -95,17 +95,20 @@ hb_subset_test_open_font (const char *font_path)
|
||||||
return NULL; /* Shut up, compiler! */
|
return NULL; /* Shut up, compiler! */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline hb_subset_input_t *
|
||||||
|
hb_subset_test_create_input(const hb_set_t *codepoints)
|
||||||
|
{
|
||||||
|
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
|
||||||
|
hb_set_t * input_codepoints = hb_subset_input_unicode_set (input);
|
||||||
|
hb_set_union (input_codepoints, codepoints);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
static inline hb_face_t *
|
static inline hb_face_t *
|
||||||
hb_subset_test_create_subset (hb_face_t *source,
|
hb_subset_test_create_subset (hb_face_t *source,
|
||||||
const hb_set_t *codepoints)
|
hb_subset_input_t *input)
|
||||||
{
|
{
|
||||||
hb_subset_profile_t *profile = hb_subset_profile_create();
|
hb_subset_profile_t *profile = hb_subset_profile_create();
|
||||||
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
|
|
||||||
|
|
||||||
hb_set_t * input_codepoints = hb_subset_input_unicode_set (input);
|
|
||||||
|
|
||||||
hb_set_union (input_codepoints, codepoints);
|
|
||||||
|
|
||||||
hb_face_t *subset = hb_subset (source, profile, input);
|
hb_face_t *subset = hb_subset (source, profile, input);
|
||||||
g_assert (subset);
|
g_assert (subset);
|
||||||
|
|
||||||
|
@ -119,6 +122,7 @@ hb_subset_test_check (hb_face_t *expected,
|
||||||
hb_face_t *actual,
|
hb_face_t *actual,
|
||||||
hb_tag_t table)
|
hb_tag_t table)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "compare %c%c%c%c\n", HB_UNTAG(table));
|
||||||
hb_blob_t *expected_blob = hb_face_reference_table (expected, table);
|
hb_blob_t *expected_blob = hb_face_reference_table (expected, table);
|
||||||
hb_blob_t *actual_blob = hb_face_reference_table (actual, table);
|
hb_blob_t *actual_blob = hb_face_reference_table (actual, table);
|
||||||
hb_test_assert_blobs_equal (expected_blob, actual_blob);
|
hb_test_assert_blobs_equal (expected_blob, actual_blob);
|
||||||
|
|
|
@ -40,7 +40,7 @@ test_subset_cmap (void)
|
||||||
hb_set_t *codepoints = hb_set_create ();
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
hb_set_add (codepoints, 97);
|
hb_set_add (codepoints, 97);
|
||||||
hb_set_add (codepoints, 99);
|
hb_set_add (codepoints, 99);
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('c','m','a','p'));
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('c','m','a','p'));
|
||||||
|
@ -59,7 +59,7 @@ test_subset_cmap_noop (void)
|
||||||
hb_set_add (codepoints, 97);
|
hb_set_add (codepoints, 97);
|
||||||
hb_set_add (codepoints, 98);
|
hb_set_add (codepoints, 98);
|
||||||
hb_set_add (codepoints, 99);
|
hb_set_add (codepoints, 99);
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('c','m','a','p'));
|
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('c','m','a','p'));
|
||||||
|
|
|
@ -31,6 +31,18 @@
|
||||||
|
|
||||||
/* Unit tests for hb-subset-glyf.h */
|
/* Unit tests for hb-subset-glyf.h */
|
||||||
|
|
||||||
|
static void check_maxp_num_glyphs (hb_face_t *face, uint16_t expected_num_glyphs)
|
||||||
|
{
|
||||||
|
hb_blob_t *maxp_blob = hb_face_reference_table (face, HB_TAG ('m','a','x', 'p'));
|
||||||
|
|
||||||
|
unsigned int maxp_len;
|
||||||
|
uint8_t *raw_maxp = (uint8_t *) hb_blob_get_data(maxp_blob, &maxp_len);
|
||||||
|
uint16_t num_glyphs = (raw_maxp[4] << 8) + raw_maxp[5];
|
||||||
|
g_assert_cmpuint(expected_num_glyphs, ==, num_glyphs);
|
||||||
|
|
||||||
|
hb_blob_destroy (maxp_blob);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_subset_glyf (void)
|
test_subset_glyf (void)
|
||||||
{
|
{
|
||||||
|
@ -40,12 +52,12 @@ test_subset_glyf (void)
|
||||||
hb_set_t *codepoints = hb_set_create();
|
hb_set_t *codepoints = hb_set_create();
|
||||||
hb_set_add (codepoints, 97);
|
hb_set_add (codepoints, 97);
|
||||||
hb_set_add (codepoints, 99);
|
hb_set_add (codepoints, 99);
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
|
||||||
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('m','a','x', 'p'));
|
check_maxp_num_glyphs(face_abc_subset, 3);
|
||||||
|
|
||||||
hb_face_destroy (face_abc_subset);
|
hb_face_destroy (face_abc_subset);
|
||||||
hb_face_destroy (face_abc);
|
hb_face_destroy (face_abc);
|
||||||
|
@ -60,12 +72,12 @@ test_subset_glyf_with_components (void)
|
||||||
|
|
||||||
hb_set_t *codepoints = hb_set_create();
|
hb_set_t *codepoints = hb_set_create();
|
||||||
hb_set_add (codepoints, 0x1fc);
|
hb_set_add (codepoints, 0x1fc);
|
||||||
hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, codepoints);
|
hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (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 ('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 ('l','o','c', 'a'));
|
||||||
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('m','a','x', 'p'));
|
check_maxp_num_glyphs(face_generated_subset, 4);
|
||||||
|
|
||||||
hb_face_destroy (face_generated_subset);
|
hb_face_destroy (face_generated_subset);
|
||||||
hb_face_destroy (face_subset);
|
hb_face_destroy (face_subset);
|
||||||
|
@ -81,16 +93,42 @@ test_subset_glyf_noop (void)
|
||||||
hb_set_add (codepoints, 97);
|
hb_set_add (codepoints, 97);
|
||||||
hb_set_add (codepoints, 98);
|
hb_set_add (codepoints, 98);
|
||||||
hb_set_add (codepoints, 99);
|
hb_set_add (codepoints, 99);
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
|
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
|
||||||
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
|
check_maxp_num_glyphs(face_abc_subset, 4);
|
||||||
|
|
||||||
hb_face_destroy (face_abc_subset);
|
hb_face_destroy (face_abc_subset);
|
||||||
hb_face_destroy (face_abc);
|
hb_face_destroy (face_abc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_subset_glyf_strip_hints (void)
|
||||||
|
{
|
||||||
|
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_set_t *codepoints = hb_set_create();
|
||||||
|
hb_set_add (codepoints, 'a');
|
||||||
|
hb_set_add (codepoints, 'c');
|
||||||
|
hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
|
||||||
|
*hb_subset_input_drop_hints(input) = true;
|
||||||
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
||||||
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
|
||||||
|
check_maxp_num_glyphs(face_abc_subset, 3);
|
||||||
|
|
||||||
|
hb_face_destroy (face_abc_subset);
|
||||||
|
hb_face_destroy (face_abc);
|
||||||
|
hb_face_destroy (face_ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(rsheeter): test strip hints from composite
|
||||||
|
|
||||||
// TODO(grieger): test for long loca generation.
|
// TODO(grieger): test for long loca generation.
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -98,9 +136,10 @@ main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
hb_test_init (&argc, &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);
|
hb_test_add (test_subset_glyf_noop);
|
||||||
|
hb_test_add (test_subset_glyf);
|
||||||
|
hb_test_add (test_subset_glyf_strip_hints);
|
||||||
|
hb_test_add (test_subset_glyf_with_components);
|
||||||
|
|
||||||
return hb_test_run();
|
return hb_test_run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ test_subset_hdmx_simple_subset (void)
|
||||||
hb_set_t *codepoints = hb_set_create ();
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'c');
|
hb_set_add (codepoints, 'c');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('h','d','m','x'));
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('h','d','m','x'));
|
||||||
|
@ -60,7 +60,7 @@ test_subset_hdmx_noop (void)
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'b');
|
hb_set_add (codepoints, 'b');
|
||||||
hb_set_add (codepoints, 'c');
|
hb_set_add (codepoints, 'c');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('h','d','m','x'));
|
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('h','d','m','x'));
|
||||||
|
|
|
@ -55,7 +55,7 @@ test_subset_hmtx_simple_subset (void)
|
||||||
hb_set_t *codepoints = hb_set_create ();
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'c');
|
hb_set_add (codepoints, 'c');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
check_num_hmetrics(face_abc_subset, 3); /* nothing has same width */
|
check_num_hmetrics(face_abc_subset, 3); /* nothing has same width */
|
||||||
|
@ -76,7 +76,7 @@ test_subset_hmtx_monospace (void)
|
||||||
hb_set_t *codepoints = hb_set_create ();
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'c');
|
hb_set_add (codepoints, 'c');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
check_num_hmetrics(face_abc_subset, 1); /* everything has same width */
|
check_num_hmetrics(face_abc_subset, 1); /* everything has same width */
|
||||||
|
@ -97,7 +97,7 @@ test_subset_hmtx_keep_num_metrics (void)
|
||||||
hb_set_t *codepoints = hb_set_create ();
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'c');
|
hb_set_add (codepoints, 'c');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
check_num_hmetrics(face_abc_subset, 3); /* c is wider */
|
check_num_hmetrics(face_abc_subset, 3); /* c is wider */
|
||||||
|
@ -117,7 +117,7 @@ test_subset_hmtx_decrease_num_metrics (void)
|
||||||
hb_set_t *codepoints = hb_set_create ();
|
hb_set_t *codepoints = hb_set_create ();
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'b');
|
hb_set_add (codepoints, 'b');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
check_num_hmetrics(face_abc_subset, 1); /* everything left has same width */
|
check_num_hmetrics(face_abc_subset, 1); /* everything left has same width */
|
||||||
|
@ -137,7 +137,7 @@ test_subset_hmtx_noop (void)
|
||||||
hb_set_add (codepoints, 'a');
|
hb_set_add (codepoints, 'a');
|
||||||
hb_set_add (codepoints, 'b');
|
hb_set_add (codepoints, 'b');
|
||||||
hb_set_add (codepoints, 'c');
|
hb_set_add (codepoints, 'c');
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
check_num_hmetrics(face_abc_subset, 4); /* nothing has same width */
|
check_num_hmetrics(face_abc_subset, 4); /* nothing has same width */
|
||||||
|
|
|
@ -37,7 +37,7 @@ test_subset_os2 (void)
|
||||||
|
|
||||||
hb_set_t *codepoints = hb_set_create();
|
hb_set_t *codepoints = hb_set_create();
|
||||||
hb_set_add (codepoints, 98);
|
hb_set_add (codepoints, 98);
|
||||||
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, codepoints);
|
hb_face_t *face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_b, face_abc_subset, HB_TAG ('O','S','/','2'));
|
hb_subset_test_check (face_b, face_abc_subset, HB_TAG ('O','S','/','2'));
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include "main-font-text.hh"
|
#include "main-font-text.hh"
|
||||||
#include "hb-subset.h"
|
#include "hb-subset.h"
|
||||||
|
#include "hb-subset-private.hh"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Command line interface to the harfbuzz font subsetter.
|
* Command line interface to the harfbuzz font subsetter.
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
struct subset_consumer_t
|
struct subset_consumer_t
|
||||||
{
|
{
|
||||||
subset_consumer_t (option_parser_t *parser)
|
subset_consumer_t (option_parser_t *parser)
|
||||||
: failed (false), options (parser), font (nullptr), input (nullptr) {}
|
: failed (false), options (parser), subset_options (parser), font (nullptr), input (nullptr) {}
|
||||||
|
|
||||||
void init (hb_buffer_t *buffer_,
|
void init (hb_buffer_t *buffer_,
|
||||||
const font_options_t *font_opts)
|
const font_options_t *font_opts)
|
||||||
|
@ -89,6 +90,8 @@ struct subset_consumer_t
|
||||||
|
|
||||||
void finish (const font_options_t *font_opts)
|
void finish (const font_options_t *font_opts)
|
||||||
{
|
{
|
||||||
|
input->drop_hints = subset_options.drop_hints;
|
||||||
|
|
||||||
hb_subset_profile_t *subset_profile = hb_subset_profile_create();
|
hb_subset_profile_t *subset_profile = hb_subset_profile_create();
|
||||||
hb_face_t *face = hb_font_get_face (font);
|
hb_face_t *face = hb_font_get_face (font);
|
||||||
|
|
||||||
|
@ -111,6 +114,7 @@ struct subset_consumer_t
|
||||||
|
|
||||||
private:
|
private:
|
||||||
output_options_t options;
|
output_options_t options;
|
||||||
|
subset_options_t subset_options;
|
||||||
hb_font_t *font;
|
hb_font_t *font;
|
||||||
hb_subset_input_t *input;
|
hb_subset_input_t *input;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1009,3 +1009,18 @@ format_options_t::serialize_buffer_of_glyphs (hb_buffer_t *buffer,
|
||||||
serialize_glyphs (buffer, font, output_format, format_flags, gs);
|
serialize_glyphs (buffer, font, output_format, format_flags, gs);
|
||||||
g_string_append_c (gs, '\n');
|
g_string_append_c (gs, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
subset_options_t::add_options (option_parser_t *parser)
|
||||||
|
{
|
||||||
|
GOptionEntry entries[] =
|
||||||
|
{
|
||||||
|
{"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr},
|
||||||
|
{nullptr}
|
||||||
|
};
|
||||||
|
parser->add_group (entries,
|
||||||
|
"subset",
|
||||||
|
"Subset options:",
|
||||||
|
"Options subsetting",
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
|
@ -655,6 +655,20 @@ struct format_options_t : option_group_t
|
||||||
hb_bool_t trace;
|
hb_bool_t trace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct subset_options_t : option_group_t
|
||||||
|
{
|
||||||
|
subset_options_t (option_parser_t *parser)
|
||||||
|
{
|
||||||
|
drop_hints = false;
|
||||||
|
|
||||||
|
add_options (parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_options (option_parser_t *parser);
|
||||||
|
|
||||||
|
hb_bool_t drop_hints;
|
||||||
|
};
|
||||||
|
|
||||||
/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
|
/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
|
||||||
#if defined (_MSC_VER) && (_MSC_VER < 1800)
|
#if defined (_MSC_VER) && (_MSC_VER < 1800)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue