[repack] WIP implement extension promotion mechanism.
This commit is contained in:
parent
d9295d88a7
commit
c20b85cfed
|
@ -199,7 +199,7 @@ struct graph_t
|
|||
return vertices_.length - 1;
|
||||
}
|
||||
|
||||
const hb_serialize_context_t::object_t& object(unsigned i) const
|
||||
const hb_serialize_context_t::object_t& object (unsigned i) const
|
||||
{
|
||||
return vertices_[i].obj;
|
||||
}
|
||||
|
@ -368,6 +368,8 @@ struct graph_t
|
|||
*/
|
||||
bool assign_spaces ()
|
||||
{
|
||||
update_parents ();
|
||||
|
||||
hb_set_t visited;
|
||||
hb_set_t roots;
|
||||
find_space_roots (visited, roots);
|
||||
|
@ -632,6 +634,40 @@ struct graph_t
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds a new node to the graph, not connected to anything.
|
||||
*/
|
||||
unsigned new_node (char* head, char* tail)
|
||||
{
|
||||
positions_invalid = true;
|
||||
distance_invalid = true;
|
||||
parents_invalid = true; // TODO: remove
|
||||
|
||||
auto* clone = vertices_.push ();
|
||||
if (vertices_.in_error ()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
clone->obj.head = head;
|
||||
clone->obj.tail = tail;
|
||||
clone->distance = 0;
|
||||
clone->space = 0;
|
||||
|
||||
unsigned clone_idx = vertices_.length - 2;
|
||||
|
||||
// The last object is the root of the graph, so swap back the root to the end.
|
||||
// The root's obj idx does change, however since it's root nothing else refers to it.
|
||||
// all other obj idx's will be unaffected.
|
||||
hb_swap (vertices_[vertices_.length - 2], *clone);
|
||||
|
||||
// Since the root moved, update the parents arrays of all children on the root.
|
||||
for (const auto& l : root ().obj.all_links ())
|
||||
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
|
||||
|
||||
return clone_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Raises the sorting priority of all children.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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_GSUBGPOS_GRAPH_HH
|
||||
#define GRAPH_GSUBGPOS_GRAPH_HH
|
||||
|
||||
#include "graph.hh"
|
||||
#include "hb-ot-layout-gsubgpos.hh"
|
||||
#include "OT/Layout/GSUB/ExtensionSubst.hh"
|
||||
|
||||
namespace graph {
|
||||
|
||||
struct GSTAR : public OT::GSUBGPOS
|
||||
{
|
||||
const void* get_lookup_list_field_offset () const
|
||||
{
|
||||
switch (u.version.major) {
|
||||
case 1: return &(u.version1.lookupList);
|
||||
#ifndef HB_NO_BORING_EXPANSION
|
||||
case 2: return &(u.version2.lookupList);
|
||||
#endif
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Lookup : public OT::Lookup
|
||||
{
|
||||
unsigned extension_type (hb_tag_t table_tag)
|
||||
{
|
||||
switch (table_tag)
|
||||
{
|
||||
case HB_OT_TAG_GPOS: return 9;
|
||||
case HB_OT_TAG_GSUB: return 7;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool make_extension (hb_tag_t table_tag,
|
||||
graph_t& graph,
|
||||
unsigned this_index,
|
||||
hb_vector_t<char>& buffer)
|
||||
{
|
||||
// TODO: use a context_t?
|
||||
unsigned ext_type = extension_type (table_tag);
|
||||
unsigned type = lookupType;
|
||||
if (!ext_type || type == ext_type)
|
||||
{
|
||||
// NOOP
|
||||
printf("Already extension (obj %u).\n", this_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
printf("Promoting lookup type %u (obj %u) to extension.\n",
|
||||
type,
|
||||
this_index);
|
||||
|
||||
|
||||
for (unsigned i = 0; i < subTable.len; i++)
|
||||
{
|
||||
unsigned subtable_index = graph.index_for_offset (this_index, &subTable[i]);
|
||||
if (!make_subtable_extension (graph,
|
||||
this_index,
|
||||
subtable_index,
|
||||
buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
lookupType = ext_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool make_subtable_extension (graph_t& graph,
|
||||
unsigned lookup_index,
|
||||
unsigned subtable_index,
|
||||
hb_vector_t<char>& buffer)
|
||||
{
|
||||
printf(" Promoting subtable %u in lookup %u to extension.\n", subtable_index, lookup_index);
|
||||
|
||||
unsigned type = lookupType;
|
||||
unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
|
||||
unsigned start = buffer.length;
|
||||
unsigned end = start + extension_size;
|
||||
if (!buffer.resize (buffer.length + extension_size))
|
||||
return false;
|
||||
|
||||
OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
|
||||
(OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) &buffer[start];
|
||||
extension->format = 1;
|
||||
extension->extensionLookupType = type;
|
||||
extension->extensionOffset = 0;
|
||||
|
||||
unsigned ext_index = graph.new_node (&buffer[start], &buffer[end]);
|
||||
if (ext_index == (unsigned) -1) return false;
|
||||
|
||||
auto& lookup_vertex = graph.vertices_[lookup_index];
|
||||
for (auto& l : lookup_vertex.obj.real_links.writer ())
|
||||
{
|
||||
if (l.objidx == subtable_index)
|
||||
{
|
||||
// Change lookup to point at the extension.
|
||||
printf(" Changing %d to %d\n", l.objidx, ext_index);
|
||||
l.objidx = ext_index;
|
||||
}
|
||||
}
|
||||
|
||||
// Make extension point at the subtable.
|
||||
// TODO: update extension parents array.
|
||||
auto& ext_vertex = graph.vertices_[ext_index];
|
||||
auto& subtable_vertex = graph.vertices_[subtable_index];
|
||||
auto* l = ext_vertex.obj.real_links.push ();
|
||||
|
||||
l->width = 4;
|
||||
l->objidx = subtable_index;
|
||||
l->is_signed = 0;
|
||||
l->whence = 0;
|
||||
l->position = 4;
|
||||
l->bias = 0;
|
||||
|
||||
subtable_vertex.remap_parent (lookup_index, ext_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static inline void
|
||||
find_lookups (graph_t& graph,
|
||||
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
|
||||
{
|
||||
// TODO: move this into GSTAR?
|
||||
// TODO: template on types, based on gstar version.
|
||||
const GSTAR* gstar = (const GSTAR*) graph.root ().obj.head;
|
||||
|
||||
unsigned lookup_list_idx = graph.index_for_offset (graph.root_idx (),
|
||||
gstar->get_lookup_list_field_offset());
|
||||
|
||||
const OT::LookupList<SmallTypes>* lookupList =
|
||||
(const OT::LookupList<SmallTypes>*) graph.object (lookup_list_idx).head;
|
||||
|
||||
for (unsigned i = 0; i < lookupList->len; i++)
|
||||
{
|
||||
unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
|
||||
Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
|
||||
lookups.set (lookup_idx, lookup);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* GRAPH_GSUBGPOS_GRAPH_HH */
|
|
@ -3850,7 +3850,7 @@ struct ExtensionFormat1
|
|||
return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
|
||||
}
|
||||
|
||||
protected:
|
||||
public: // TODO
|
||||
HBUINT16 format; /* Format identifier. Set to 1. */
|
||||
HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
|
||||
* by ExtensionOffset (i.e. the
|
||||
|
|
|
@ -44,7 +44,7 @@ using graph::graph_t;
|
|||
*/
|
||||
|
||||
static inline
|
||||
void _make_extensions (graph_t& sorted_graph)
|
||||
void _make_extensions (hb_tag_t table_tag, graph_t& sorted_graph, hb_vector_t<char>& buffer)
|
||||
{
|
||||
// TODO: Move this into graph or gsubgpos graph?
|
||||
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
|
||||
|
@ -52,7 +52,7 @@ void _make_extensions (graph_t& sorted_graph)
|
|||
|
||||
for (auto p : lookups.iter ())
|
||||
{
|
||||
p.second->make_extension (sorted_graph, p.first);
|
||||
p.second->make_extension (table_tag, sorted_graph, p.first, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,12 +182,13 @@ hb_resolve_overflows (const T& packed,
|
|||
return graph::serialize (sorted_graph);
|
||||
}
|
||||
|
||||
hb_vector_t<char> extension_buffer;
|
||||
if ((table_tag == HB_OT_TAG_GPOS
|
||||
|| table_tag == HB_OT_TAG_GSUB)
|
||||
&& will_overflow)
|
||||
{
|
||||
_make_extensions (table_tag, sorted_graph, extension_buffer);
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
|
||||
_make_extensions (sorted_graph);
|
||||
if (sorted_graph.assign_spaces ())
|
||||
sorted_graph.sort_shortest_distance ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue