Merge branch 'master' of https://github.com/harfbuzz/harfbuzz into glyf

This commit is contained in:
Rod Sheeter 2019-05-20 21:29:54 -07:00
commit d1b12a5465
26 changed files with 372 additions and 162 deletions

View File

@ -24,7 +24,14 @@ make distcheck
### Run tests with asan ### Run tests with asan
**NOTE**: this sometimes yields harder to read results than the full fuzzer
```shell ```shell
# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8
# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer
# ex
export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer
./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address ./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address
# make/run tests as usual # make/run tests as usual
``` ```
@ -58,7 +65,11 @@ cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAIL
# push your changs to a branch on googlefonts/harfbuzz # push your changs to a branch on googlefonts/harfbuzz
# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile # In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
# Change the git clone to pull your branch # Change the git clone to pull your branch
# Do this periodically
sudo python infra/helper.py build_image harfbuzz sudo python infra/helper.py build_image harfbuzz
# Do these to update/run
sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
``` ```

View File

@ -2,7 +2,7 @@
from __future__ import print_function, division, absolute_import from __future__ import print_function, division, absolute_import
import io, os.path, sys import io, os.path, sys, re
if len (sys.argv) != 2: if len (sys.argv) != 2:
print ("usage: ./gen-ucd ucdxml-file", file=sys.stderr) print ("usage: ./gen-ucd ucdxml-file", file=sys.stderr)
@ -29,18 +29,68 @@ dm1 = set(v[0] for i,v in dm.items() if len(v) == 1)
dmx = set(v for v in dm.values() if len(v) not in (1,2)) dmx = set(v for v in dm.values() if len(v) not in (1,2))
assert not dmx assert not dmx
print(len(sorted(gc_set))) #print(len(sorted(gc_set)))
print(len(sorted(gc_ccc_non0))) #print(len(sorted(gc_ccc_non0)))
print(len(sorted(gc_bmg_non0))) #print(len(sorted(gc_bmg_non0)))
print("GC, CCC, and BMG fit in one byte. Compress together.") #print("GC, CCC, and BMG fit in one byte. Compress together.")
print() #print()
print(len(sorted(sc_set))) #print(len(sorted(sc_set)))
print("SC fits in one byte. Compress separately.") #print("SC fits in one byte. Compress separately.")
print() #print()
print(len(dm)) #print(len(dm))
print(len(dm1), min(dm1), max(dm1)) #print(len(dm1), min(dm1), max(dm1))
print(len(dm2)) #print(len(dm2))
#print(sorted(dm2diff)) ##print(sorted(dm2diff))
print(len(sorted(set(v // 512 for v in dm1)))) #print(len(sorted(set(v // 512 for v in dm1))))
gc_order = packTab.AutoMapping()
for _ in ('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',):
gc_order[_]
sc_order = packTab.AutoMapping()
sc_array = []
sc_re = re.compile(" (HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
for line in open('hb-common.h'):
m = sc_re.search (line)
if not m: continue
name = m.group(1)
tag = ''.join(m.group(i) for i in range(2, 6))
i = sc_order[tag]
assert i == len(sc_array)
sc_array.append(name)
DEFAULT = 1
COMPACT = 3
print()
print('#include <stdint.h>')
print()
code = packTab.Code('_hb_ucd')
sc_array, _, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
code.print_c(linkage='static inline')
for compression in (DEFAULT, COMPACT):
print()
if compression == DEFAULT:
print('#ifdef HB_OPTIMIZE_SIZE')
else:
print('#else')
print()
code = packTab.Code('_hb_ucd')
packTab.pack_table(gc, 'Cn', mapping=gc_order, compression=compression).genCode(code, 'gc')
packTab.pack_table(ccc, 0, compression=compression).genCode(code, 'ccc')
packTab.pack_table(bmg, 0, compression=compression).genCode(code, 'bmg')
packTab.pack_table(sc, 'Zzzz', mapping=sc_order, compression=compression).genCode(code, 'sc')
code.print_c(linkage='static inline')
if compression != DEFAULT:
print()
print('#endif')
print()

View File

@ -30,7 +30,7 @@
* http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
* https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
*/ */
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) #if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros" #pragma GCC diagnostic ignored "-Wunused-macros"
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L

View File

@ -43,6 +43,9 @@
#ifndef NDEBUG #ifndef NDEBUG
#define NDEBUG #define NDEBUG
#endif #endif
#ifndef __OPTIMIZE_SIZE__
#define __OPTIMIZE_SIZE__
#endif
#endif #endif
#ifdef HB_LEAN #ifdef HB_LEAN
@ -113,6 +116,11 @@
#endif #endif
#endif #endif
#ifdef __OPTIMIZE_SIZE__
#ifndef HB_OPTIMIZE_SIZE
#define HB_OPTIMIZE_SIZE
#endif
#endif
#ifdef HAVE_CONFIG_OVERRIDE_H #ifdef HAVE_CONFIG_OVERRIDE_H
#include "config-override.h" #include "config-override.h"

View File

@ -132,7 +132,7 @@ struct CFFIndex
if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!c->extend_min (*this))) return_trace (false);
this->count = byteArray.length; this->count = byteArray.length;
this->offSize = offSize_; this->offSize = offSize_;
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1)))) if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
return_trace (false); return_trace (false);
/* serialize indices */ /* serialize indices */
@ -277,7 +277,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!c->extend_min (*this))) return_trace (false);
this->count = dataArrayLen; this->count = dataArrayLen;
this->offSize = offSize_; this->offSize = offSize_;
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1)))) if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
return_trace (false); return_trace (false);
/* serialize indices */ /* serialize indices */
@ -479,7 +479,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!c->extend_min (*this))) return_trace (false);
this->count = fontDicts.length; this->count = fontDicts.length;
this->offSize = offSize_; this->offSize = offSize_;
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1)))) if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
return_trace (false); return_trace (false);
/* serialize font dict offsets */ /* serialize font dict offsets */
@ -516,7 +516,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!c->extend_min (*this))) return_trace (false);
this->count = fdCount; this->count = fdCount;
this->offSize = offSize_; this->offSize = offSize_;
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1)))) if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
return_trace (false); return_trace (false);
/* serialize font dict offsets */ /* serialize font dict offsets */

