Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ot-glyf-table.hh
index dc7aa84..d62f24b 100644 (file)
 #define HB_OT_GLYF_TABLE_HH
 
 #include "hb-open-type-private.hh"
-
+#include "hb-ot-head-table.hh"
+#include "hb-subset-glyf.hh"
+#include "hb-subset-plan.hh"
+#include "hb-subset-private.hh"
 
 namespace OT {
 
@@ -42,6 +45,8 @@ namespace OT {
 
 struct loca
 {
+  friend struct glyf;
+
   static const hb_tag_t tableTag = HB_OT_TAG_loca;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -50,12 +55,9 @@ struct loca
     return_trace (true);
   }
 
-  public:
-  union {
-    USHORT     shortsZ[VAR];           /* Location offset divided by 2. */
-    ULONG      longsZ[VAR];            /* Location offset. */
-  } u;
-  DEFINE_SIZE_ARRAY (0, u.longsZ);
+  protected:
+  HBUINT8              dataX[VAR];             /* Location data. */
+  DEFINE_SIZE_ARRAY (0, dataX);
 };
 
 
@@ -78,24 +80,391 @@ struct glyf
     return_trace (true);
   }
 
-  public:
-  BYTE         dataX[VAR];             /* Glyphs data. */
+  inline bool subset (hb_subset_plan_t *plan) const
+  {
+    hb_blob_t *glyf_prime = nullptr;
+    hb_blob_t *loca_prime = nullptr;
 
-  DEFINE_SIZE_ARRAY (0, dataX);
-};
+    bool success = true;
+    bool use_short_loca = false;
+    if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
+      success = success && hb_subset_plan_add_table (plan, HB_OT_TAG_glyf, glyf_prime);
+      success = success && hb_subset_plan_add_table (plan, HB_OT_TAG_loca, loca_prime);
+      success = success && _add_head_and_set_loca_version (plan->source, use_short_loca, plan->dest);
+    } else {
+      success = false;
+    }
+    hb_blob_destroy (loca_prime);
+    hb_blob_destroy (glyf_prime);
 
