[repacker] begin adding PairPos splitting support.
This commit is contained in:
parent
f3aff45e04
commit
f6a242b605
|
@ -411,7 +411,7 @@ test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc
|
|||
test_priority_queue_CPPFLAGS = $(HBCFLAGS)
|
||||
test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_repacker_SOURCES = test-repacker.cc hb-static.cc graph/gsubgpos-graph.cc
|
||||
test_repacker_SOURCES = test-repacker.cc hb-static.cc graph/gsubgpos-context.cc
|
||||
test_repacker_CPPFLAGS = $(HBCFLAGS)
|
||||
test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
|
||||
|
||||
|
|
|
@ -349,7 +349,9 @@ HB_SUBSET_sources = \
|
|||
hb-repacker.hh \
|
||||
graph/graph.hh \
|
||||
graph/gsubgpos-graph.hh \
|
||||
graph/gsubgpos-graph.cc \
|
||||
graph/gsubgpos-context.hh \
|
||||
graph/gsubgpos-context.cc \
|
||||
graph/pairpos-graph.hh \
|
||||
graph/serialize.hh \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -97,10 +97,11 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
|
|||
}
|
||||
};
|
||||
|
||||
static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
|
||||
const MarkArray &mark_array,
|
||||
const hb_set_t &glyphset,
|
||||
hb_map_t* klass_mapping /* INOUT */)
|
||||
HB_INTERNAL inline
|
||||
void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
|
||||
const MarkArray &mark_array,
|
||||
const hb_set_t &glyphset,
|
||||
hb_map_t* klass_mapping /* INOUT */)
|
||||
{
|
||||
hb_set_t orig_classes;
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
|
||||
#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
|
||||
|
||||
#include "ValueFormat.hh"
|
||||
|
||||
namespace OT {
|
||||
namespace Layout {
|
||||
namespace GPOS_impl {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
namespace graph {
|
||||
|
||||
make_extension_context_t::make_extension_context_t (hb_tag_t table_tag_,
|
||||
gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
|
||||
graph_t& graph_,
|
||||
hb_vector_t<char>& buffer_)
|
||||
: table_tag (table_tag_),
|
||||
|
@ -47,7 +47,7 @@ make_extension_context_t::make_extension_context_t (hb_tag_t table_tag_,
|
|||
buffer.alloc (num_non_ext_subtables () * extension_size);
|
||||
}
|
||||
|
||||
unsigned make_extension_context_t::num_non_ext_subtables () {
|
||||
unsigned gsubgpos_graph_context_t::num_non_ext_subtables () {
|
||||
unsigned count = 0;
|
||||
for (auto l : lookups.values ())
|
||||
{
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright © 2022 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 "graph.hh"
|
||||
#include "../hb-ot-layout-gsubgpos.hh"
|
||||
|
||||
#ifndef GRAPH_GSUBGPOS_CONTEXT_HH
|
||||
#define GRAPH_GSUBGPOS_CONTEXT_HH
|
||||
|
||||
namespace graph {
|
||||
|
||||
struct Lookup;
|
||||
|
||||
struct gsubgpos_graph_context_t
|
||||
{
|
||||
hb_tag_t table_tag;
|
||||
graph_t& graph;
|
||||
hb_vector_t<char>& buffer;
|
||||
unsigned lookup_list_index;
|
||||
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
|
||||
|
||||
HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
|
||||
graph_t& graph_,
|
||||
hb_vector_t<char>& buffer_);
|
||||
|
||||
bool in_error () const
|
||||
{
|
||||
return buffer.in_error ();
|
||||
}
|
||||
|
||||
private:
|
||||
HB_INTERNAL unsigned num_non_ext_subtables ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // GRAPH_GSUBGPOS_CONTEXT
|
|
@ -27,6 +27,8 @@
|
|||
#include "graph.hh"
|
||||
#include "../hb-ot-layout-gsubgpos.hh"
|
||||
#include "../OT/Layout/GSUB/ExtensionSubst.hh"
|
||||
#include "gsubgpos-context.hh"
|
||||
#include "pairpos-graph.hh"
|
||||
|
||||
#ifndef GRAPH_GSUBGPOS_GRAPH_HH
|
||||
#define GRAPH_GSUBGPOS_GRAPH_HH
|
||||
|
@ -35,27 +37,6 @@ namespace graph {
|
|||
|
||||
struct Lookup;
|
||||
|
||||
struct make_extension_context_t
|
||||
{
|
||||
hb_tag_t table_tag;
|
||||
graph_t& graph;
|
||||
hb_vector_t<char>& buffer;
|
||||
unsigned lookup_list_index;
|
||||
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
|
||||
|
||||
HB_INTERNAL make_extension_context_t (hb_tag_t table_tag_,
|
||||
graph_t& graph_,
|
||||
hb_vector_t<char>& buffer_);
|
||||
|
||||
bool in_error () const
|
||||
{
|
||||
return buffer.in_error ();
|
||||
}
|
||||
|
||||
private:
|
||||
HB_INTERNAL unsigned num_non_ext_subtables ();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
|
||||
{
|
||||
|
@ -65,6 +46,16 @@ struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
|
|||
this->extensionLookupType = type;
|
||||
this->extensionOffset = 0;
|
||||
}
|
||||
|
||||
unsigned get_lookup_type () const
|
||||
{
|
||||
return this->extensionLookupType;
|
||||
}
|
||||
|
||||
unsigned get_subtable_index (graph_t& graph, unsigned this_index) const
|
||||
{
|
||||
return graph.index_for_offset (this_index, &this->extensionOffset);
|
||||
}
|
||||
};
|
||||
|
||||
struct Lookup : public OT::Lookup
|
||||
|
@ -86,7 +77,7 @@ struct Lookup : public OT::Lookup
|
|||
return lookupType == extension_type (table_tag);
|
||||
}
|
||||
|
||||
bool make_extension (make_extension_context_t& c,
|
||||
bool make_extension (gsubgpos_graph_context_t& c,
|
||||
unsigned this_index)
|
||||
{
|
||||
unsigned type = lookupType;
|
||||
|
@ -115,7 +106,43 @@ struct Lookup : public OT::Lookup
|
|||
return true;
|
||||
}
|
||||
|
||||
bool make_subtable_extension (make_extension_context_t& c,
|
||||
bool split_subtables_if_needed (gsubgpos_graph_context_t& c,
|
||||
unsigned this_index)
|
||||
{
|
||||
unsigned type = lookupType;
|
||||
bool is_ext = is_extension (c.table_tag);
|
||||
|
||||
if (c.table_tag != HB_OT_TAG_GPOS)
|
||||
return true;
|
||||
|
||||
if (!is_ext && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
|
||||
return true;
|
||||
|
||||
// TODO check subtable type.
|
||||
for (unsigned i = 0; i < subTable.len; i++)
|
||||
{
|
||||
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
|
||||
if (is_ext) {
|
||||
unsigned ext_subtable_index = subtable_index;
|
||||
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
|
||||
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
|
||||
c.graph.object (ext_subtable_index).head;
|
||||
|
||||
subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
|
||||
type = extension->get_lookup_type ();
|
||||
if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
|
||||
continue;
|
||||
}
|
||||
|
||||
PairPos* pairPos = (PairPos*) c.graph.object (subtable_index).head;
|
||||
// TODO sanitize
|
||||
pairPos->split_subtables (c, subtable_index);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool make_subtable_extension (gsubgpos_graph_context_t& c,
|
||||
unsigned lookup_index,
|
||||
unsigned subtable_index)
|
||||
{
|
||||
|
@ -214,6 +241,9 @@ struct GSTAR : public OT::GSUBGPOS
|
|||
return len >= get_size ();
|
||||
}
|
||||
|
||||
// TODO(garretrieger): add find subtable's method, could be templated locate a specific
|
||||
// subtable type, maybe take the lookup map as a starting point?
|
||||
|
||||
void find_lookups (graph_t& graph,
|
||||
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright © 2022 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
|
||||
*/
|
||||
|
||||
#ifndef GRAPH_PAIRPOS_GRAPH_HH
|
||||
#define GRAPH_PAIRPOS_GRAPH_HH
|
||||
|
||||
#include "../OT/Layout/GPOS/PairPos.hh"
|
||||
#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
|
||||
|
||||
namespace graph {
|
||||
|
||||
struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
|
||||
{
|
||||
unsigned get_size () const
|
||||
{
|
||||
return OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
|
||||
+ pairSet.get_size () - SmallTypes::size;
|
||||
}
|
||||
|
||||
bool split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
||||
{
|
||||
printf("Checking if pair pos %u needs splits...\n", this_index);
|
||||
hb_set_t visited;
|
||||
const unsigned base_size = get_size ();
|
||||
printf(" base_size = %u\n", base_size);
|
||||
unsigned accumulated = base_size;
|
||||
// TODO: include coverage size
|
||||
unsigned num_pair_sets = pairSet.len;
|
||||
printf(" num_pair_sets = %u\n", num_pair_sets);
|
||||
for (unsigned i = 0; i < pairSet.len; i++)
|
||||
{
|
||||
unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
|
||||
accumulated += c.graph.find_subgraph_size (pair_set_index, visited);
|
||||
|
||||
if (accumulated > (1 << 16))
|
||||
{
|
||||
// TODO: do the split
|
||||
|
||||
printf(" PairPos split needed %u/%u\n", i, num_pair_sets);
|
||||
accumulated = base_size;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
|
||||
{
|
||||
return c.graph.index_for_offset (this_index, &pairSet[i]);
|
||||
}
|
||||
};
|
||||
|
||||
struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
|
||||
{
|
||||
bool split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct PairPos : public OT::Layout::GPOS_impl::PairPos
|
||||
{
|
||||
bool split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
||||
{
|
||||
unsigned format = u.format;
|
||||
printf("PairPos::format = %u\n", format);
|
||||
switch (u.format) {
|
||||
case 1:
|
||||
return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
|
||||
case 2:
|
||||
return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
|
||||
#ifndef HB_NO_BORING_EXPANSION
|
||||
case 3:
|
||||
case 4:
|
||||
// Don't split 24bit PairPos's.
|
||||
#endif
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // GRAPH_PAIRPOS_GRAPH_HH
|
|
@ -1,4 +1,4 @@
|
|||
#include "graph/gsubgpos-graph.cc"
|
||||
#include "gsubgpos-context.cc"
|
||||
#include "hb-aat-layout.cc"
|
||||
#include "hb-aat-map.cc"
|
||||
#include "hb-blob.cc"
|
||||
|
|
|
@ -66,12 +66,34 @@ inline int compare_sizes (const void* a, const void* b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context)
|
||||
{
|
||||
// Algorithm:
|
||||
// 1. Scan all sub-tables and compute their sizes.
|
||||
// 2. For any PairPos subtables that are >64kb:
|
||||
// a. split into two more pieces that are <64kb
|
||||
// b. De-dup subgraphs (optional) (can this be done during serialization?)
|
||||
|
||||
// TODO: Add a split subtables method at the lookup level, it could scan it's subtables and split as
|
||||
// needed.
|
||||
// TODO: rename gsubgpos_graph_context_t to be more general.
|
||||
|
||||
for (unsigned lookup_index : ext_context.lookups.keys ())
|
||||
{
|
||||
graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
|
||||
lookup->split_subtables_if_needed (ext_context, lookup_index);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
|
||||
* to extension lookups.
|
||||
*/
|
||||
static inline
|
||||
bool _promote_extensions_if_needed (graph::make_extension_context_t& ext_context)
|
||||
bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context)
|
||||
{
|
||||
// Simple Algorithm (v1, current):
|
||||
// 1. Calculate how many bytes each non-extension lookup consumes.
|
||||
|
@ -293,10 +315,15 @@ hb_resolve_overflows (const T& packed,
|
|||
{
|
||||
if (recalculate_extensions)
|
||||
{
|
||||
graph::make_extension_context_t ext_context (table_tag, sorted_graph, extension_buffer);
|
||||
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph, extension_buffer);
|
||||
if (ext_context.in_error ())
|
||||
return nullptr;
|
||||
|
||||
if (!_presplit_subtables_if_needed (ext_context)) {
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!_promote_extensions_if_needed (ext_context)) {
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
|
||||
return nullptr;
|
||||
|
|
|
@ -345,7 +345,7 @@ hb_subset_sources = files(
|
|||
'hb-subset-plan.cc',
|
||||
'hb-subset-plan.hh',
|
||||
'hb-subset-repacker.cc',
|
||||
'graph/gsubgpos-graph.cc',
|
||||
'graph/gsubgpos-context.cc',
|
||||
'hb-subset.cc',
|
||||
'hb-subset.hh',
|
||||
)
|
||||
|
@ -574,7 +574,7 @@ if get_option('tests').enabled()
|
|||
'test-number': ['test-number.cc', 'hb-number.cc'],
|
||||
'test-ot-tag': ['hb-ot-tag.cc'],
|
||||
'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
|
||||
'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-graph.cc'],
|
||||
'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-context.cc'],
|
||||
'test-set': ['test-set.cc', 'hb-static.cc'],
|
||||
'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
|
||||
'test-unicode-ranges': ['test-unicode-ranges.cc'],
|
||||
|
|
Loading…
Reference in New Issue