View File

@ -576,7 +576,7 @@ struct CFF1StringIndex : CFF1Index
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
{ {
if (!unlikely (c->extend_min (this->count))) if (unlikely (!c->extend_min (this->count)))
return_trace (false); return_trace (false);
count = 0; count = 0;
return_trace (true); return_trace (true);

View File

@ -186,7 +186,7 @@ struct AxisValue
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (unlikely (c->check_struct (this))) if (unlikely (!c->check_struct (this)))
return_trace (false); return_trace (false);
switch (u.format) switch (u.format)

View File

@ -28,6 +28,7 @@
#define HB_SET_HH #define HB_SET_HH
#include "hb.hh" #include "hb.hh"
#include "hb-machinery.hh"
/* /*
@ -308,7 +309,7 @@ struct hb_set_t
{ {
page->add (g); page->add (g);
array = (const T *) ((const char *) array + stride); array = &StructAtOffsetUnaligned<T> (array, stride);
count--; count--;
} }
while (count && (g = *array, start <= g && g < end)); while (count && (g = *array, start <= g && g < end));

View File

@ -45,11 +45,39 @@ hb_subset_input_create_or_fail ()
input->unicodes = hb_set_create (); input->unicodes = hb_set_create ();
input->glyphs = hb_set_create (); input->glyphs = hb_set_create ();
input->name_ids = hb_set_create (); input->name_ids = hb_set_create ();
input->drop_tables = hb_set_create ();
input->drop_hints = false; input->drop_hints = false;
input->drop_layout = true;
input->desubroutinize = false; input->desubroutinize = false;
input->retain_gids = false; input->retain_gids = false;
hb_tag_t default_drop_tables[] = {
// Layout disabled by default
HB_TAG ('G', 'S', 'U', 'B'),
HB_TAG ('G', 'P', 'O', 'S'),
HB_TAG ('G', 'D', 'E', 'F'),
// Copied from fontTools:
HB_TAG ('B', 'A', 'S', 'E'),
HB_TAG ('J', 'S', 'T', 'F'),
HB_TAG ('D', 'S', 'I', 'G'),
HB_TAG ('E', 'B', 'D', 'T'),
HB_TAG ('E', 'B', 'L', 'C'),
HB_TAG ('E', 'B', 'S', 'C'),
HB_TAG ('S', 'V', 'G', ' '),
HB_TAG ('P', 'C', 'L', 'T'),
HB_TAG ('L', 'T', 'S', 'H'),
// Graphite tables
HB_TAG ('F', 'e', 'a', 't'),
HB_TAG ('G', 'l', 'a', 't'),
HB_TAG ('G', 'l', 'o', 'c'),
HB_TAG ('S', 'i', 'l', 'f'),
HB_TAG ('S', 'i', 'l', 'l'),
// Colour
HB_TAG ('s', 'b', 'i', 'x')
};
input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
return input; return input;
} }
@ -83,6 +111,7 @@ hb_subset_input_destroy (hb_subset_input_t *subset_input)
hb_set_destroy (subset_input->unicodes); hb_set_destroy (subset_input->unicodes);
hb_set_destroy (subset_input->glyphs); hb_set_destroy (subset_input->glyphs);
hb_set_destroy (subset_input->name_ids); hb_set_destroy (subset_input->name_ids);
hb_set_destroy (subset_input->drop_tables);
free (subset_input); free (subset_input);
} }
@ -117,6 +146,12 @@ hb_subset_input_nameid_set (hb_subset_input_t *subset_input)
return subset_input->name_ids; return subset_input->name_ids;
} }
HB_EXTERN hb_set_t *
hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input)
{
return subset_input->drop_tables;
}
HB_EXTERN void HB_EXTERN void
hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
hb_bool_t drop_hints) hb_bool_t drop_hints)
@ -130,19 +165,6 @@ hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input)
return subset_input->drop_hints; return subset_input->drop_hints;
} }
HB_EXTERN void
hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
hb_bool_t drop_layout)
{
subset_input->drop_layout = drop_layout;
}
HB_EXTERN hb_bool_t
hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input)
{
return subset_input->drop_layout;
}
HB_EXTERN void HB_EXTERN void
hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
hb_bool_t desubroutinize) hb_bool_t desubroutinize)

View File

@ -41,11 +41,11 @@ struct hb_subset_input_t
hb_set_t *unicodes; hb_set_t *unicodes;
hb_set_t *glyphs; hb_set_t *glyphs;
hb_set_t *name_ids; hb_set_t *name_ids;
hb_set_t *drop_tables;
bool drop_hints : 1; bool drop_hints;
bool drop_layout : 1; bool desubroutinize;
bool desubroutinize : 1; bool retain_gids;
bool retain_gids : 1;
/* TODO /* TODO
* *
* features * features

View File

@ -236,11 +236,12 @@ hb_subset_plan_create (hb_face_t *face,
hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> (); hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
plan->drop_hints = input->drop_hints; plan->drop_hints = input->drop_hints;
plan->drop_layout = input->drop_layout;
plan->desubroutinize = input->desubroutinize; plan->desubroutinize = input->desubroutinize;
plan->retain_gids = input->retain_gids; plan->retain_gids = input->retain_gids;
plan->unicodes = hb_set_create (); plan->unicodes = hb_set_create ();
plan->name_ids = hb_set_reference (input->name_ids); plan->name_ids = hb_set_reference (input->name_ids);
plan->drop_tables = hb_set_reference (input->drop_tables);
/* TODO Clean this up... */ /* TODO Clean this up... */
if (hb_set_is_empty (plan->name_ids)) if (hb_set_is_empty (plan->name_ids))
hb_set_add_range (plan->name_ids, 0, 0x7FFF); hb_set_add_range (plan->name_ids, 0, 0x7FFF);
@ -253,7 +254,7 @@ hb_subset_plan_create (hb_face_t *face,
plan->_glyphset = _populate_gids_to_retain (face, plan->_glyphset = _populate_gids_to_retain (face,
input->unicodes, input->unicodes,
input->glyphs, input->glyphs,
!plan->drop_layout, !input->drop_tables->has (HB_OT_TAG_GSUB),
plan->unicodes, plan->unicodes,
plan->codepoint_to_glyph); plan->codepoint_to_glyph);
@ -279,6 +280,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_set_destroy (plan->unicodes); hb_set_destroy (plan->unicodes);
hb_set_destroy (plan->name_ids); hb_set_destroy (plan->name_ids);
hb_set_destroy (plan->drop_tables);
hb_face_destroy (plan->source); hb_face_destroy (plan->source);
hb_face_destroy (plan->dest); hb_face_destroy (plan->dest);
hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->codepoint_to_glyph);

View File

@ -40,16 +40,18 @@ struct hb_subset_plan_t
hb_object_header_t header; hb_object_header_t header;
bool drop_hints : 1; bool drop_hints : 1;
bool drop_layout : 1;
bool desubroutinize : 1; bool desubroutinize : 1;
bool retain_gids : 1; bool retain_gids : 1;
// For each cp that we'd like to retain maps to the corresponding gid. // For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes; hb_set_t *unicodes;
//name_ids we would like to retain // name_ids we would like to retain
hb_set_t *name_ids; hb_set_t *name_ids;
// Tables which should be dropped.
hb_set_t *drop_tables;
// The glyph subset // The glyph subset
hb_map_t *codepoint_to_glyph; hb_map_t *codepoint_to_glyph;

View File

@ -236,6 +236,9 @@ _subset_table (hb_subset_plan_t *plan,
static bool static bool
_should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
{ {
if (plan->drop_tables->has (tag))
return true;
switch (tag) { switch (tag) {
case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */ case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */
case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */ case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */
@ -245,35 +248,14 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */ case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
return plan->drop_hints; return plan->drop_hints;
#ifdef HB_NO_SUBSET_LAYOUT
// Drop Layout Tables if requested. // Drop Layout Tables if requested.
case HB_OT_TAG_GDEF: case HB_OT_TAG_GDEF:
case HB_OT_TAG_GPOS: case HB_OT_TAG_GPOS:
case HB_OT_TAG_GSUB: case HB_OT_TAG_GSUB:
#ifdef HB_NO_SUBSET_LAYOUT
return true; return true;
#endif #endif
return plan->drop_layout;
// Drop these tables below by default, list pulled
// from fontTools:
case HB_TAG ('B', 'A', 'S', 'E'):
case HB_TAG ('J', 'S', 'T', 'F'):
case HB_TAG ('D', 'S', 'I', 'G'):
case HB_TAG ('E', 'B', 'D', 'T'):
case HB_TAG ('E', 'B', 'L', 'C'):
case HB_TAG ('E', 'B', 'S', 'C'):
case HB_TAG ('S', 'V', 'G', ' '):
case HB_TAG ('P', 'C', 'L', 'T'):
case HB_TAG ('L', 'T', 'S', 'H'):
// Graphite tables:
case HB_TAG ('F', 'e', 'a', 't'):
case HB_TAG ('G', 'l', 'a', 't'):
case HB_TAG ('G', 'l', 'o', 'c'):
case HB_TAG ('S', 'i', 'l', 'f'):
case HB_TAG ('S', 'i', 'l', 'l'):
// Colour
case HB_TAG ('s', 'b', 'i', 'x'):
return true;
default: default:
return false; return false;
} }

View File

@ -57,18 +57,15 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
HB_EXTERN hb_set_t * HB_EXTERN hb_set_t *
hb_subset_input_nameid_set (hb_subset_input_t *subset_input); hb_subset_input_nameid_set (hb_subset_input_t *subset_input);
HB_EXTERN hb_set_t *
hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input);
HB_EXTERN void HB_EXTERN void
hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
hb_bool_t drop_hints); hb_bool_t drop_hints);
HB_EXTERN hb_bool_t HB_EXTERN hb_bool_t
hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input); hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
HB_EXTERN void
hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
hb_bool_t drop_layout);
HB_EXTERN hb_bool_t
hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input);
HB_EXTERN void HB_EXTERN void
hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
hb_bool_t desubroutinize); hb_bool_t desubroutinize);

View File

@ -42,6 +42,7 @@ TEST_PROGS = \
test-shape \ test-shape \
test-subset \ test-subset \
test-subset-cmap \ test-subset-cmap \
test-subset-drop-tables \
test-subset-glyf \ test-subset-glyf \
test-subset-hdmx \ test-subset-hdmx \
test-subset-hmtx \ test-subset-hmtx \
@ -57,6 +58,7 @@ TEST_PROGS = \
test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_drop_tables_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_glyf_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_glyf_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_hdmx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_hdmx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_hmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_hmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la

View File

@ -0,0 +1,71 @@
/*
* Copyright © 2019 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-test.h"
#include "hb-subset-test.h"
/* Unit tests for hb-subset.cc drop tables functionality */
static void
test_subset_drop_tables (void)
{
hb_face_t *face = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
hb_set_t *codepoints = hb_set_create();
hb_set_add (codepoints, 97);
hb_set_add (codepoints, 99);
hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG ('h', 'd', 'm', 'x'));
hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG ('h', 'm', 't', 'x'));
hb_set_destroy (codepoints);
hb_face_t* subset = hb_subset (face, input);
hb_blob_t *hdmx = hb_face_reference_table (subset, HB_TAG ('h', 'd', 'm', 'x'));
hb_blob_t *hmtx = hb_face_reference_table (subset, HB_TAG ('h', 'm', 't', 'x'));
hb_blob_t *cmap = hb_face_reference_table (subset, HB_TAG ('c', 'm', 'a', 'p'));
g_assert (!hb_blob_get_length (hdmx));
g_assert (!hb_blob_get_length (hmtx));
g_assert ( hb_blob_get_length (cmap));
hb_blob_destroy (hdmx);
hb_blob_destroy (hmtx);
hb_blob_destroy (cmap);
hb_face_destroy (subset);
hb_subset_input_destroy (input);
hb_face_destroy (face);
}
int
main (int argc, char **argv)
{
hb_test_init (&argc, &argv);
hb_test_add (test_subset_drop_tables);
return hb_test_run();
}