-struct glyfGlyphHeader
-{
-  SHORT                numberOfContours;       /* If the number of contours is
-                                        * greater than or equal to zero,
-                                        * this is a simple glyph; if negative,
-                                        * this is a composite glyph. */
-  FWORD                xMin;                   /* Minimum x for coordinate data. */
-  FWORD                yMin;                   /* Minimum y for coordinate data. */
-  FWORD                xMax;                   /* Maximum x for coordinate data. */
-  FWORD                yMax;                   /* Maximum y for coordinate data. */
-
-  DEFINE_SIZE_STATIC (10);
+    return success;
+  }
+
+  static bool
+  _add_head_and_set_loca_version (hb_face_t *source, bool use_short_loca, hb_face_t *dest)
+  {
+    hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (hb_face_reference_table (source, HB_OT_TAG_head));
+    hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
+    hb_blob_destroy (head_blob);
+
+    if (unlikely (!head_prime_blob))
+      return false;
+
+    OT::head *head_prime = (OT::head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
+    head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
+    bool success = hb_subset_face_add_table (dest, HB_OT_TAG_head, head_prime_blob);
+
+    hb_blob_destroy (head_prime_blob);
+    return success;
+  }
+
+  struct GlyphHeader
+  {
+    HBINT16            numberOfContours;       /* If the number of contours is
+                                                 * greater than or equal to zero,
+                                                 * this is a simple glyph; if negative,
+                                                 * this is a composite glyph. */
+    FWORD              xMin;                   /* Minimum x for coordinate data. */
+    FWORD              yMin;                   /* Minimum y for coordinate data. */
+    FWORD              xMax;                   /* Maximum x for coordinate data. */
+    FWORD              yMax;                   /* Maximum y for coordinate data. */
+
+    DEFINE_SIZE_STATIC (10);
+  };
+
+  struct CompositeGlyphHeader
+  {
+    static const uint16_t ARG_1_AND_2_ARE_WORDS =      0x0001;
+    static const uint16_t ARGS_ARE_XY_VALUES =         0x0002;
+    static const uint16_t ROUND_XY_TO_GRID =           0x0004;
+    static const uint16_t WE_HAVE_A_SCALE =            0x0008;
+    static const uint16_t MORE_COMPONENTS =            0x0020;
+    static const uint16_t WE_HAVE_AN_X_AND_Y_SCALE =   0x0040;
+    static const uint16_t WE_HAVE_A_TWO_BY_TWO =       0x0080;
+    static const uint16_t WE_HAVE_INSTRUCTIONS =       0x0100;
+    static const uint16_t USE_MY_METRICS =             0x0200;
+    static const uint16_t OVERLAP_COMPOUND =           0x0400;
+    static const uint16_t SCALED_COMPONENT_OFFSET =    0x0800;
+    static const uint16_t UNSCALED_COMPONENT_OFFSET =  0x1000;
+
+    HBUINT16 flags;
+    HBUINT16 glyphIndex;
+
+    inline unsigned int get_size (void) const
+    {
+      unsigned int size = min_size;
+      if (flags & ARG_1_AND_2_ARE_WORDS) {
+        // arg1 and 2 are int16
+        size += 4;
+      } else {
+        // arg1 and 2 are int8
+        size += 2;
+      }
+      if (flags & WE_HAVE_A_SCALE) {
+        // One x 16 bit (scale)
+        size += 2;
+      } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+        // Two x 16 bit (xscale, yscale)
+        size += 4;
+      } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+        // Four x 16 bit (xscale, scale01, scale10, yscale)
+        size += 8;
+      }
+      return size;
+    }
+
+    struct Iterator
+    {
+      const char *glyph_start;
+      const char *glyph_end;
+      const CompositeGlyphHeader *current;
+
+      inline bool move_to_next ()
+      {
+       if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
+       {
+         const CompositeGlyphHeader *possible =
+           &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
+         if (!in_range (possible))
+           return false;
+         current = possible;
+         return true;
+       }
+       return false;
+      }
+
+      inline bool in_range (const CompositeGlyphHeader *composite) const
+      {
+       return (const char *) composite >= glyph_start
+         && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
+         && ((const char *) composite + composite->get_size()) <= glyph_end;
+      }
+    };
+
+    static inline bool get_iterator (const char * glyph_data,
+                                    unsigned int length,
+                                    CompositeGlyphHeader::Iterator *iterator /* OUT */)
+    {
+      if (length < GlyphHeader::static_size)
+       return false; /* Empty glyph; zero extents. */
+
+      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
+      if (glyph_header.numberOfContours < 0)
+      {
+        const CompositeGlyphHeader *possible =
+         &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
+
+       iterator->glyph_start = glyph_data;
+       iterator->glyph_end = (const char *) glyph_data + length;
+       if (!iterator->in_range (possible))
+          return false;
+        iterator->current = possible;
+        return true;
+      }
+
+      return false;
+    }
+
+    DEFINE_SIZE_MIN (4);
+  };
+
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head));
+      const head *head_table = Sanitizer<head>::lock_instance (head_blob);
+      if ((unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
+      {
+       /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+       hb_blob_destroy (head_blob);
+       return;
+      }
+      short_offset = 0 == head_table->indexToLocFormat;
+      hb_blob_destroy (head_blob);
+
+      loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca));
+      loca_table = Sanitizer<loca>::lock_instance (loca_blob);
+      glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
+      glyf_table = Sanitizer<glyf>::lock_instance (glyf_blob);
+
+      num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
+      glyf_len = hb_blob_get_length (glyf_blob);
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (loca_blob);
+      hb_blob_destroy (glyf_blob);
+    }
+
+    /*
+     * Returns true if the referenced glyph is a valid glyph and a composite glyph.
+     * If true is returned a pointer to the composite glyph will be written into
+     * composite.
+     */
+    inline bool get_composite (hb_codepoint_t glyph,
+                              CompositeGlyphHeader::Iterator *composite /* OUT */) const
+    {
+      unsigned int start_offset, end_offset;
+      if (!get_offsets (glyph, &start_offset, &end_offset))
+        return false; /* glyph not found */
+
+      return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset,
+                                                end_offset - start_offset,
+                                                composite);
+    }
+
+    /* based on FontTools _g_l_y_f.py::trim */
+    inline bool remove_padding(unsigned int start_offset,
+                               unsigned int *end_offset) const
+    {
+      static const int FLAG_X_SHORT = 0x02;
+      static const int FLAG_Y_SHORT = 0x04;
+      static const int FLAG_REPEAT = 0x08;
+      static const int FLAG_X_SAME = 0x10;
+      static const int FLAG_Y_SAME = 0x20;
+
+      if (*end_offset - start_offset < GlyphHeader::static_size)
+        return true;
+
+      const char *glyph = ((const char *) glyf_table) + start_offset;
+      const char * const glyph_end = glyph + (*end_offset - start_offset);
+      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0);
+      int16_t num_contours = (int16_t) glyph_header.numberOfContours;
+
+      if (num_contours < 0)
+        /* Trimming for composites not implemented.
+         * If removing hints it falls out of that. */
+        return true;
+      else if (num_contours > 0)
+      {
+        /* simple glyph w/contours, possibly trimmable */
+        glyph += GlyphHeader::static_size + 2 * num_contours;
+
+        if (unlikely (glyph + 2 >= glyph_end)) return false;
+        uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1;
+        uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0);
+
+        glyph += 2 + nInstructions;
+        if (unlikely (glyph + 2 >= glyph_end)) return false;
+
+        unsigned int coordBytes = 0;
+        unsigned int coordsWithFlags = 0;
+        while (glyph < glyph_end)
+        {
+          uint8_t flag = (uint8_t) *glyph;
+          glyph++;
+
+          unsigned int repeat = 1;
+          if (flag & FLAG_REPEAT)
+          {
+            if (glyph >= glyph_end)
+            {
+              DEBUG_MSG(SUBSET, nullptr, "Bad flag");
+              return false;
+            }
+            repeat = ((uint8_t) *glyph) + 1;
+            glyph++;
+          }
+
+          unsigned int xBytes, yBytes;
+          xBytes = yBytes = 0;
+          if (flag & FLAG_X_SHORT)
+            xBytes = 1;
+          else if ((flag & FLAG_X_SAME) == 0)
+            xBytes = 2;
+
+          if (flag & FLAG_Y_SHORT)
+            yBytes = 1;
+          else if ((flag & FLAG_Y_SAME) == 0)
+            yBytes = 2;
+
+          coordBytes += (xBytes + yBytes) * repeat;
+          coordsWithFlags += repeat;
+          if (coordsWithFlags >= nCoordinates)
+            break;
+        }
+
+        if (coordsWithFlags != nCoordinates)
+        {
+          DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags);
+          return false;
+        }
+        glyph += coordBytes;
+
+        if (glyph < glyph_end)
+          *end_offset -= glyph_end - glyph;
+      }
+      return true;
+    }
+
+    inline bool get_offsets (hb_codepoint_t  glyph,
+                             unsigned int   *start_offset /* OUT */,
+                             unsigned int   *end_offset   /* OUT */) const
+    {
+      if (unlikely (glyph >= num_glyphs))
+       return false;
+
+      if (short_offset)
+      {
+        const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataX;
+       *start_offset = 2 * offsets[glyph];
+       *end_offset   = 2 * offsets[glyph + 1];
+      }
+      else
+      {
+        const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataX;
+
+       *start_offset = offsets[glyph];
+       *end_offset   = offsets[glyph + 1];
+      }
+
+      if (*start_offset > *end_offset || *end_offset > glyf_len)
+       return false;
+
+      return true;
+    }
+
+    inline bool get_instruction_offsets(unsigned int start_offset,
+                                        unsigned int end_offset,
+                                        unsigned int *instruction_start /* OUT */,
+                                        unsigned int *instruction_end /* OUT */) const
+    {
+      if (end_offset - start_offset < GlyphHeader::static_size)
+      {
+        *instruction_start = 0;
+        *instruction_end = 0;
+        return true; /* Empty glyph; no instructions. */
+      }
+      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
+      int16_t num_contours = (int16_t) glyph_header.numberOfContours;
+      if (num_contours < 0)
+      {
+        CompositeGlyphHeader::Iterator composite_it;
+        if (unlikely (!CompositeGlyphHeader::get_iterator (
+            (const char*) this->glyf_table + start_offset,
+             end_offset - start_offset, &composite_it))) return false;
+        const CompositeGlyphHeader *last;
+        do {
+          last = composite_it.current;
+        } while (composite_it.move_to_next());
+
+        if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
+          *instruction_start = ((char *) last - (char *) glyf_table->dataX) + last->get_size();
+        else
+          *instruction_start = end_offset;
+        *instruction_end = end_offset;
+        if (unlikely (*instruction_start > *instruction_end))
+        {
+          DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
+          return false;
+        }
+      }
+      else
+      {
+        unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
+        const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
+        *instruction_start = instruction_length_offset + 2;
+        *instruction_end = *instruction_start + (uint16_t) instruction_length;
+      }
+      return true;
+    }
+
+    inline bool get_extents (hb_codepoint_t glyph,
+                            hb_glyph_extents_t *extents) const
+    {
+      unsigned int start_offset, end_offset;
+      if (!get_offsets (glyph, &start_offset, &end_offset))
+        return false;
+
+      if (end_offset - start_offset < GlyphHeader::static_size)
+       return true; /* Empty glyph; zero extents. */
+
+      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
+
+      extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
+      extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
+      extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
+      extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
+
+      return true;
+    }
+
+    private:
+    bool short_offset;
+    unsigned int num_glyphs;
+    const loca *loca_table;
+    const glyf *glyf_table;
+    hb_blob_t *loca_blob;
+    hb_blob_t *glyf_blob;
+    unsigned int glyf_len;
+  };
+
+  protected:
+  HBUINT8              dataX[VAR];             /* Glyphs data. */
+
+  DEFINE_SIZE_ARRAY (0, dataX);
 };
 
 } /* namespace OT */