Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / src / hb-ot-color-sbix-table.hh
index 09a9517..f6bdbb3 100644 (file)
@@ -25,7 +25,7 @@
 #ifndef HB_OT_COLOR_SBIX_TABLE_HH
 #define HB_OT_COLOR_SBIX_TABLE_HH
 
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
 
 /*
  * sbix -- Standard Bitmap Graphics
@@ -62,19 +62,65 @@ struct SBIXGlyph
 
 struct SBIXStrike
 {
-  friend struct sbix;
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-                 imageOffsetsZ.sanitize_shallow (c, c->num_glyphs + 1));
+                 imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1));
   }
 
-  protected:
+  hb_blob_t *get_glyph_blob (unsigned int  glyph_id,
+                            hb_blob_t    *sbix_blob,
+                            hb_tag_t      file_type,
+                            int          *x_offset,
+                            int          *y_offset,
+                            unsigned int  num_glyphs,
+                            unsigned int *strike_ppem) const
+  {
+    if (unlikely (!ppem)) return hb_blob_get_empty (); /* To get Null() object out of the way. */
+
+    unsigned int retry_count = 8;
+    unsigned int sbix_len = sbix_blob->length;
+    unsigned int strike_offset = (const char *) this - (const char *) sbix_blob->data;
+    assert (strike_offset < sbix_len);
+
+  retry:
+    if (unlikely (glyph_id >= num_glyphs ||
+                 imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] ||
+                 imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size ||
+                 (unsigned int) imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset))
+      return hb_blob_get_empty ();
+
+    unsigned int glyph_offset = strike_offset + (unsigned int) imageOffsetsZ[glyph_id] + SBIXGlyph::min_size;
+    unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size;
+
+    const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]);
+
+    if (glyph->graphicType == HB_TAG ('d','u','p','e'))
+    {
+      if (glyph_length >= 2)
+      {
+       glyph_id = *((HBUINT16 *) &glyph->data);
+       if (retry_count--)
+         goto retry;
+      }
+      return hb_blob_get_empty ();
+    }
+
+    if (unlikely (file_type != glyph->graphicType))
+      return hb_blob_get_empty ();
+
+    if (strike_ppem) *strike_ppem = ppem;
+    if (x_offset) *x_offset = glyph->xOffset;
+    if (y_offset) *y_offset = glyph->yOffset;
+    return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length);
+  }
+
+  public:
   HBUINT16     ppem;           /* The PPEM size for which this strike was designed. */
   HBUINT16     resolution;     /* The device pixel density (in PPI) for which this
                                 * strike was designed. (E.g., 96 PPI, 192 PPI.) */
+  protected:
   UnsizedArrayOf<LOffsetTo<SBIXGlyph> >
                imageOffsetsZ;  /* Offset from the beginning of the strike data header
                                 * to bitmap data for an individual glyph ID. */
@@ -84,70 +130,157 @@ struct SBIXStrike
 
 struct sbix
 {
-  static const hb_tag_t tableTag = HB_OT_TAG_sbix;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) && strikes.sanitize (c, this)));
-  }
+  bool has_data () const { return version; }
+
+  const SBIXStrike &get_strike (unsigned int i) const { return this+strikes[i]; }
 
   struct accelerator_t
   {
-    inline void init (hb_face_t *face)
+    void init (hb_face_t *face)
     {
-      num_glyphs = hb_face_get_glyph_count (face);
+      table = hb_sanitize_context_t().reference_table<sbix> (face);
+      num_glyphs = face->get_num_glyphs ();
+    }
+    void fini () { table.destroy (); }
+
+    bool has_data () const { return table->has_data (); }
 
-      OT::Sanitizer<OT::sbix> sanitizer;
-      sanitizer.set_num_glyphs (num_glyphs);
-      sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_sbix));
-      sbix_len = hb_blob_get_length (sbix_blob);
-      sbix_table = sbix_blob->as<OT::sbix> ();
+    bool get_extents (hb_font_t          *font,
+                     hb_codepoint_t      glyph,
+                     hb_glyph_extents_t *extents) const
+    {
+      /* We only support PNG right now, and following function checks type. */
+      return get_png_extents (font, glyph, extents);
+    }
 
+    hb_blob_t *reference_png (hb_font_t      *font,
+                             hb_codepoint_t  glyph_id,
+                             int            *x_offset,
+                             int            *y_offset,
+                             unsigned int   *available_ppem) const
+    {
+      return choose_strike (font).get_glyph_blob (glyph_id, table.get_blob (),
+                                                 HB_TAG ('p','n','g',' '),
+                                                 x_offset, y_offset,
+                                                 num_glyphs, available_ppem);
     }
 
-    inline void fini (void)
+    private:
+
+    const SBIXStrike &choose_strike (hb_font_t *font) const
     {
-      hb_blob_destroy (sbix_blob);
+      unsigned count = table->strikes.len;
+      if (unlikely (!count))
+        return Null(SBIXStrike);
+
+      unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
+      if (!requested_ppem)
+        requested_ppem = 1<<30; /* Choose largest strike. */
+      /* TODO Add DPI sensitivity as well? */
+      unsigned int best_i = 0;
+      unsigned int best_ppem = table->get_strike (0).ppem;
+
+      for (unsigned int i = 1; i < count; i++)
+      {
+       unsigned int ppem = (table->get_strike (i)).ppem;
+       if ((requested_ppem <= ppem && ppem < best_ppem) ||
+           (requested_ppem > best_ppem && ppem > best_ppem))
+       {
+         best_i = i;
+         best_ppem = ppem;
+       }
+      }
+
+      return table->get_strike (best_i);
     }
 
-    inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
-                                       unsigned int group, unsigned int gid)) const
+    struct PNGHeader
     {
-      for (unsigned group = 0; group < sbix_table->strikes.len; ++group)
+      HBUINT8  signature[8];
+      struct
       {
-       const SBIXStrike &strike = sbix_table->strikes[group](sbix_table);
-       for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph)
-         if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0)
-         {
-           const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike);
-           callback ((const uint8_t*) &sbixGlyph.data,
-                     strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8,
-                     group, glyph);
-         }
+        struct
+       {
+         HBUINT32      length;
+         Tag           type;
+       }               header;
+       HBUINT32        width;
+       HBUINT32        height;
+       HBUINT8         bitDepth;
+       HBUINT8         colorType;
+       HBUINT8         compressionMethod;
+       HBUINT8         filterMethod;
+       HBUINT8         interlaceMethod;
+      } IHDR;
+
+      public:
+      DEFINE_SIZE_STATIC (29);
+    };
+
+    bool get_png_extents (hb_font_t          *font,
+                         hb_codepoint_t      glyph,
+                         hb_glyph_extents_t *extents) const
+    {
+      /* Following code is safe to call even without data.
+       * But faster to short-circuit. */
+      if (!has_data ())
+        return false;
+
+      int x_offset = 0, y_offset = 0;
+      unsigned int strike_ppem = 0;
+      hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
+
+      const PNGHeader &png = *blob->as<PNGHeader>();
+
+      extents->x_bearing = x_offset;
+      extents->y_bearing = y_offset;
+      extents->width     = png.IHDR.width;
+      extents->height    = png.IHDR.height;
+
+      /* Convert to font units. */
+      if (strike_ppem)
+      {
+       double scale = font->face->get_upem () / (double) strike_ppem;
+       extents->x_bearing = round (extents->x_bearing * scale);
+       extents->y_bearing = round (extents->y_bearing * scale);
+       extents->width = round (extents->width * scale);
+       extents->height = round (extents->height * scale);
       }
+
+      hb_blob_destroy (blob);
+
+      return strike_ppem;
     }
 
     private:
-    hb_blob_t *sbix_blob;
-    const sbix *sbix_table;
+    hb_blob_ptr_t<sbix> table;
 
-    unsigned int sbix_len;
     unsigned int num_glyphs;
-
   };
 
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+                         version >= 1 &&
+                         strikes.sanitize (c, this)));
+  }
+
   protected:
   HBUINT16     version;        /* Table version number — set to 1 */
   HBUINT16     flags;          /* Bit 0: Set to 1. Bit 1: Draw outlines.
                                 * Bits 2 to 15: reserved (set to 0). */
-  LArrayOf<LOffsetTo<SBIXStrike> >
+  LOffsetLArrayOf<SBIXStrike>
                strikes;        /* Offsets from the beginning of the 'sbix'
                                 * table to data for each individual bitmap strike. */
   public:
   DEFINE_SIZE_ARRAY (8, strikes);
 };
 
+struct sbix_accelerator_t : sbix::accelerator_t {};
+
 } /* namespace OT */
 
 #endif /* HB_OT_COLOR_SBIX_TABLE_HH */