Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/gfx/harfbuzz/src/graph/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 23 kB image not shown  

Quelle  pairpos-graph.hh   Sprache: C

 
/*
 * 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 "split-helpers.hh"
#include "coverage-graph.hh"
#include "classdef-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>
{
  bool sanitize (graph_t::vertex_t& vertex) const
  {
    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
    unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
    if (vertex_len < min_size) return false;
    hb_barrier ();

    return vertex_len >=
        min_size + pairSet.get_size () - pairSet.len.get_size();
  }

  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
                                         unsigned parent_index,
                                         unsigned this_index)
  {
    hb_set_t visited;

    const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
    const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
    const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;

    unsigned partial_coverage_size = 4;
    unsigned accumulated = base_size;
    hb_vector_t<unsigned> split_points;
    for (unsigned i = 0; i < pairSet.len; i++)
    {
      unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
      unsigned accumulated_delta =
          c.graph.find_subgraph_size (pair_set_index, visited) +
          SmallTypes::size; // for PairSet offset.
      partial_coverage_size += OT::HBUINT16::static_size;

      accumulated += accumulated_delta;
      unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size);

      if (total >= (1 << 16))
      {
        split_points.push (i);
        accumulated = base_size + accumulated_delta;
        partial_coverage_size = 6;
        visited.clear (); // node sharing isn't allowed between splits.
      }
    }

    split_context_t split_context {
      c,
      this,
      c.graph.duplicate_if_shared (parent_index, this_index),
    };

    return actuate_subtable_split<split_context_t> (split_context, split_points);
  }

 private:

  struct split_context_t {
    gsubgpos_graph_context_t& c;
    PairPosFormat1* thiz;
    unsigned this_index;

    unsigned original_count ()
    {
      return thiz->pairSet.len;
    }

    unsigned clone_range (unsigned start, unsigned end)
    {
      return thiz->clone_range (this->c, this->this_index, start, end);
    }

    bool shrink (unsigned count)
    {
      return thiz->shrink (this->c, this->this_index, count);
    }
  };

  bool shrink (gsubgpos_graph_context_t& c,
               unsigned this_index,
               unsigned count)
  {
    DEBUG_MSG (SUBSET_REPACK, nullptr,
               " Shrinking PairPosFormat1 (%u) to [0, %u).",
               this_index,
               count);
    unsigned old_count = pairSet.len;
    if (count >= old_count)
      return true;

    pairSet.len = count;
    c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;

    auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
    if (!coverage) return false;

    unsigned coverage_size = coverage.vertex->table_size ();
    auto new_coverage =
        + hb_zip (coverage.table->iter (), hb_range ())
        | hb_filter ([&] (hb_pair_t<unsignedunsigned> p) {
          return p.second < count;
        })
        | hb_map_retains_sorting (hb_first)
        ;

    return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
  }

  // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
  // Returns object id of the new object.
  unsigned clone_range (gsubgpos_graph_context_t& c,
                        unsigned this_index,
                        unsigned start, unsigned end) const
  {
    DEBUG_MSG (SUBSET_REPACK, nullptr,
               " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end);

    unsigned num_pair_sets = end - start;
    unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
                          + num_pair_sets * SmallTypes::size;

    unsigned pair_pos_prime_id = c.create_node (prime_size);
    if (pair_pos_prime_id == (unsigned) -1) return -1;

    PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
    pair_pos_prime->format = this->format;
    pair_pos_prime->valueFormat[0] = this->valueFormat[0];
    pair_pos_prime->valueFormat[1] = this->valueFormat[1];
    pair_pos_prime->pairSet.len = num_pair_sets;

    for (unsigned i = start; i < end; i++)
    {
      c.graph.move_child<> (this_index,
                            &pairSet[i],
                            pair_pos_prime_id,
                            &pair_pos_prime->pairSet[i - start]);
    }

    unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
    if (!Coverage::clone_coverage (c,
                                   coverage_id,
                                   pair_pos_prime_id,
                                   2,
                                   start, end))
      return -1;

    return pair_pos_prime_id;
  }



  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 sanitize (graph_t::vertex_t& vertex) const
  {
    size_t vertex_len = vertex.table_size ();
    unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
    if (vertex_len < min_size) return false;
    hb_barrier ();

    const unsigned class1_count = class1Count;
    return vertex_len >=
        min_size + class1_count * get_class1_record_size ();
  }

  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
                                         unsigned parent_index,
                                         unsigned this_index)
  {
    const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
    const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
    const Coverage* coverage = get_coverage (c, this_index);
    const ClassDef* class_def_1 = get_class_def_1 (c, this_index);
    auto gid_and_class =
        + coverage->iter ()
        | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
          return hb_codepoint_pair_t (gid, class_def_1->get_class (gid));
        })
        ;
    class_def_size_estimator_t estimator (gid_and_class);

    const unsigned class1_count = class1Count;
    const unsigned class2_count = class2Count;
    const unsigned class1_record_size = get_class1_record_size ();

    const unsigned value_1_len = valueFormat1.get_len ();
    const unsigned value_2_len = valueFormat2.get_len ();
    const unsigned total_value_len = value_1_len + value_2_len;

    unsigned accumulated = base_size;
    unsigned coverage_size = 4;
    unsigned class_def_1_size = 4;
    unsigned max_coverage_size = coverage_size;
    unsigned max_class_def_1_size = class_def_1_size;

    hb_vector_t<unsigned> split_points;

    hb_hashmap_t<unsignedunsigned> device_tables = get_all_device_tables (c, this_index);
    hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices ();
    hb_vector_t<unsigned> 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++)
    {
      unsigned accumulated_delta = class1_record_size;
      class_def_1_size = estimator.add_class_def_size (i);
      coverage_size = estimator.coverage_size ();
      max_coverage_size = hb_max (max_coverage_size, coverage_size);
      max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);

      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_delta += size_of_value_record_children (c,
                                                        device_tables,
                                                        format1_device_table_indices,
                                                        value1_index,
                                                        visited);
          accumulated_delta += size_of_value_record_children (c,
                                                        device_tables,
                                                        format2_device_table_indices,
                                                        value2_index,
                                                        visited);
        }
      }

      accumulated += accumulated_delta;
      unsigned total = accumulated
                       + coverage_size + class_def_1_size + class_def_2_size
                       // The largest object will pack last and can exceed the size limit.
                       - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size);
      if (total >= (1 << 16))
      {
        split_points.push (i);
        // split does not include i, so add the size for i when we reset the size counters.
        accumulated = base_size + accumulated_delta;

        estimator.reset();
        class_def_1_size = estimator.add_class_def_size(i);
        coverage_size = estimator.coverage_size();
        visited.clear (); // node sharing isn't allowed between splits.
      }
    }

    split_context_t split_context {
      c,
      this,
      c.graph.duplicate_if_shared (parent_index, this_index),
      class1_record_size,
      total_value_len,
      value_1_len,
      value_2_len,
      max_coverage_size,
      max_class_def_1_size,
      device_tables,
      format1_device_table_indices,
      format2_device_table_indices
    };

    return actuate_subtable_split<split_context_t> (split_context, split_points);
  }
 private:

  struct split_context_t
  {
    gsubgpos_graph_context_t& c;
    PairPosFormat2* thiz;
    unsigned this_index;
    unsigned class1_record_size;
    unsigned value_record_len;
    unsigned value1_record_len;
    unsigned value2_record_len;
    unsigned max_coverage_size;
    unsigned max_class_def_size;

    const hb_hashmap_t<unsignedunsigned>& device_tables;
    const hb_vector_t<unsigned>& format1_device_table_indices;
    const hb_vector_t<unsigned>& format2_device_table_indices;

    unsigned original_count ()
    {
      return thiz->class1Count;
    }

    unsigned clone_range (unsigned start, unsigned end)
    {
      return thiz->clone_range (*this, start, end);
    }

    bool shrink (unsigned count)
    {
      return thiz->shrink (*this, count);
    }
  };

  size_t get_class1_record_size () const
  {
    const size_t class2_count = class2Count;
    return
        class2_count * (valueFormat1.get_size () + valueFormat2.get_size ());
  }

  unsigned clone_range (split_context_t& split_context,
                        unsigned start, unsigned end) const
  {
    DEBUG_MSG (SUBSET_REPACK, nullptr,
               " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end);

    graph_t& graph = split_context.c.graph;

    unsigned num_records = end - start;
    unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size
                          + num_records * split_context.class1_record_size;

    unsigned pair_pos_prime_id = split_context.c.create_node (prime_size);
    if (pair_pos_prime_id == (unsigned) -1) return -1;

    PairPosFormat2* pair_pos_prime =
        (PairPosFormat2*) graph.object (pair_pos_prime_id).head;
    pair_pos_prime->format = this->format;
    pair_pos_prime->valueFormat1 = this->valueFormat1;
    pair_pos_prime->valueFormat2 = this->valueFormat2;
    pair_pos_prime->class1Count = num_records;
    pair_pos_prime->class2Count = this->class2Count;
    clone_class1_records (split_context,
                          pair_pos_prime_id,
                          start,
                          end);

    unsigned coverage_id =
        graph.index_for_offset (split_context.this_index, &coverage);
    unsigned class_def_1_id =
        graph.index_for_offset (split_context.this_index, &classDef1);
    auto& coverage_v = graph.vertices_[coverage_id];
    auto& class_def_1_v = graph.vertices_[class_def_1_id];
    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
    ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
    if (!coverage_table
        || !coverage_table->sanitize (coverage_v)
        || !class_def_1_table
        || !class_def_1_table->sanitize (class_def_1_v))
      return -1;

    auto klass_map =
    + coverage_table->iter ()
    | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
      return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid));
    })
    | hb_filter ([&] (hb_codepoint_t klass) {
      return klass >= start && klass < end;
    }, hb_second)
    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) {
      // Classes must be from 0...N so subtract start
      return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start);
    })
    ;

    if (!Coverage::add_coverage (split_context.c,
                                 pair_pos_prime_id,
                                 2,
                                 + klass_map | hb_map_retains_sorting (hb_first),
                                 split_context.max_coverage_size))
      return -1;

    // classDef1
    if (!ClassDef::add_class_def (split_context.c,
                                  pair_pos_prime_id,
                                  8,
                                  + klass_map,
                                  split_context.max_class_def_size))
      return -1;

    // classDef2
    unsigned class_def_2_id =
        graph.index_for_offset (split_context.this_index, &classDef2);
    auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
    class_def_link->width = SmallTypes::size;
    class_def_link->objidx = class_def_2_id;
    class_def_link->position = 10;
    graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id);
    graph.duplicate (pair_pos_prime_id, class_def_2_id);

    return pair_pos_prime_id;
  }

  void clone_class1_records (split_context_t& split_context,
                             unsigned pair_pos_prime_id,
                             unsigned start, unsigned end) const
  {
    PairPosFormat2* pair_pos_prime =
        (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;

    char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size;
    unsigned num_records = end - start;
    hb_memcpy (&pair_pos_prime->values[0],
            start_addr,
            num_records * split_context.class1_record_size);

    if (!split_context.format1_device_table_indices
        && !split_context.format2_device_table_indices)
      // No device tables to move over.
      return;

    unsigned class2_count = class2Count;
    for (unsigned i = start; i < end; i++)
    {
      for (unsigned j = 0; j < class2_count; j++)
      {
        unsigned value1_index = split_context.value_record_len * (class2_count * i + j);
        unsigned value2_index = value1_index + split_context.value1_record_len;

        unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j);
        unsigned new_value2_index = new_value1_index + split_context.value1_record_len;

        transfer_device_tables (split_context,
                                pair_pos_prime_id,
                                split_context.format1_device_table_indices,
                                value1_index,
                                new_value1_index);

        transfer_device_tables (split_context,
                                pair_pos_prime_id,
                                split_context.format2_device_table_indices,
                                value2_index,
                                new_value2_index);
      }
    }
  }

  void transfer_device_tables (split_context_t& split_context,
                               unsigned pair_pos_prime_id,
                               const hb_vector_t<unsigned>& device_table_indices,
                               unsigned old_value_record_index,
                               unsigned new_value_record_index) const
  {
    PairPosFormat2* pair_pos_prime =
        (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;

    for (unsigned i : device_table_indices)
    {
      OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i];
      unsigned record_position = ((char*) record) - ((char*) this);
      if (!split_context.device_tables.has (record_position)) continue;

      split_context.c.graph.move_child (
          split_context.this_index,
          record,
          pair_pos_prime_id,
          (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]);
    }
  }

  bool shrink (split_context_t& split_context,
               unsigned count)
  {
    DEBUG_MSG (SUBSET_REPACK, nullptr,
               " Shrinking PairPosFormat2 (%u) to [0, %u).",
               split_context.this_index,
               count);
    unsigned old_count = class1Count;
    if (count >= old_count)
      return true;

    graph_t& graph = split_context.c.graph;
    class1Count = count;
    graph.vertices_[split_context.this_index].obj.tail -=
        (old_count - count) * split_context.class1_record_size;

    auto coverage =
        graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
    if (!coverage) return false;

    auto class_def_1 =
        graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
    if (!class_def_1) return false;

    auto klass_map =
    + coverage.table->iter ()
    | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
      return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid));
    })
    | hb_filter ([&] (hb_codepoint_t klass) {
      return klass < count;
    }, hb_second)
    ;

    auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
    if (!Coverage::make_coverage (split_context.c,
                                  + new_coverage,
                                  coverage.index,
                                  // existing ranges my not be kept, worst case size is a format 1
                                  // coverage table.
                                  4 + new_coverage.len() * 2))
      return false;

    return ClassDef::make_class_def (split_context.c,
                                     + klass_map,
                                     class_def_1.index,
                                     class_def_1.vertex->table_size ());
  }

  hb_hashmap_t<unsignedunsigned>
  get_all_device_tables (gsubgpos_graph_context_t& c,
                         unsigned this_index) const
  {
    const auto& v = c.graph.vertices_[this_index];
    return v.position_to_index_map ();
  }

  const Coverage* get_coverage (gsubgpos_graph_context_t& c,
                          unsigned this_index) const
  {
    unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
    auto& coverage_v = c.graph.vertices_[coverage_id];

    Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
    if (!coverage_table || !coverage_table->sanitize (coverage_v))
      return &Null(Coverage);
    return coverage_table;
  }

  const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c,
                                   unsigned this_index) const
  {
    unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1);
    auto& class_def_1_v = c.graph.vertices_[class_def_1_id];

    ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
    if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v))
      return &Null(ClassDef);
    return class_def_1_table;
  }

  unsigned size_of_value_record_children (gsubgpos_graph_context_t& c,
                                          const hb_hashmap_t<unsignedunsigned>& device_tables,
                                          const hb_vector_t<unsigned> device_table_indices,
                                          unsigned value_record_index,
                                          hb_set_t& visited)
  {
    unsigned size = 0;
    for (unsigned i : device_table_indices)
    {
      OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i];
      unsigned record_position = ((char*) record) - ((char*) this);
      unsigned* obj_idx;
      if (!device_tables.has (record_position, &obj_idx)) continue;
      size += c.graph.find_subgraph_size (*obj_idx, visited);
    }
    return size;
  }

  unsigned size_of (gsubgpos_graph_context_t& c,
                    unsigned this_index,
                    const void* offset) const
  {
    const unsigned id = c.graph.index_for_offset (this_index, offset);
    return c.graph.vertices_[id].table_size ();
  }
};

struct PairPos : public OT::Layout::GPOS_impl::PairPos
{
  hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
                                         unsigned parent_index,
                                         unsigned this_index)
  {
    switch (u.format) {
    case 1:
      return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
    case 2:
      return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
#ifndef HB_NO_BEYOND_64K
    case 3: HB_FALLTHROUGH;
    case 4: HB_FALLTHROUGH;
      // Don't split 24bit PairPos's.
#endif
    default:
      return hb_vector_t<unsigned> ();
    }
  }

  bool sanitize (graph_t::vertex_t& vertex) const
  {
    int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
    if (vertex_len < u.format.get_size ()) return false;
    hb_barrier ();

    switch (u.format) {
    case 1:
      return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
    case 2:
      return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
#ifndef HB_NO_BEYOND_64K
    case 3: HB_FALLTHROUGH;
    case 4: HB_FALLTHROUGH;
#endif
    default:
      // We don't handle format 3 and 4 here.
      return false;
    }
  }
};

}

#endif  // GRAPH_PAIRPOS_GRAPH_HH

Messung V0.5
C=97 H=96 G=96

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.