diff --git a/src/OT/Layout/GPOS/ValueFormat.hh b/src/OT/Layout/GPOS/ValueFormat.hh index 8a653e7ee..38758a163 100644 --- a/src/OT/Layout/GPOS/ValueFormat.hh +++ b/src/OT/Layout/GPOS/ValueFormat.hh @@ -59,13 +59,22 @@ struct ValueFormat : HBUINT16 unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } unsigned int get_size () const { return get_len () * Value::static_size; } - bool has_offsets () const { + hb_vector_t get_device_table_indices () const { + unsigned i = 0; + hb_vector_t result; unsigned format = *this; - return format & ( - xPlaDevice | - yPlaDevice | - xAdvDevice | - yAdvDevice ); + + if (format & xPlacement) i++; + if (format & yPlacement) i++; + if (format & xAdvance) i++; + if (format & yAdvance) i++; + + if (format & xPlaDevice) result.push (i++); + if (format & yPlaDevice) result.push (i++); + if (format & xAdvDevice) result.push (i++); + if (format & yAdvDevice) result.push (i++); + + return result; } bool apply_value (hb_ot_apply_context_t *c, diff --git a/src/graph/pairpos-graph.hh b/src/graph/pairpos-graph.hh index e8dd0d954..acd6148ea 100644 --- a/src/graph/pairpos-graph.hh +++ b/src/graph/pairpos-graph.hh @@ -250,8 +250,6 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_subtables (gsubgpos_graph_context_t& c, unsigned this_index) { // TODO(garretrieger): sanitization. - hb_set_t visited; - const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size + size_of (c, this_index, &coverage) + size_of (c, this_index, &classDef1) @@ -261,31 +259,36 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 split_points; + + hb_hashmap_t device_tables = get_all_device_tables (c, this_index); + hb_vector_t format1_device_table_indices = valueFormat1.get_device_table_indices (); + hb_vector_t format2_device_table_indices = valueFormat2.get_device_table_indices (); + bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices); + + hb_set_t visited; for (unsigned i = 0; i < class1_count; i++) { accumulated += class1_record_size; - if (has_offsets) { + if (has_device_tables) { for (unsigned j = 0; j < class2_count; j++) { unsigned value1_index = total_value_len * (class2_count * i + j); unsigned value2_index = value1_index + value_1_len; - accumulated += size_of_value_record_children (c, - this_index, - valueFormat1, + device_tables, + format1_device_table_indices, value1_index, visited); accumulated += size_of_value_record_children (c, - this_index, - valueFormat2, + device_tables, + format2_device_table_indices, value2_index, visited); } @@ -315,19 +318,35 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 (); } + hb_hashmap_t + get_all_device_tables (gsubgpos_graph_context_t& c, + unsigned this_index) const + { + hb_hashmap_t result; + + const auto& o = c.graph.object (this_index); + for (const auto& l : o.real_links) { + result.set ((void*) (((uint8_t*)this) + l.position), l.objidx); + } + + return result; + } + unsigned size_of_value_record_children (gsubgpos_graph_context_t& c, - unsigned this_index, - unsigned format, + const hb_hashmap_t& device_tables, + const hb_vector_t device_table_indices, unsigned value_record_index, hb_set_t& visited) { - // TODO(garretrieger): implement me, walk through flags and recurse for each offset - // found. - // Actually may be better to just walk the offsets on the vertex directly. ie. prescan - // all of the links and exclude those for coverage, classDef1/2 and then sort by position. - // then we know how many offsets each valueFormat1 and valueFormat2 consume, then we can just - // grab that many offsets and recurse on each iteration. - return 0; + unsigned size = 0; + for (unsigned i : device_table_indices) + { + OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i]; + unsigned* obj_idx; + if (!device_tables.has ((void*) record, &obj_idx)) continue; + size += c.graph.find_subgraph_size (*obj_idx, visited); + } + return size; } unsigned size_of (gsubgpos_graph_context_t& c,