Merge branch 'master' of https://github.com/harfbuzz/harfbuzz into glyf
This commit is contained in:
commit
d1b12a5465
11
TESTING.md
11
TESTING.md
@ -24,7 +24,14 @@ make distcheck
|
||||
|
||||
### Run tests with asan
|
||||
|
||||
**NOTE**: this sometimes yields harder to read results than the full fuzzer
|
||||
|
||||
```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
|
||||
# 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
|
||||
# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
|
||||
# Change the git clone to pull your branch
|
||||
|
||||
# Do this periodically
|
||||
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 run_fuzzer harfbuzz hb-subset-fuzzer
|
||||
```
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
|
||||
import io, os.path, sys
|
||||
import io, os.path, sys, re
|
||||
|
||||
if len (sys.argv) != 2:
|
||||
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))
|
||||
assert not dmx
|
||||
|
||||
print(len(sorted(gc_set)))
|
||||
print(len(sorted(gc_ccc_non0)))
|
||||
print(len(sorted(gc_bmg_non0)))
|
||||
print("GC, CCC, and BMG fit in one byte. Compress together.")
|
||||
print()
|
||||
#print(len(sorted(gc_set)))
|
||||
#print(len(sorted(gc_ccc_non0)))
|
||||
#print(len(sorted(gc_bmg_non0)))
|
||||
#print("GC, CCC, and BMG fit in one byte. Compress together.")
|
||||
#print()
|
||||
|
||||
print(len(sorted(sc_set)))
|
||||
print("SC fits in one byte. Compress separately.")
|
||||
print()
|
||||
#print(len(sorted(sc_set)))
|
||||
#print("SC fits in one byte. Compress separately.")
|
||||
#print()
|
||||
|
||||
print(len(dm))
|
||||
print(len(dm1), min(dm1), max(dm1))
|
||||
print(len(dm2))
|
||||
#print(sorted(dm2diff))
|
||||
print(len(sorted(set(v // 512 for v in dm1))))
|
||||
#print(len(dm))
|
||||
#print(len(dm1), min(dm1), max(dm1))
|
||||
#print(len(dm2))
|
||||
##print(sorted(dm2diff))
|
||||
#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()
|
||||
|
@ -30,7 +30,7 @@
|
||||
* 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
|
||||
*/
|
||||
#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 ignored "-Wunused-macros"
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
@ -43,6 +43,9 @@
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#ifndef __OPTIMIZE_SIZE__
|
||||
#define __OPTIMIZE_SIZE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HB_LEAN
|
||||
@ -113,6 +116,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __OPTIMIZE_SIZE__
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
#define HB_OPTIMIZE_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_OVERRIDE_H
|
||||
#include "config-override.h"
|
||||
|
@ -132,7 +132,7 @@ struct CFFIndex
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = byteArray.length;
|
||||
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);
|
||||
|
||||
/* serialize indices */
|
||||
@ -277,7 +277,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = dataArrayLen;
|
||||
this->offSize = offSize_;
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
@ -479,7 +479,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = fontDicts.length;
|
||||
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);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
@ -516,7 +516,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count = fdCount;
|
||||
this->offSize = offSize_;
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
|
@ -576,7 +576,7 @@ struct CFF1StringIndex : CFF1Index
|
||||
TRACE_SERIALIZE (this);
|
||||
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);
|
||||
count = 0;
|
||||
return_trace (true);
|
||||
|
@ -186,7 +186,7 @@ struct AxisValue
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (c->check_struct (this)))
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
|
||||
switch (u.format)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define HB_SET_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
|
||||
/*
|
||||
@ -308,7 +309,7 @@ struct hb_set_t
|
||||
{
|
||||
page->add (g);
|
||||
|
||||
array = (const T *) ((const char *) array + stride);
|
||||
array = &StructAtOffsetUnaligned<T> (array, stride);
|
||||
count--;
|
||||
}
|
||||
while (count && (g = *array, start <= g && g < end));
|
||||
|
@ -45,11 +45,39 @@ hb_subset_input_create_or_fail ()
|
||||
input->unicodes = hb_set_create ();
|
||||
input->glyphs = hb_set_create ();
|
||||
input->name_ids = hb_set_create ();
|
||||
input->drop_tables = hb_set_create ();
|
||||
input->drop_hints = false;
|
||||
input->drop_layout = true;
|
||||
input->desubroutinize = 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;
|
||||
}
|
||||
|
||||
@ -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->glyphs);
|
||||
hb_set_destroy (subset_input->name_ids);
|
||||
hb_set_destroy (subset_input->drop_tables);
|
||||
|
||||
free (subset_input);
|
||||
}
|
||||
@ -117,6 +146,12 @@ hb_subset_input_nameid_set (hb_subset_input_t *subset_input)
|
||||
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_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
|
||||
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;
|
||||
}
|
||||
|
||||
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_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
|
||||
hb_bool_t desubroutinize)
|
||||
|
@ -41,11 +41,11 @@ struct hb_subset_input_t
|
||||
hb_set_t *unicodes;
|
||||
hb_set_t *glyphs;
|
||||
hb_set_t *name_ids;
|
||||
hb_set_t *drop_tables;
|
||||
|
||||
bool drop_hints : 1;
|
||||
bool drop_layout : 1;
|
||||
bool desubroutinize : 1;
|
||||
bool retain_gids : 1;
|
||||
bool drop_hints;
|
||||
bool desubroutinize;
|
||||
bool retain_gids;
|
||||
/* TODO
|
||||
*
|
||||
* features
|
||||
|
@ -236,11 +236,12 @@ hb_subset_plan_create (hb_face_t *face,
|
||||
hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
|
||||
|
||||
plan->drop_hints = input->drop_hints;
|
||||
plan->drop_layout = input->drop_layout;
|
||||
plan->desubroutinize = input->desubroutinize;
|
||||
plan->retain_gids = input->retain_gids;
|
||||
plan->unicodes = hb_set_create ();
|
||||
plan->name_ids = hb_set_reference (input->name_ids);
|
||||
plan->drop_tables = hb_set_reference (input->drop_tables);
|
||||
|
||||
/* TODO Clean this up... */
|
||||
if (hb_set_is_empty (plan->name_ids))
|
||||
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,
|
||||
input->unicodes,
|
||||
input->glyphs,
|
||||
!plan->drop_layout,
|
||||
!input->drop_tables->has (HB_OT_TAG_GSUB),
|
||||
plan->unicodes,
|
||||
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->name_ids);
|
||||
hb_set_destroy (plan->drop_tables);
|
||||
hb_face_destroy (plan->source);
|
||||
hb_face_destroy (plan->dest);
|
||||
hb_map_destroy (plan->codepoint_to_glyph);
|
||||
|
@ -40,16 +40,18 @@ struct hb_subset_plan_t
|
||||
hb_object_header_t header;
|
||||
|
||||
bool drop_hints : 1;
|
||||
bool drop_layout : 1;
|
||||
bool desubroutinize : 1;
|
||||
bool retain_gids : 1;
|
||||
|
||||
// For each cp that we'd like to retain maps to the corresponding gid.
|
||||
hb_set_t *unicodes;
|
||||
|
||||
//name_ids we would like to retain
|
||||
// name_ids we would like to retain
|
||||
hb_set_t *name_ids;
|
||||
|
||||
// Tables which should be dropped.
|
||||
hb_set_t *drop_tables;
|
||||
|
||||
// The glyph subset
|
||||
hb_map_t *codepoint_to_glyph;
|
||||
|
||||
|
@ -236,6 +236,9 @@ _subset_table (hb_subset_plan_t *plan,
|
||||
static bool
|
||||
_should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
|
||||
{
|
||||
if (plan->drop_tables->has (tag))
|
||||
return true;
|
||||
|
||||
switch (tag) {
|
||||
case HB_TAG ('c', 'v', 'a', 'r'): /* 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 */
|
||||
return plan->drop_hints;
|
||||
|
||||
#ifdef HB_NO_SUBSET_LAYOUT
|
||||
// Drop Layout Tables if requested.
|
||||
case HB_OT_TAG_GDEF:
|
||||
case HB_OT_TAG_GPOS:
|
||||
case HB_OT_TAG_GSUB:
|
||||
#ifdef HB_NO_SUBSET_LAYOUT
|
||||
return true;
|
||||
#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:
|
||||
return false;
|
||||
}
|
||||
|
@ -57,18 +57,15 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
|
||||
HB_EXTERN hb_set_t *
|
||||
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_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
|
||||
hb_bool_t drop_hints);
|
||||
HB_EXTERN hb_bool_t
|
||||
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_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
|
||||
hb_bool_t desubroutinize);
|
||||
|
@ -42,6 +42,7 @@ TEST_PROGS = \
|
||||
test-shape \
|
||||
test-subset \
|
||||
test-subset-cmap \
|
||||
test-subset-drop-tables \
|
||||
test-subset-glyf \
|
||||
test-subset-hdmx \
|
||||
test-subset-hmtx \
|
||||
@ -57,6 +58,7 @@ TEST_PROGS = \
|
||||
|
||||
test_subset_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_hdmx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||
test_subset_hmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
|
||||
|
71
test/api/test-subset-drop-tables.c
Normal file
71
test/api/test-subset-drop-tables.c
Normal 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();
|
||||
}
|
@ -137,7 +137,9 @@ test_subset_glyf_with_gsub (void)
|
||||
|
||||
input = hb_subset_test_create_input (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);
|
||||
|
||||
@ -164,7 +166,9 @@ test_subset_glyf_without_gsub (void)
|
||||
|
||||
input = hb_subset_test_create_input (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);
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@ -16,10 +16,16 @@ trySubset (hb_face_t *face,
|
||||
{
|
||||
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_layout (input, drop_layout);
|
||||
hb_subset_input_set_retain_gids (input, retain_gids);
|
||||
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++)
|
||||
{
|
||||
hb_set_add (codepoints, text[i]);
|
||||
|
@ -50,8 +50,9 @@ bin_PROGRAMS += hb-shape
|
||||
|
||||
hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
|
||||
hb_subset_LDADD = \
|
||||
$(LDADD) \
|
||||
$(top_builddir)/src/libharfbuzz-subset.la
|
||||
$(top_builddir)/src/libharfbuzz-subset.la \
|
||||
$(LDADD)
|
||||
|
||||
bin_PROGRAMS += hb-subset
|
||||
|
||||
hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
|
||||
|
@ -32,6 +32,7 @@ HB_OT_SHAPE_CLOSURE_sources = \
|
||||
HB_SUBSET_CLI_sources = \
|
||||
hb-subset.cc \
|
||||
options.cc \
|
||||
options-subset.cc \
|
||||
options.hh \
|
||||
main-font-text.hh \
|
||||
$(NULL)
|
||||
|
@ -43,7 +43,7 @@ struct subset_consumer_t
|
||||
const font_options_t *font_opts)
|
||||
{
|
||||
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,
|
||||
@ -89,12 +89,6 @@ struct subset_consumer_t
|
||||
|
||||
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 *new_face = hb_subset (face, input);
|
||||
|
127
util/options-subset.cc
Normal file
127
util/options-subset.cc
Normal 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);
|
||||
}
|
@ -31,6 +31,8 @@
|
||||
#endif
|
||||
#include <hb-ot.h>
|
||||
|
||||
#define DELIMITERS "<+>{},;&#\\xXuUnNiI\n\t\v\f\r "
|
||||
|
||||
static struct supported_font_funcs_t {
|
||||
char name[4];
|
||||
void (*func) (hb_font_t *);
|
||||
@ -352,7 +354,7 @@ parse_unicodes (const char *name G_GNUC_UNUSED,
|
||||
|
||||
while (s && *s)
|
||||
{
|
||||
while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t\v\f\r ", *s))
|
||||
while (*s && strchr (DELIMITERS, *s))
|
||||
s++;
|
||||
if (!*s)
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define OPTIONS_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-subset.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@ -673,28 +674,18 @@ struct subset_options_t : option_group_t
|
||||
{
|
||||
subset_options_t (option_parser_t *parser)
|
||||
{
|
||||
keep_layout = false;
|
||||
drop_hints = false;
|
||||
retain_gids = false;
|
||||
desubroutinize = false;
|
||||
name_ids = hb_set_create ();
|
||||
|
||||
input = hb_subset_input_create_or_fail ();
|
||||
add_options (parser);
|
||||
}
|
||||
|
||||
virtual ~subset_options_t ()
|
||||
{
|
||||
hb_set_destroy (name_ids);
|
||||
hb_subset_input_destroy (input);
|
||||
}
|
||||
|
||||
|
||||
void add_options (option_parser_t *parser);
|
||||
|
||||
hb_bool_t keep_layout;
|
||||
hb_bool_t drop_hints;
|
||||
hb_bool_t retain_gids;
|
||||
hb_bool_t desubroutinize;
|
||||
hb_set_t *name_ids;
|
||||
hb_subset_input_t *input;
|
||||
};
|
||||
|
||||
/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
|
||||
|
Loading…
Reference in New Issue
Block a user