View File

@ -137,7 +137,9 @@ test_subset_glyf_with_gsub (void)
input = hb_subset_test_create_input (codepoints); input = hb_subset_test_create_input (codepoints);
hb_set_destroy (codepoints); hb_set_destroy (codepoints);
hb_subset_input_set_drop_layout (input, false); hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'S', 'U', 'B'));
hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'P', 'O', 'S'));
hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'D', 'E', 'F'));
face_subset = hb_subset_test_create_subset (face_fil, input); face_subset = hb_subset_test_create_subset (face_fil, input);
@ -164,7 +166,9 @@ test_subset_glyf_without_gsub (void)
input = hb_subset_test_create_input (codepoints); input = hb_subset_test_create_input (codepoints);
hb_set_destroy (codepoints); hb_set_destroy (codepoints);
hb_subset_input_set_drop_layout (input, true); hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'S', 'U', 'B'));
hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'P', 'O', 'S'));
hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'D', 'E', 'F'));
face_subset = hb_subset_test_create_subset (face_fil, input); face_subset = hb_subset_test_create_subset (face_fil, input);

View File

@ -16,10 +16,16 @@ trySubset (hb_face_t *face,
{ {
hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_subset_input_set_drop_hints (input, drop_hints); hb_subset_input_set_drop_hints (input, drop_hints);
hb_subset_input_set_drop_layout (input, drop_layout);
hb_subset_input_set_retain_gids (input, retain_gids); hb_subset_input_set_retain_gids (input, retain_gids);
hb_set_t *codepoints = hb_subset_input_unicode_set (input); hb_set_t *codepoints = hb_subset_input_unicode_set (input);
if (!drop_layout)
{
hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'S', 'U', 'B'));
hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'P', 'O', 'S'));
hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'D', 'E', 'F'));
}
for (int i = 0; i < text_length; i++) for (int i = 0; i < text_length; i++)
{ {
hb_set_add (codepoints, text[i]); hb_set_add (codepoints, text[i]);

View File

@ -50,8 +50,9 @@ bin_PROGRAMS += hb-shape
hb_subset_SOURCES = $(HB_SUBSET_CLI_sources) hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
hb_subset_LDADD = \ hb_subset_LDADD = \
$(LDADD) \ $(top_builddir)/src/libharfbuzz-subset.la \
$(top_builddir)/src/libharfbuzz-subset.la $(LDADD)
bin_PROGRAMS += hb-subset bin_PROGRAMS += hb-subset
hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources) hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)

View File

@ -32,6 +32,7 @@ HB_OT_SHAPE_CLOSURE_sources = \
HB_SUBSET_CLI_sources = \ HB_SUBSET_CLI_sources = \
hb-subset.cc \ hb-subset.cc \
options.cc \ options.cc \
options-subset.cc \
options.hh \ options.hh \
main-font-text.hh \ main-font-text.hh \
$(NULL) $(NULL)

View File

@ -43,7 +43,7 @@ struct subset_consumer_t
const font_options_t *font_opts) const font_options_t *font_opts)
{ {
font = hb_font_reference (font_opts->get_font ()); font = hb_font_reference (font_opts->get_font ());
input = hb_subset_input_create_or_fail (); input = hb_subset_input_reference (subset_options.input);
} }
void consume_line (const char *text, void consume_line (const char *text,
@ -89,12 +89,6 @@ struct subset_consumer_t
void finish (const font_options_t *font_opts) void finish (const font_options_t *font_opts)
{ {
hb_subset_input_set_drop_layout (input, !subset_options.keep_layout);
hb_subset_input_set_drop_hints (input, subset_options.drop_hints);
hb_subset_input_set_retain_gids (input, subset_options.retain_gids);
hb_subset_input_set_desubroutinize (input, subset_options.desubroutinize);
hb_set_set (hb_subset_input_nameid_set (input), subset_options.name_ids);
hb_face_t *face = hb_font_get_face (font); hb_face_t *face = hb_font_get_face (font);
hb_face_t *new_face = hb_subset (face, input); hb_face_t *new_face = hb_subset (face, input);

127
util/options-subset.cc Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright © 2019 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 "options.hh"
#include "hb-subset-input.hh"
static gboolean
parse_nameids (const char *name G_GNUC_UNUSED,
const char *arg,
gpointer data,
GError **error G_GNUC_UNUSED)
{
subset_options_t *subset_opts = (subset_options_t *) data;
hb_set_t *name_ids = subset_opts->input->name_ids;
hb_set_clear (name_ids);
char *s = (char *) arg;
char *p;
while (s && *s)
{
while (*s && strchr (", ", *s))
s++;
if (!*s)
break;
errno = 0;
hb_codepoint_t u = strtoul (s, &p, 10);
if (errno || s == p)
{
hb_set_destroy (name_ids);
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Failed parsing nameID values at: '%s'", s);
return false;
}
hb_set_add (name_ids, u);
s = p;
}
return true;
}
static gboolean
parse_drop_tables (const char *name,
const char *arg,
gpointer data,
GError **error G_GNUC_UNUSED)
{
subset_options_t *subset_opts = (subset_options_t *) data;
hb_set_t *drop_tables = subset_opts->input->drop_tables;
char last_name_char = name[strlen (name) - 1];
if (last_name_char != '+' && last_name_char != '-')
hb_set_clear (drop_tables);
char *s = strtok((char *) arg, ", ");
while (s)
{
if (strlen (s) > 4) // Table tags are at most 4 bytes.
{
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Failed parsing table tag values at: '%s'", s);
return false;
}
hb_tag_t tag = hb_tag_from_string (s, strlen (s));
if (last_name_char != '-')
hb_set_add (drop_tables, tag);
else
hb_set_del (drop_tables, tag);
s = strtok(NULL, ", ");
}
return true;
}
void
subset_options_t::add_options (option_parser_t *parser)
{
GOptionEntry entries[] =
{
{"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->input->drop_hints, "Whether to drop hints", nullptr},
{"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->input->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr},
{"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->input->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr},
{"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers"},
{"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
{"drop-tables+", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
{"drop-tables-", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
{nullptr}
};
parser->add_group (entries,
"subset",
"Subset options:",
"Options subsetting",
this);
}

View File

@ -31,6 +31,8 @@
#endif #endif
#include <hb-ot.h> #include <hb-ot.h>
#define DELIMITERS "<+>{},;&#\\xXuUnNiI\n\t\v\f\r "
static struct supported_font_funcs_t { static struct supported_font_funcs_t {
char name[4]; char name[4];
void (*func) (hb_font_t *); void (*func) (hb_font_t *);
@ -352,7 +354,7 @@ parse_unicodes (const char *name G_GNUC_UNUSED,
while (s && *s) while (s && *s)
{ {
while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t\v\f\r ", *s)) while (*s && strchr (DELIMITERS, *s))
s++; s++;
if (!*s) if (!*s)
break; break;
@ -970,67 +972,3 @@ 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');
} }
static gboolean
parse_nameids (const char *name G_GNUC_UNUSED,
const char *arg,
gpointer data,
GError **error G_GNUC_UNUSED)
{
subset_options_t *subset_opts = (subset_options_t *) data;
hb_set_t *name_ids = hb_set_create ();
char *s = (char *) arg;
char *p;
while (s && *s)
{
while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t\v\f\r ", *s))
s++;
if (!*s)
break;
errno = 0;
hb_codepoint_t u = strtoul (s, &p, 10);
if (errno || s == p)
{
hb_set_destroy (name_ids);
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Failed parsing nameID values at: '%s'", s);
return false;
}
hb_set_add (name_ids, u);
s = p;
}
hb_set_t *prev = subset_opts->name_ids;
subset_opts->name_ids = hb_set_reference (name_ids);
hb_set_destroy (prev);
hb_set_destroy (name_ids);
return true;
}
void
subset_options_t::add_options (option_parser_t *parser)
{
GOptionEntry entries[] =
{
{"layout", 0, 0, G_OPTION_ARG_NONE, &this->keep_layout, "Keep OpenType Layout tables", nullptr},
{"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr},
{"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr},
{"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr},
{"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers"},
{nullptr}
};
parser->add_group (entries,
"subset",
"Subset options:",
"Options subsetting",
this);
}

View File

@ -28,6 +28,7 @@
#define OPTIONS_HH #define OPTIONS_HH
#include "hb.hh" #include "hb.hh"
#include "hb-subset.h"
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h> #include <stddef.h>
@ -673,28 +674,18 @@ struct subset_options_t : option_group_t
{ {
subset_options_t (option_parser_t *parser) subset_options_t (option_parser_t *parser)
{ {
keep_layout = false; input = hb_subset_input_create_or_fail ();
drop_hints = false;
retain_gids = false;
desubroutinize = false;
name_ids = hb_set_create ();
add_options (parser); add_options (parser);
} }
virtual ~subset_options_t () virtual ~subset_options_t ()
{ {
hb_set_destroy (name_ids); hb_subset_input_destroy (input);
} }
void add_options (option_parser_t *parser); void add_options (option_parser_t *parser);
hb_bool_t keep_layout; hb_subset_input_t *input;
hb_bool_t drop_hints;
hb_bool_t retain_gids;
hb_bool_t desubroutinize;
hb_set_t *name_ids;
}; };
/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */ /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */