diff --git a/src/Makefile.sources b/src/Makefile.sources index a3fb92bac..14c6ed346 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -353,6 +353,7 @@ HB_SUBSET_sources = \ graph/gsubgpos-context.cc \ graph/pairpos-graph.hh \ graph/coverage-graph.hh \ + graph/classdef-graph.hh \ graph/pairpos-graph.hh \ graph/serialize.hh \ $(NULL) diff --git a/src/graph/classdef-graph.hh b/src/graph/classdef-graph.hh new file mode 100644 index 000000000..e81cd6ec4 --- /dev/null +++ b/src/graph/classdef-graph.hh @@ -0,0 +1,141 @@ +/* + * 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-common.hh" + +#ifndef GRAPH_CLASSDEF_GRAPH_HH +#define GRAPH_CLASSDEF_GRAPH_HH + +namespace graph { + +struct ClassDefFormat1 : public OT::ClassDefFormat1_3 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size (); + } +}; + +struct ClassDefFormat2 : public OT::ClassDefFormat2_4 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); + } +}; + +struct ClassDef : public OT::ClassDef +{ + template + static bool clone_class_def (gsubgpos_graph_context_t& c, + unsigned class_def_id, + unsigned new_parent_id, + unsigned link_position, + It glyphs) + { + unsigned class_def_size = c.graph.vertices_[class_def_id].table_size (); + auto& class_def_v = c.graph.vertices_[class_def_id]; + ClassDef* class_def_table = (ClassDef*) class_def_v.obj.head; + if (!class_def_table->sanitize (class_def_v)) + return false; + + auto new_class_def = + + glyphs + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair (gid, class_def_table[gid]); + }) + ; + + unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr); + auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id]; + if (!make_class_def (c, new_class_def, class_def_prime_id, class_def_size)) + return false; + + auto* class_def_link = c.graph.vertices_[new_parent_id].obj.real_links.push (); + class_def_link->width = SmallTypes::size; + class_def_link->objidx = class_def_prime_id; + class_def_link->position = link_position; + class_def_prime_vertex.parents.push (new_parent_id); + + return true; + } + + template + static bool make_class_def (gsubgpos_graph_context_t& c, + It glyph_and_class, + unsigned dest_obj, + unsigned max_size) + { + char* buffer = (char*) hb_calloc (1, max_size); + hb_serialize_context_t serializer (buffer, max_size); + ClassDef_serialize (&serializer, glyph_and_class); + serializer.end_serialize (); + if (serializer.in_error ()) + { + hb_free (buffer); + return false; + } + + hb_bytes_t class_def_copy = serializer.copy_bytes (); + c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + + auto& obj = c.graph.vertices_[dest_obj].obj; + obj.head = (char *) class_def_copy.arrayZ; + obj.tail = obj.head + class_def_copy.length; + + hb_free (buffer); + return true; + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < OT::ClassDef::min_size) return false; + switch (u.format) + { + case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); + case 2: return ((ClassDefFormat2*)this)->sanitize (vertex); +#ifndef HB_NO_BORING_EXPANSION + // Not currently supported + case 3: + case 4: +#endif + default: return false; + } + } +}; + + +} + +#endif // GRAPH_CLASSDEF_GRAPH_HH diff --git a/src/graph/coverage-graph.hh b/src/graph/coverage-graph.hh index c18b4f112..28ceed945 100644 --- a/src/graph/coverage-graph.hh +++ b/src/graph/coverage-graph.hh @@ -85,7 +85,7 @@ struct Coverage : public OT::Layout::Common::Coverage auto* coverage_link = c.graph.vertices_[new_parent_id].obj.real_links.push (); coverage_link->width = SmallTypes::size; coverage_link->objidx = coverage_prime_id; - coverage_link->position = 2; + coverage_link->position = link_position; coverage_prime_vertex.parents.push (new_parent_id); return true; diff --git a/src/graph/pairpos-graph.hh b/src/graph/pairpos-graph.hh index dce38cd6b..d52d3bb09 100644 --- a/src/graph/pairpos-graph.hh +++ b/src/graph/pairpos-graph.hh @@ -28,6 +28,7 @@ #define GRAPH_PAIRPOS_GRAPH_HH #include "coverage-graph.hh" +#include "classdef-graph.hh" #include "../OT/Layout/GPOS/PairPos.hh" #include "../OT/Layout/GPOS/PosLookupSubTable.hh" @@ -308,10 +309,19 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4class2Count = this->class2Count; clone_class1_records (split_context, pair_pos_prime, start, end); + unsigned coverage_id = + split_context.c.graph.index_for_offset (split_context.this_index, &coverage); + if (!Coverage::clone_coverage (split_context.c, + coverage_id, + pair_pos_prime_id, + 2, + start, end)) + return -1; + // TODO: class def 1 (clone_classdef (start, end)) + // TODO: class def 2 (just link to existing) - // TODO - return -1; + return -1; // TODO } void clone_class1_records (split_context& split_context, diff --git a/src/meson.build b/src/meson.build index 1f1105cae..2118eb57c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -350,6 +350,7 @@ hb_subset_sources = files( 'graph/gsubgpos-graph.hh', 'graph/pairpos-graph.hh', 'graph/coverage-graph.hh', + 'graph/classdef-graph.hh', 'hb-subset.cc', 'hb-subset.hh', )