Introduce get_extent support for color bitmap font. (#351)
authorSeigo Nonaka <nona@google.com>
Fri, 2 Dec 2016 23:03:50 +0000 (15:03 -0800)
committerBehdad Esfahbod <behdad@behdad.org>
Fri, 2 Dec 2016 23:03:50 +0000 (17:03 -0600)
hb_font_get_glyph_extents now works for color bitmap fonts.
Currently only font having index format 1 and image format 17
is supported.

src/Makefile.sources
src/hb-ot-ebdt-table.hh [new file with mode: 0644]
src/hb-ot-font.cc

index 5c695c5..8d2f3c6 100644 (file)
@@ -21,6 +21,7 @@ HB_BASE_sources = \
        hb-open-file-private.hh \
        hb-open-type-private.hh \
        hb-ot-cmap-table.hh \
+       hb-ot-ebdt-table.hh \
        hb-ot-glyf-table.hh \
        hb-ot-head-table.hh \
        hb-ot-hhea-table.hh \
diff --git a/src/hb-ot-ebdt-table.hh b/src/hb-ot-ebdt-table.hh
new file mode 100644 (file)
index 0000000..f3d0de6
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright © 2016  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): Seigo Nonaka
+ */
+
+#ifndef HB_OT_EBDT_TABLE_HH
+#define HB_OT_EBDT_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+namespace OT {
+
+struct SmallGlyphMetrics
+{
+  BYTE height;
+  BYTE width;
+  int8_t bearingX;
+  int8_t bearingY;
+  BYTE advance;
+
+  DEFINE_SIZE_STATIC(5);
+};
+
+struct SBitLineMetrics {
+  int8_t ascender;
+  int8_t decender;
+  BYTE widthMax;
+  int8_t caretSlopeNumerator;
+  int8_t caretSlopeDenominator;
+  int8_t caretOffset;
+  int8_t minOriginSB;
+  int8_t minAdvanceSB;
+  int8_t maxBeforeBL;
+  int8_t minAfterBL;
+  int8_t padding1;
+  int8_t padding2;
+
+  DEFINE_SIZE_STATIC(12);
+};
+
+struct BitmapSizeTable
+{
+  ULONG indexSubtableArrayOffset;
+  ULONG indexTablesSize;
+  ULONG numberOfIndexSubtables;
+  ULONG colorRef;
+  SBitLineMetrics horizontal;
+  SBitLineMetrics vertical;
+  USHORT startGlyphIndex;
+  USHORT endGlyphIndex;
+  BYTE ppemX;
+  BYTE ppemY;
+  BYTE bitDepth;
+  int8_t flags;
+
+  DEFINE_SIZE_STATIC(48);
+};
+
+/*
+ * Index Subtables.
+ */
+struct IndexSubtable
+{
+  USHORT firstGlyphIndex;
+  USHORT lastGlyphIndex;
+  ULONG offsetToSubtable;
+
+  DEFINE_SIZE_STATIC(8);
+};
+
+struct IndexSubHeader
+{
+  USHORT indexFormat;
+  USHORT imageFormat;
+  ULONG imageDataOffset;
+};
+
+struct IndexSubtableFormat1
+{
+  IndexSubHeader header;
+  ULONG offsetArray[VAR];
+};
+
+/*
+ * Glyph Bitmap Data Formats.
+ */
+struct GlyphBitmapDataFormat17
+{
+  SmallGlyphMetrics glyphMetrics;
+  ULONG dataLen;
+  BYTE data[VAR];
+};
+
+struct IndexSubtableArray
+{
+  public:
+  const IndexSubtable* find_table(hb_codepoint_t glyph, unsigned int numTables) const
+  {
+    for (unsigned int i = 0; i < numTables; ++i) {
+      unsigned int firstGlyphIndex = indexSubtables[i].firstGlyphIndex;
+      unsigned int lastGlyphIndex = indexSubtables[i].lastGlyphIndex;
+      if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
+        return &indexSubtables[i];
+      }
+    }
+    return NULL;
+  }
+
+  protected:
+  IndexSubtable indexSubtables[VAR];
+};
+
+/*
+ * CBLC -- Color Bitmap Location Table
+ */
+
+#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
+
+struct CBLC
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (true);
+  }
+
+  public:
+  const BitmapSizeTable* find_table(hb_codepoint_t glyph) const
+  {
+    // TODO: Make it possible to select strike.
+    const uint32_t tableSize = numSizes;
+    for (uint32_t i = 0; i < tableSize; ++i) {
+      unsigned int startGlyphIndex = sizeTables[i].startGlyphIndex;
+      unsigned int endGlyphIndex = sizeTables[i].endGlyphIndex;
+      if (startGlyphIndex <= glyph && glyph <= endGlyphIndex) {
+        return &sizeTables[i];
+      }
+    }
+    return NULL;
+  }
+
+  protected:
+  ULONG version;
+  ULONG numSizes;
+
+  BitmapSizeTable sizeTables[VAR];
+};
+
+/*
+ * CBDT -- Color Bitmap Data Table
+ */
+#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
+
+struct CBDT
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (true);
+  }
+
+  protected:
+  BYTE data[VAR];
+};
+
+} /* namespace OT */
+
+#endif /* HB_OT_EBDT_TABLE_HH */
index 20f2f89..d9be196 100644 (file)
@@ -31,6 +31,7 @@
 #include "hb-font-private.hh"
 
 #include "hb-ot-cmap-table.hh"
+#include "hb-ot-ebdt-table.hh"
 #include "hb-ot-glyf-table.hh"
 #include "hb-ot-head-table.hh"
 #include "hb-ot-hhea-table.hh"
@@ -207,6 +208,96 @@ struct hb_ot_face_glyf_accelerator_t
   }
 };
 
+struct hb_ot_face_ebdt_accelerator_t
+{
+  hb_blob_t *cblc_blob = NULL;
+  hb_blob_t *cbdt_blob = NULL;
+  const OT::CBLC *cblc = NULL;
+  const OT::CBDT *cbdt = NULL;
+
+  float upem = 0.0f;
+
+  inline void init (hb_face_t *face)
+  {
+    this->cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
+    this->cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+
+    if (hb_blob_get_length (this->cblc_blob) == 0) {
+      return;  /* Not a bitmap font. */
+    }
+    cblc = OT::Sanitizer<OT::CBLC>::lock_instance (this->cblc_blob);
+    cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (this->cbdt_blob);
+
+    upem = face->get_upem();
+  }
+
+  inline void fini (void)
+  {
+    if (this->cblc_blob) {
+      hb_blob_destroy (this->cblc_blob);
+      hb_blob_destroy (this->cbdt_blob);
+    }
+  }
+
+  inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+  {
+    if (cblc == NULL) {
+      return false;  // Not a color bitmap font.
+    }
+
+    const OT::BitmapSizeTable* sizeTable = this->cblc->find_table(glyph);
+    if (sizeTable == NULL) {
+      return false;
+    }
+
+    const OT::IndexSubtableArray& subtables =
+            OT::StructAtOffset<OT::IndexSubtableArray> (this->cblc, sizeTable->indexSubtableArrayOffset);
+    const OT::IndexSubtable* subtable = subtables.find_table(glyph, sizeTable->numberOfIndexSubtables);
+    if (subtable == NULL) {
+      return false;
+    }
+
+    unsigned int offsetToSubtable = sizeTable->indexSubtableArrayOffset + subtable->offsetToSubtable;
+    const OT::IndexSubHeader& header =
+            OT::StructAtOffset<OT::IndexSubHeader> (this->cblc, offsetToSubtable);
+
+    unsigned int imageDataOffset = header.imageDataOffset;
+    switch (header.indexFormat) {
+      case 1: {
+        const OT::IndexSubtableFormat1& format1 =
+            OT::StructAtOffset<OT::IndexSubtableFormat1> (this->cblc, offsetToSubtable);
+        imageDataOffset += format1.offsetArray[glyph - subtable->firstGlyphIndex];
+        switch (header.imageFormat) {
+          case 17: {
+            const OT::GlyphBitmapDataFormat17& glyphFormat17 =
+                OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, imageDataOffset);
+            extents->x_bearing = glyphFormat17.glyphMetrics.bearingX;
+            extents->y_bearing = glyphFormat17.glyphMetrics.bearingY;
+            extents->width = glyphFormat17.glyphMetrics.width;
+            extents->height = -glyphFormat17.glyphMetrics.height;
+          }
+          break;
+          default:
+            // TODO: Support other image formats.
+            return false;
+        }
+      }
+      break;
+      default:
+        // TODO: Support other index subtable format.
+        return false;
+    }
+
+    // Convert to the font units.
+    extents->x_bearing *= upem / (float)(sizeTable->ppemX);
+    extents->y_bearing *= upem / (float)(sizeTable->ppemY);
+    extents->width *= upem / (float)(sizeTable->ppemX);
+    extents->height *= upem / (float)(sizeTable->ppemY);
+
+    return true;
+  }
+};
+
 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
                                          hb_codepoint_t codepoint,
                                          hb_codepoint_t *glyph);
@@ -379,6 +470,7 @@ struct hb_ot_font_t
   hb_ot_face_metrics_accelerator_t h_metrics;
   hb_ot_face_metrics_accelerator_t v_metrics;
   hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
+  hb_lazy_loader_t<hb_ot_face_ebdt_accelerator_t> ebdt;
 };
 
 
@@ -395,6 +487,7 @@ _hb_ot_font_create (hb_face_t *face)
   ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE,
                           ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
   ot_font->glyf.init (face);
+  ot_font->ebdt.init (face);
 
   return ot_font;
 }
@@ -406,6 +499,7 @@ _hb_ot_font_destroy (hb_ot_font_t *ot_font)
   ot_font->h_metrics.fini ();
   ot_font->v_metrics.fini ();
   ot_font->glyf.fini ();
+  ot_font->ebdt.fini ();
 
   free (ot_font);
 }
@@ -464,6 +558,8 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   bool ret = ot_font->glyf->get_extents (glyph, extents);
+  if ( !ret )
+    ret = ot_font->ebdt->get_extents (glyph, extents);
   extents->x_bearing = font->em_scale_x (extents->x_bearing);
   extents->y_bearing = font->em_scale_y (extents->y_bearing);
   extents->width     = font->em_scale_x (extents->width);