diff mupdf-source/thirdparty/harfbuzz/src/hb-ot-stat-table.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/harfbuzz/src/hb-ot-stat-table.hh	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,618 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  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.
+ */
+
+#ifndef HB_OT_STAT_TABLE_HH
+#define HB_OT_STAT_TABLE_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
+
+/*
+ * STAT -- Style Attributes
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/stat
+ */
+#define HB_OT_TAG_STAT HB_TAG('S','T','A','T')
+
+
+namespace OT {
+
+enum
+{
+  OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001,	/* If set, this axis value table
+						 * provides axis value information
+						 * that is applicable to other fonts
+						 * within the same font family. This
+						 * is used if the other fonts were
+						 * released earlier and did not include
+						 * information about values for some axis.
+						 * If newer versions of the other
+						 * fonts include the information
+						 * themselves and are present,
+						 * then this record is ignored. */
+  ELIDABLE_AXIS_VALUE_NAME = 0x0002		/* If set, it indicates that the axis
+						 * value represents the “normal” value
+						 * for the axis and may be omitted when
+						 * composing name strings. */
+  // Reserved = 0xFFFC				/* Reserved for future use — set to zero. */
+};
+
+struct StatAxisRecord
+{
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+  hb_ot_name_id_t get_name_id () const { return nameID; }
+
+  hb_tag_t get_axis_tag () const { return tag; }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  protected:
+  Tag		tag;		/* A tag identifying the axis of design variation. */
+  NameID	nameID;		/* The name ID for entries in the 'name' table that
+				 * provide a display string for this axis. */
+  HBUINT16	ordering;	/* A value that applications can use to determine
+				 * primary sorting of face names, or for ordering
+				 * of descriptors when composing family or face names. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct AxisValueFormat1
+{
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    if (!user_axes_location->has (axis_tag) ||
+        fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+      return true;
+
+    return false;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float>*  user_axes_location = c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier — set to 1. */
+  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
+				 * identifying the axis of design variation
+				 * to which the axis value record applies.
+				 * Must be less than designAxisCount. */
+  HBUINT16	flags;		/* Flags — see below for details. */
+  NameID	valueNameID;	/* The name ID for entries in the 'name' table
+				 * that provide a display string for this
+				 * attribute value. */
+  F16DOT16	value;		/* A numeric value for this attribute value. */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct AxisValueFormat2
+{
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return nominalValue.to_float (); }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    if (!user_axes_location->has (axis_tag) ||
+        fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+      return true;
+
+    return false;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float>*  user_axes_location = c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier — set to 2. */
+  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
+				 * identifying the axis of design variation
+				 * to which the axis value record applies.
+				 * Must be less than designAxisCount. */
+  HBUINT16	flags;		/* Flags — see below for details. */
+  NameID	valueNameID;	/* The name ID for entries in the 'name' table
+				 * that provide a display string for this
+				 * attribute value. */
+  F16DOT16	nominalValue;	/* A numeric value for this attribute value. */
+  F16DOT16	rangeMinValue;	/* The minimum value for a range associated
+				 * with the specified name ID. */
+  F16DOT16	rangeMaxValue;	/* The maximum value for a range associated
+				 * with the specified name ID. */
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+struct AxisValueFormat3
+{
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
+  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    unsigned axis_idx = get_axis_index ();
+    return axis_records[axis_idx].get_axis_tag ();
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_tag_t axis_tag = get_axis_tag (axis_records);
+    float axis_value = get_value ();
+
+    if (!user_axes_location->has (axis_tag) ||
+        fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
+      return true;
+
+    return false;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location;
+
+    if (keep_axis_value (axis_records, user_axes_location))
+      return_trace (c->serializer->embed (this));
+
+    return_trace (false);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier — set to 3. */
+  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
+				 * identifying the axis of design variation
+				 * to which the axis value record applies.
+				 * Must be less than designAxisCount. */
+  HBUINT16	flags;		/* Flags — see below for details. */
+  NameID	valueNameID;	/* The name ID for entries in the 'name' table
+				 * that provide a display string for this
+				 * attribute value. */
+  F16DOT16	value;		/* A numeric value for this attribute value. */
+  F16DOT16	linkedValue;	/* The numeric value for a style-linked mapping
+				 * from this value. */
+  public:
+  DEFINE_SIZE_STATIC (16);
+};
+
+struct AxisValueRecord
+{
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
+				 * identifying the axis to which this value
+				 * applies. Must be less than designAxisCount. */
+  F16DOT16	value;		/* A numeric value for this attribute value. */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct AxisValueFormat4
+{
+  const AxisValueRecord &get_axis_record (unsigned int axis_index) const
+  { return axisValues.as_array (axisCount)[axis_index]; }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
+
+    for (const auto& rec : axis_value_records)
+    {
+      unsigned axis_idx = rec.get_axis_index ();
+      float axis_value = rec.get_value ();
+      hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
+
+      if (user_axes_location->has (axis_tag) &&
+          fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f)
+        return false;
+    }
+
+    return true;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    const hb_hashmap_t<hb_tag_t, float> *user_axes_location = c->plan->user_axes_location;
+    if (!keep_axis_value (axis_records, user_axes_location))
+      return_trace (false);
+
+    unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
+    auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
+    if (unlikely (!out)) return_trace (false);
+    hb_memcpy (out, this, total_size);
+    return_trace (true);
+  }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+                          axisValues.sanitize (c, axisCount)));
+  }
+
+  protected:
+  HBUINT16	format;		/* Format identifier — set to 4. */
+  HBUINT16	axisCount;	/* The total number of axes contributing to
+				 * this axis-values combination. */
+  HBUINT16	flags;		/* Flags — see below for details. */
+  NameID	valueNameID;	/* The name ID for entries in the 'name' table
+				 * that provide a display string for this
+				 * attribute value. */
+  UnsizedArrayOf<AxisValueRecord>
+		axisValues;	/* Array of AxisValue records that provide the
+				 * combination of axis values, one for each
+				 * contributing axis. */
+  public:
+  DEFINE_SIZE_ARRAY (8, axisValues);
+};
+
+struct AxisValue
+{
+  bool get_value (unsigned int axis_index) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_value ();
+    case 2: return u.format2.get_value ();
+    case 3: return u.format3.get_value ();
+    case 4: return u.format4.get_axis_record (axis_index).get_value ();
+    default:return 0;
+    }
+  }
+
+  unsigned int get_axis_index () const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_axis_index ();
+    case 2: return u.format2.get_axis_index ();
+    case 3: return u.format3.get_axis_index ();
+    /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
+    default:return -1;
+    }
+  }
+
+  hb_ot_name_id_t get_value_name_id () const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_value_name_id ();
+    case 2: return u.format2.get_value_name_id ();
+    case 3: return u.format3.get_value_name_id ();
+    case 4: return u.format4.get_value_name_id ();
+    default:return HB_OT_NAME_ID_INVALID;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
+                        hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
+    case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
+    case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
+    case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
+    default:return false;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (u.format)
+    {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union
+  {
+  HBUINT16		format;
+  AxisValueFormat1	format1;
+  AxisValueFormat2	format2;
+  AxisValueFormat3	format3;
+  AxisValueFormat4	format4;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
+{
+  bool subset (hb_subset_context_t *c,
+               unsigned axisValueCount,
+               unsigned& count,
+               const hb_array_t<const StatAxisRecord> axis_records) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto axisValueOffsets = as_array (axisValueCount);
+    count = 0;
+    for (const auto& offset : axisValueOffsets)
+    {
+      if (!offset) continue;
+      auto o_snap = c->serializer->snapshot ();
+      auto *o = c->serializer->embed (offset);
+      if (!o) return_trace (false);
+      if (!o->serialize_subset (c, offset, this, axis_records))
+      {
+        c->serializer->revert (o_snap);
+        continue;
+      }
+      count++;
+    }
+
+    return_trace (count);
+  }
+};
+
+struct STAT
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
+
+  bool has_data () const { return version.to_int (); }
+
+  bool get_value (hb_tag_t tag, float *value) const
+  {
+    unsigned int axis_index;
+    if (!get_design_axes ().lfind (tag, &axis_index)) return false;
+
+    hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
+    for (unsigned int i = 0; i < axis_values.length; i++)
+    {
+      const AxisValue& axis_value = this+axis_values[i];
+      if (axis_value.get_axis_index () == axis_index)
+      {
+	if (value)
+	  *value = axis_value.get_value (axis_index);
+	return true;
+      }
+    }
+    return false;
+  }
+
+  unsigned get_design_axis_count () const { return designAxisCount; }
+
+  hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
+  {
+    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
+    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
+    return axis_record.get_name_id ();
+  }
+
+  unsigned get_axis_value_count () const { return axisValueCount; }
+
+  hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
+  {
+    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
+    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
+    return axis_value.get_value_name_id ();
+  }
+
+  void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+                         hb_set_t *nameids_to_retain /* OUT */) const
+  {
+    if (!has_data ()) return;
+
+    + get_design_axes ()
+    | hb_map (&StatAxisRecord::get_name_id)
+    | hb_sink (nameids_to_retain)
+    ;
+
+    auto designAxes = get_design_axes ();
+
+    + get_axis_value_offsets ()
+    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
+    | hb_filter ([&] (const AxisValue& _)
+                 { return _.keep_axis_value (designAxes, user_axes_location); })
+    | hb_map (&AxisValue::get_value_name_id)
+    | hb_sink (nameids_to_retain)
+    ;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    STAT *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto designAxes = get_design_axes ();
+    for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
+      if (unlikely (!c->serializer->embed (designAxes[i])))
+          return_trace (false);
+
+    if (designAxisCount)
+      c->serializer->check_assign (out->designAxesOffset, this->get_size (),
+                                   HB_SERIALIZE_ERROR_INT_OVERFLOW);
+
+    unsigned count = 0;
+    out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
+                                                    axisValueCount, count, designAxes);
+    return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  version.major == 1 &&
+			  version.minor > 0 &&
+			  designAxesOffset.sanitize (c, this, designAxisCount) &&
+			  offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
+  }
+
+  protected:
+  hb_array_t<const StatAxisRecord> const get_design_axes () const
+  { return (this+designAxesOffset).as_array (designAxisCount); }
+
+  hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
+  { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
+
+
+  protected:
+  FixedVersion<>version;	/* Version of the stat table
+				 * initially set to 0x00010002u */
+  HBUINT16	designAxisSize;	/* The size in bytes of each axis record. */
+  HBUINT16	designAxisCount;/* The number of design axis records. In a
+				 * font with an 'fvar' table, this value must be
+				 * greater than or equal to the axisCount value
+				 * in the 'fvar' table. In all fonts, must
+				 * be greater than zero if axisValueCount
+				 * is greater than zero. */
+  NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
+		designAxesOffset;
+				/* Offset in bytes from the beginning of
+				 * the STAT table to the start of the design
+				 * axes array. If designAxisCount is zero,
+				 * set to zero; if designAxisCount is greater
+				 * than zero, must be greater than zero. */
+  HBUINT16	axisValueCount;	/* The number of axis value tables. */
+  NNOffset32To<AxisValueOffsetArray>
+		offsetToAxisValueOffsets;
+				/* Offset in bytes from the beginning of
+				 * the STAT table to the start of the design
+				 * axes value offsets array. If axisValueCount
+				 * is zero, set to zero; if axisValueCount is
+				 * greater than zero, must be greater than zero. */
+  NameID	elidedFallbackNameID;
+				/* Name ID used as fallback when projection of
+				 * names into a particular font model produces
+				 * a subfamily name containing only elidable
+				 * elements. */
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_STAT_TABLE_HH */