2022-07-20 01:33:16 +02:00
|
|
|
/*
|
|
|
|
* 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"
|
2022-07-26 02:04:20 +02:00
|
|
|
#include "../hb-ot-layout-gsubgpos.hh"
|
|
|
|
#include "../OT/Layout/GSUB/ExtensionSubst.hh"
|
2022-07-27 20:58:41 +02:00
|
|
|
#include "gsubgpos-context.hh"
|
|
|
|
#include "pairpos-graph.hh"
|
2022-08-11 21:26:59 +02:00
|
|
|
#include "markbasepos-graph.hh"
|
2022-07-20 01:33:16 +02:00
|
|
|
|
2022-07-21 21:07:55 +02:00
|
|
|
#ifndef GRAPH_GSUBGPOS_GRAPH_HH
|
|
|
|
#define GRAPH_GSUBGPOS_GRAPH_HH
|
|
|
|
|
2022-07-20 01:33:16 +02:00
|
|
|
namespace graph {
|
|
|
|
|
2022-07-21 20:36:20 +02:00
|
|
|
struct Lookup;
|
|
|
|
|
2022-07-23 00:49:40 +02:00
|
|
|
template<typename T>
|
|
|
|
struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
|
|
|
|
{
|
|
|
|
void reset(unsigned type)
|
|
|
|
{
|
|
|
|
this->format = 1;
|
|
|
|
this->extensionLookupType = type;
|
|
|
|
this->extensionOffset = 0;
|
|
|
|
}
|
2022-07-27 20:58:41 +02:00
|
|
|
|
2022-07-29 20:29:12 +02:00
|
|
|
bool sanitize (graph_t::vertex_t& vertex) const
|
|
|
|
{
|
|
|
|
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
|
|
|
return vertex_len >= OT::ExtensionFormat1<T>::static_size;
|
|
|
|
}
|
|
|
|
|
2022-07-27 20:58:41 +02:00
|
|
|
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);
|
|
|
|
}
|
2022-07-23 00:49:40 +02:00
|
|
|
};
|
|
|
|
|
2022-07-20 01:33:16 +02:00
|
|
|
struct Lookup : public OT::Lookup
|
|
|
|
{
|
2022-07-21 20:36:20 +02:00
|
|
|
unsigned number_of_subtables () const
|
2022-07-20 01:33:16 +02:00
|
|
|
{
|
2022-07-21 20:36:20 +02:00
|
|
|
return subTable.len;
|
|
|
|
}
|
|
|
|
|
2022-07-21 23:45:04 +02:00
|
|
|
bool sanitize (graph_t::vertex_t& vertex) const
|
|
|
|
{
|
|
|
|
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
|
|
|
if (vertex_len < OT::Lookup::min_size) return false;
|
|
|
|
return vertex_len >= this->get_size ();
|
|
|
|
}
|
|
|
|
|
2022-07-21 20:36:20 +02:00
|
|
|
bool is_extension (hb_tag_t table_tag) const
|
|
|
|
{
|
|
|
|
return lookupType == extension_type (table_tag);
|
2022-07-20 01:33:16 +02:00
|
|
|
}
|
|
|
|
|
2022-07-27 20:58:41 +02:00
|
|
|
bool make_extension (gsubgpos_graph_context_t& c,
|
2022-07-21 21:07:55 +02:00
|
|
|
unsigned this_index)
|
2022-07-20 01:33:16 +02:00
|
|
|
{
|
|
|
|
unsigned type = lookupType;
|
2022-07-21 21:07:55 +02:00
|
|
|
unsigned ext_type = extension_type (c.table_tag);
|
|
|
|
if (!ext_type || is_extension (c.table_tag))
|
2022-07-20 01:33:16 +02:00
|
|
|
{
|
|
|
|
// NOOP
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-21 23:45:04 +02:00
|
|
|
DEBUG_MSG (SUBSET_REPACK, nullptr,
|
2022-07-22 23:04:34 +02:00
|
|
|
"Promoting lookup type %u (obj %u) to extension.",
|
2022-07-21 23:45:04 +02:00
|
|
|
type,
|
|
|
|
this_index);
|
2022-07-20 01:33:16 +02:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < subTable.len; i++)
|
|
|
|
{
|
2022-07-21 21:07:55 +02:00
|
|
|
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
|
|
|
|
if (!make_subtable_extension (c,
|
2022-07-20 01:33:16 +02:00
|
|
|
this_index,
|
2022-07-21 21:07:55 +02:00
|
|
|
subtable_index))
|
2022-07-20 01:33:16 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
lookupType = ext_type;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-27 20:58:41 +02:00
|
|
|
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;
|
|
|
|
|
2022-08-17 02:36:23 +02:00
|
|
|
if (!is_ext &&
|
|
|
|
type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair &&
|
|
|
|
type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
|
2022-07-27 20:58:41 +02:00
|
|
|
return true;
|
|
|
|
|
2022-08-05 02:32:47 +02:00
|
|
|
hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>> all_new_subtables;
|
2022-07-27 20:58:41 +02:00
|
|
|
for (unsigned i = 0; i < subTable.len; i++)
|
|
|
|
{
|
|
|
|
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
|
2022-09-29 21:39:59 +02:00
|
|
|
unsigned parent_index = this_index;
|
2022-07-27 20:58:41 +02:00
|
|
|
if (is_ext) {
|
|
|
|
unsigned ext_subtable_index = subtable_index;
|
2022-09-29 21:39:59 +02:00
|
|
|
parent_index = ext_subtable_index;
|
2022-07-27 20:58:41 +02:00
|
|
|
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
|
|
|
|
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
|
|
|
|
c.graph.object (ext_subtable_index).head;
|
2022-08-06 01:37:11 +02:00
|
|
|
if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index]))
|
2022-07-29 20:29:12 +02:00
|
|
|
continue;
|
2022-07-27 20:58:41 +02:00
|
|
|
|
|
|
|
subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
|
|
|
|
type = extension->get_lookup_type ();
|
2022-08-17 02:36:23 +02:00
|
|
|
if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair
|
|
|
|
&& type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase)
|
2022-07-27 20:58:41 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-08-11 21:26:59 +02:00
|
|
|
hb_vector_t<unsigned> new_sub_tables;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 2:
|
2022-09-29 21:39:59 +02:00
|
|
|
new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
|
2022-08-11 21:26:59 +02:00
|
|
|
case 4:
|
2022-09-29 21:39:59 +02:00
|
|
|
new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
|
2022-08-11 21:26:59 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-07-28 02:55:36 +02:00
|
|
|
if (new_sub_tables.in_error ()) return false;
|
2022-08-11 21:26:59 +02:00
|
|
|
if (!new_sub_tables) continue;
|
2022-08-05 02:32:47 +02:00
|
|
|
hb_pair_t<unsigned, hb_vector_t<unsigned>>* entry = all_new_subtables.push ();
|
|
|
|
entry->first = i;
|
|
|
|
entry->second = std::move (new_sub_tables);
|
2022-07-27 20:58:41 +02:00
|
|
|
}
|
|
|
|
|
2022-08-05 02:32:47 +02:00
|
|
|
if (all_new_subtables) {
|
2022-07-29 02:25:19 +02:00
|
|
|
add_sub_tables (c, this_index, type, all_new_subtables);
|
2022-08-05 02:32:47 +02:00
|
|
|
}
|
2022-07-28 02:55:36 +02:00
|
|
|
|
2022-07-27 20:58:41 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-11 21:26:59 +02:00
|
|
|
template<typename T>
|
|
|
|
hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
|
2022-09-29 21:39:59 +02:00
|
|
|
unsigned parent_idx,
|
2022-08-11 21:26:59 +02:00
|
|
|
unsigned objidx)
|
|
|
|
{
|
|
|
|
T* sub_table = (T*) c.graph.object (objidx).head;
|
|
|
|
if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
|
|
|
|
return hb_vector_t<unsigned> ();
|
|
|
|
|
2022-09-29 21:39:59 +02:00
|
|
|
return sub_table->split_subtables (c, parent_idx, objidx);
|
2022-08-11 21:26:59 +02:00
|
|
|
}
|
|
|
|
|
2022-07-28 02:55:36 +02:00
|
|
|
void add_sub_tables (gsubgpos_graph_context_t& c,
|
|
|
|
unsigned this_index,
|
2022-07-28 03:04:37 +02:00
|
|
|
unsigned type,
|
2022-08-05 02:32:47 +02:00
|
|
|
hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
|
2022-07-20 01:33:16 +02:00
|
|
|
{
|
2022-07-28 03:04:37 +02:00
|
|
|
bool is_ext = is_extension (c.table_tag);
|
2022-07-28 02:55:36 +02:00
|
|
|
auto& v = c.graph.vertices_[this_index];
|
2022-08-05 02:32:47 +02:00
|
|
|
fix_existing_subtable_links (c, this_index, subtable_ids);
|
|
|
|
|
|
|
|
unsigned new_subtable_count = 0;
|
|
|
|
for (const auto& p : subtable_ids)
|
|
|
|
new_subtable_count += p.second.length;
|
2022-07-28 02:55:36 +02:00
|
|
|
|
|
|
|
size_t new_size = v.table_size ()
|
2022-08-05 02:32:47 +02:00
|
|
|
+ new_subtable_count * OT::Offset16::static_size;
|
2022-07-28 02:55:36 +02:00
|
|
|
char* buffer = (char*) hb_calloc (1, new_size);
|
|
|
|
c.add_buffer (buffer);
|
2022-11-22 20:56:48 +01:00
|
|
|
hb_memcpy (buffer, v.obj.head, v.table_size());
|
2022-07-28 22:54:28 +02:00
|
|
|
|
2022-07-28 02:55:36 +02:00
|
|
|
v.obj.head = buffer;
|
|
|
|
v.obj.tail = buffer + new_size;
|
|
|
|
|
|
|
|
Lookup* new_lookup = (Lookup*) buffer;
|
|
|
|
|
2022-08-05 03:25:16 +02:00
|
|
|
unsigned shift = 0;
|
2022-08-05 02:32:47 +02:00
|
|
|
new_lookup->subTable.len = subTable.len + new_subtable_count;
|
|
|
|
for (const auto& p : subtable_ids)
|
2022-07-28 02:55:36 +02:00
|
|
|
{
|
2022-08-05 03:25:16 +02:00
|
|
|
unsigned offset_index = p.first + shift + 1;
|
|
|
|
shift += p.second.length;
|
|
|
|
|
2022-08-05 02:32:47 +02:00
|
|
|
for (unsigned subtable_id : p.second)
|
2022-07-28 03:04:37 +02:00
|
|
|
{
|
2022-08-05 02:32:47 +02:00
|
|
|
if (is_ext)
|
|
|
|
{
|
|
|
|
unsigned ext_id = create_extension_subtable (c, subtable_id, type);
|
|
|
|
c.graph.vertices_[subtable_id].parents.push (ext_id);
|
|
|
|
subtable_id = ext_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* link = v.obj.real_links.push ();
|
|
|
|
link->width = 2;
|
|
|
|
link->objidx = subtable_id;
|
|
|
|
link->position = (char*) &new_lookup->subTable[offset_index++] -
|
|
|
|
(char*) new_lookup;
|
|
|
|
c.graph.vertices_[subtable_id].parents.push (this_index);
|
2022-07-28 03:04:37 +02:00
|
|
|
}
|
2022-07-28 02:55:36 +02:00
|
|
|
}
|
2022-07-29 02:25:19 +02:00
|
|
|
|
2022-08-05 02:32:47 +02:00
|
|
|
// Repacker sort order depends on link order, which we've messed up so resort it.
|
|
|
|
v.obj.real_links.qsort ();
|
|
|
|
|
2022-07-29 02:25:19 +02:00
|
|
|
// The head location of the lookup has changed, invalidating the lookups map entry
|
|
|
|
// in the context. Update the map.
|
|
|
|
c.lookups.set (this_index, new_lookup);
|
2022-07-28 02:55:36 +02:00
|
|
|
}
|
2022-07-27 22:00:00 +02:00
|
|
|
|
2022-08-05 02:32:47 +02:00
|
|
|
void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
|
|
|
|
unsigned this_index,
|
|
|
|
hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
|
|
|
|
{
|
|
|
|
auto& v = c.graph.vertices_[this_index];
|
|
|
|
Lookup* lookup = (Lookup*) v.obj.head;
|
|
|
|
|
2022-08-05 03:25:16 +02:00
|
|
|
unsigned shift = 0;
|
2022-08-05 02:32:47 +02:00
|
|
|
for (const auto& p : subtable_ids)
|
|
|
|
{
|
2022-08-05 03:25:16 +02:00
|
|
|
unsigned insert_index = p.first + shift;
|
2022-08-05 02:32:47 +02:00
|
|
|
unsigned pos_offset = p.second.length * OT::Offset16::static_size;
|
|
|
|
unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup;
|
2022-08-05 03:25:16 +02:00
|
|
|
shift += p.second.length;
|
2022-08-05 02:32:47 +02:00
|
|
|
|
|
|
|
for (auto& l : v.obj.all_links_writer ())
|
|
|
|
{
|
|
|
|
if (l.position > insert_offset) l.position += pos_offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-28 02:55:36 +02:00
|
|
|
unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
|
|
|
|
unsigned subtable_index,
|
|
|
|
unsigned type)
|
|
|
|
{
|
|
|
|
unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
|
2022-07-27 22:00:00 +02:00
|
|
|
|
|
|
|
unsigned ext_index = c.create_node (extension_size);
|
|
|
|
if (ext_index == (unsigned) -1)
|
2022-07-28 02:55:36 +02:00
|
|
|
return -1;
|
2022-07-20 01:33:16 +02:00
|
|
|
|
2022-07-28 02:55:36 +02:00
|
|
|
auto& ext_vertex = c.graph.vertices_[ext_index];
|
2022-07-23 00:49:40 +02:00
|
|
|
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
|
2022-07-28 02:55:36 +02:00
|
|
|
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head;
|
2022-07-23 00:49:40 +02:00
|
|
|
extension->reset (type);
|
2022-07-20 01:33:16 +02:00
|
|
|
|
2022-07-28 02:55:36 +02:00
|
|
|
// Make extension point at the subtable.
|
|
|
|
auto* l = ext_vertex.obj.real_links.push ();
|
|
|
|
|
|
|
|
l->width = 4;
|
|
|
|
l->objidx = subtable_index;
|
|
|
|
l->position = 4;
|
|
|
|
|
|
|
|
return ext_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool make_subtable_extension (gsubgpos_graph_context_t& c,
|
|
|
|
unsigned lookup_index,
|
|
|
|
unsigned subtable_index)
|
|
|
|
{
|
|
|
|
unsigned type = lookupType;
|
|
|
|
|
2022-07-28 03:04:37 +02:00
|
|
|
unsigned ext_index = create_extension_subtable(c, subtable_index, type);
|
2022-07-28 02:55:36 +02:00
|
|
|
if (ext_index == (unsigned) -1)
|
|
|
|
return false;
|
2022-07-20 01:33:16 +02:00
|
|
|
|
2022-07-21 21:07:55 +02:00
|
|
|
auto& lookup_vertex = c.graph.vertices_[lookup_index];
|
2022-07-20 01:33:16 +02:00
|
|
|
for (auto& l : lookup_vertex.obj.real_links.writer ())
|
|
|
|
{
|
|
|
|
if (l.objidx == subtable_index)
|
|
|
|
// Change lookup to point at the extension.
|
|
|
|
l.objidx = ext_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make extension point at the subtable.
|
2022-07-21 21:07:55 +02:00
|
|
|
auto& ext_vertex = c.graph.vertices_[ext_index];
|
|
|
|
auto& subtable_vertex = c.graph.vertices_[subtable_index];
|
2022-07-20 20:17:29 +02:00
|
|
|
ext_vertex.parents.push (lookup_index);
|
2022-07-20 01:33:16 +02:00
|
|
|
subtable_vertex.remap_parent (lookup_index, ext_index);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-21 20:36:20 +02:00
|
|
|
private:
|
|
|
|
unsigned extension_type (hb_tag_t table_tag) const
|
2022-07-20 01:33:16 +02:00
|
|
|
{
|
2022-07-21 20:36:20 +02:00
|
|
|
switch (table_tag)
|
|
|
|
{
|
|
|
|
case HB_OT_TAG_GPOS: return 9;
|
|
|
|
case HB_OT_TAG_GSUB: return 7;
|
|
|
|
default: return 0;
|
|
|
|
}
|
2022-07-20 01:33:16 +02:00
|
|
|
}
|
2022-07-21 20:36:20 +02:00
|
|
|
};
|
2022-07-20 01:33:16 +02:00
|
|
|
|
2022-07-21 23:45:04 +02:00
|
|
|
template <typename T>
|
|
|
|
struct LookupList : public OT::LookupList<T>
|
|
|
|
{
|
|
|
|
bool sanitize (const graph_t::vertex_t& vertex) const
|
|
|
|
{
|
|
|
|
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
|
|
|
|
if (vertex_len < OT::LookupList<T>::min_size) return false;
|
|
|
|
return vertex_len >= OT::LookupList<T>::item_size * this->len;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GSTAR : public OT::GSUBGPOS
|
|
|
|
{
|
|
|
|
static GSTAR* graph_to_gstar (graph_t& graph)
|
|
|
|
{
|
|
|
|
const auto& r = graph.root ();
|
|
|
|
|
|
|
|
GSTAR* gstar = (GSTAR*) r.obj.head;
|
2022-08-06 01:37:11 +02:00
|
|
|
if (!gstar || !gstar->sanitize (r))
|
2022-07-21 23:45:04 +02:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return gstar;
|
|
|
|
}
|
|
|
|
|
|
|
|
const void* get_lookup_list_field_offset () const
|
|
|
|
{
|
|
|
|
switch (u.version.major) {
|
2022-07-23 00:49:40 +02:00
|
|
|
case 1: return u.version1.get_lookup_list_offset ();
|
2022-10-29 19:15:03 +02:00
|
|
|
#ifndef HB_NO_BEYOND_64K
|
2022-07-23 00:49:40 +02:00
|
|
|
case 2: return u.version2.get_lookup_list_offset ();
|
2022-07-21 23:45:04 +02:00
|
|
|
#endif
|
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool sanitize (const graph_t::vertex_t& vertex)
|
|
|
|
{
|
|
|
|
int64_t len = vertex.obj.tail - vertex.obj.head;
|
2022-07-21 23:57:17 +02:00
|
|
|
if (len < OT::GSUBGPOS::min_size) return false;
|
|
|
|
return len >= get_size ();
|
2022-07-21 23:45:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void find_lookups (graph_t& graph,
|
|
|
|
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
|
|
|
|
{
|
2022-07-21 23:54:42 +02:00
|
|
|
switch (u.version.major) {
|
|
|
|
case 1: find_lookups<SmallTypes> (graph, lookups); break;
|
2022-10-29 19:15:03 +02:00
|
|
|
#ifndef HB_NO_BEYOND_64K
|
2022-07-21 23:54:42 +02:00
|
|
|
case 2: find_lookups<MediumTypes> (graph, lookups); break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 21:42:58 +02:00
|
|
|
unsigned get_lookup_list_index (graph_t& graph)
|
|
|
|
{
|
|
|
|
return graph.index_for_offset (graph.root_idx (),
|
|
|
|
get_lookup_list_field_offset());
|
|
|
|
}
|
|
|
|
|
2022-07-21 23:54:42 +02:00
|
|
|
template<typename Types>
|
|
|
|
void find_lookups (graph_t& graph,
|
|
|
|
hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
|
|
|
|
{
|
2022-07-25 21:42:58 +02:00
|
|
|
unsigned lookup_list_idx = get_lookup_list_index (graph);
|
2022-07-21 23:54:42 +02:00
|
|
|
const LookupList<Types>* lookupList =
|
|
|
|
(const LookupList<Types>*) graph.object (lookup_list_idx).head;
|
2022-08-06 01:37:11 +02:00
|
|
|
if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx]))
|
2022-07-21 23:45:04 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
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;
|
2022-08-06 01:37:11 +02:00
|
|
|
if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue;
|
2022-07-21 23:45:04 +02:00
|
|
|
lookups.set (lookup_idx, lookup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-07-20 01:33:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* GRAPH_GSUBGPOS_GRAPH_HH */
|