Get font ascender and descender metrics from OS/2 table.
authorSimon Cozens <simon@simon-cozens.org>
Mon, 26 Oct 2015 07:23:22 +0000 (16:23 +0900)
committerBehdad Esfahbod <behdad@behdad.org>
Fri, 27 Nov 2015 21:03:54 +0000 (16:03 -0500)
src/hb-font-private.hh
src/hb-font.cc
src/hb-font.h
src/hb-ft.cc
src/hb-ot-font.cc

index 7255cb9..4c12e13 100644 (file)
@@ -42,6 +42,8 @@
  */
 
 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
+  HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
   HB_FONT_FUNC_IMPLEMENT (glyph) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
@@ -160,6 +162,21 @@ struct hb_font_t {
   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
+  inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.f.font_h_extents (this, user_data,
+                                       extents,
+                                       klass->user_data.font_h_extents);
+  }
+  inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.f.font_v_extents (this, user_data,
+                                       extents,
+                                       klass->user_data.font_v_extents);
+  }
+
   inline bool has_glyph (hb_codepoint_t unicode)
   {
     hb_codepoint_t glyph;
@@ -265,6 +282,26 @@ struct hb_font_t {
 
   /* A bit higher-level, and with fallback */
 
+  inline void get_extents_for_direction (hb_direction_t direction,
+                                        hb_font_extents_t *extents)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      if (!get_font_h_extents (extents))
+      {
+       extents->ascender = y_scale * .8;
+       extents->descender = y_scale - extents->ascender;
+       extents->line_gap = 0;
+      }
+    } else {
+      if (!get_font_v_extents (extents))
+      {
+       extents->ascender = x_scale / 2;
+       extents->descender = x_scale - extents->ascender;
+       extents->line_gap = 0;
+      }
+    }
+  }
+
   inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
                                               hb_direction_t direction,
                                               hb_position_t *x, hb_position_t *y)
@@ -284,7 +321,7 @@ struct hb_font_t {
   {
     *x = get_glyph_h_advance (glyph) / 2;
 
-    /* TODO use font_metrics.ascent */
+    /* TODO use font_extents.ascender */
     *y = y_scale;
   }
 
index d1b8a88..3bd8e31 100644 (file)
  */
 
 static hb_bool_t
+hb_font_get_font_h_extents_nil (hb_font_t *font,
+                               void *font_data HB_UNUSED,
+                               hb_font_extents_t *metrics,
+                               void *user_data HB_UNUSED)
+{
+  memset (metrics, 0, sizeof (*metrics));
+  return false;
+}
+static hb_bool_t
+hb_font_get_font_h_extents_parent (hb_font_t *font,
+                                  void *font_data HB_UNUSED,
+                                  hb_font_extents_t *metrics,
+                                  void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_font_h_extents (metrics);
+  if (ret) {
+    metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
+    metrics->descender = font->parent_scale_y_distance (metrics->descender);
+    metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
+  }
+  return ret;
+}
+
+static hb_bool_t
+hb_font_get_font_v_extents_nil (hb_font_t *font,
+                               void *font_data HB_UNUSED,
+                               hb_font_extents_t *metrics,
+                               void *user_data HB_UNUSED)
+{
+  memset (metrics, 0, sizeof (*metrics));
+  return false;
+}
+static hb_bool_t
+hb_font_get_font_v_extents_parent (hb_font_t *font,
+                                  void *font_data HB_UNUSED,
+                                  hb_font_extents_t *metrics,
+                                  void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_font_v_extents (metrics);
+  if (ret) {
+    metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
+    metrics->descender = font->parent_scale_x_distance (metrics->descender);
+    metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
+  }
+  return ret;
+}
+
+static hb_bool_t
 hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
                       void *font_data HB_UNUSED,
                       hb_codepoint_t unicode,
@@ -280,7 +328,6 @@ hb_font_get_glyph_from_name_parent (hb_font_t *font,
   return font->parent->get_glyph_from_name (name, len, glyph);
 }
 
-
 static const hb_font_funcs_t _hb_font_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
 
@@ -522,6 +569,42 @@ hb_font_t::has_func (unsigned int i)
 /* Public getters */
 
 /**
+ * hb_font_get_h_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.2
+ **/
+hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+                      hb_font_extents_t *extents)
+{
+  return font->get_font_h_extents (extents);
+}
+
+/**
+ * hb_font_get_v_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.2
+ **/
+hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+                      hb_font_extents_t *extents)
+{
+  return font->get_font_v_extents (extents);
+}
+
+/**
  * hb_font_get_glyph:
  * @font: a font.
  * @unicode: 
@@ -746,6 +829,23 @@ hb_font_get_glyph_from_name (hb_font_t *font,
 /* A bit higher-level, and with fallback */
 
 /**
+ * hb_font_get_extents_for_direction:
+ * @font: a font.
+ * @direction:
+ * @extents:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+void
+hb_font_get_extents_for_direction (hb_font_t *font,
+                                  hb_direction_t direction,
+                                  hb_font_extents_t *extents)
+{
+  return font->get_extents_for_direction (direction, extents);
+}
+/**
  * hb_font_get_glyph_advance_for_direction:
  * @font: a font.
  * @glyph: 
index c3165e1..caced5e 100644 (file)
@@ -78,7 +78,15 @@ HB_EXTERN hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
 
 
-/* glyph extents */
+/* font and glyph extents */
+
+/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
+typedef struct hb_font_extents_t
+{
+  hb_position_t ascender; /* typographic ascender. */
+  hb_position_t descender; /* typographic descender. */
+  hb_position_t line_gap; /* suggested line spacing gap. */
+} hb_font_extents_t;
 
 /* Note that height is negative in coordinate systems that grow up. */
 typedef struct hb_glyph_extents_t
@@ -89,9 +97,15 @@ typedef struct hb_glyph_extents_t
   hb_position_t height; /* distance from top to bottom side. */
 } hb_glyph_extents_t;
 
-
 /* func types */
 
+typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
+                                                      hb_font_extents_t *metrics,
+                                                      void *user_data);
+typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
+typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
+
+
 typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
                                               hb_codepoint_t unicode, hb_codepoint_t variation_selector,
                                               hb_codepoint_t *glyph,
@@ -141,6 +155,38 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
 /* func setters */
 
 /**
+ * hb_font_funcs_set_font_h_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
+                                      hb_font_get_font_h_extents_func_t func,
+                                      void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_font_v_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
+                                      hb_font_get_font_v_extents_func_t func,
+                                      void *user_data, hb_destroy_func_t destroy);
+
+/**
  * hb_font_funcs_set_glyph_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
@@ -316,10 +362,16 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
                                        hb_font_get_glyph_from_name_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
 
-
 /* func dispatch */
 
 HB_EXTERN hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+                      hb_font_extents_t *extents);
+HB_EXTERN hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+                      hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
                   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
                   hb_codepoint_t *glyph);
@@ -370,6 +422,10 @@ hb_font_get_glyph_from_name (hb_font_t *font,
 /* high-level funcs, with fallback */
 
 HB_EXTERN void
+hb_font_get_extents_for_direction (hb_font_t *font,
+                                  hb_direction_t direction,
+                                  hb_font_extents_t *extents);
+HB_EXTERN void
 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
                                         hb_codepoint_t glyph,
                                         hb_direction_t direction,
index 9b872ea..682acb7 100644 (file)
@@ -366,6 +366,25 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
   return *glyph != 0;
 }
 
+static hb_bool_t
+hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_font_extents_t *metrics,
+                         void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+  metrics->ascender = ft_face->ascender;
+  metrics->descender = ft_face->descender;
+  metrics->line_gap = ft_face->height - (ft_face->ascender - ft_face->descender);
+  if (font->y_scale < 0)
+  {
+    metrics->ascender = -metrics->ascender;
+    metrics->descender = -metrics->descender;
+    metrics->line_gap = -metrics->line_gap;
+  }
+  return true;
+}
 
 static hb_font_funcs_t *static_ft_funcs = NULL;
 
@@ -387,6 +406,8 @@ retry:
   {
     funcs = hb_font_funcs_create ();
 
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
+    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
     hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
index 58586bf..a0f1e30 100644 (file)
@@ -35,6 +35,7 @@
 #include "hb-ot-head-table.hh"
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-hmtx-table.hh"
+#include "hb-ot-os2-table.hh"
 
 
 struct hb_ot_face_metrics_accelerator_t
@@ -42,17 +43,41 @@ struct hb_ot_face_metrics_accelerator_t
   unsigned int num_metrics;
   unsigned int num_advances;
   unsigned int default_advance;
+  unsigned short ascender;
+  unsigned short descender;
+  unsigned short line_gap;
+
   const OT::_mtx *table;
   hb_blob_t *blob;
 
   inline void init (hb_face_t *face,
-                   hb_tag_t _hea_tag, hb_tag_t _mtx_tag)
+                   hb_tag_t _hea_tag,
+                   hb_tag_t _mtx_tag,
+                   hb_tag_t os2_tag)
   {
     this->default_advance = face->get_upem ();
 
+    bool got_font_extents = false;
+    if (os2_tag)
+    {
+      hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
+      const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
+      this->ascender = os2->sTypoAscender;
+      this->descender = os2->sTypoDescender;
+      this->line_gap = os2->sTypoLineGap;
+      hb_blob_destroy (os2_blob);
+      got_font_extents = (this->ascender | this->descender) != 0;
+    }
+
     hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
     const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
     this->num_advances = _hea->numberOfLongMetrics;
+    if (!got_font_extents)
+    {
+      this->ascender = _hea->ascender;
+      this->descender = _hea->descender;
+      this->line_gap = _hea->lineGap;
+    }
     hb_blob_destroy (_hea_blob);
 
     this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
@@ -252,8 +277,8 @@ _hb_ot_font_create (hb_face_t *face)
     return NULL;
 
   ot_font->cmap.init (face);
-  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx);
-  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx); /* TODO Can we do this lazily? */
+  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
+  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
   ot_font->glyf.init (face);
 
   return ot_font;
@@ -320,6 +345,31 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
   return ret;
 }
 
+static hb_bool_t
+hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_font_extents_t *metrics,
+                         void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
+  metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
+  metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
+  return true;
+}
+
+static hb_bool_t
+hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_font_extents_t *metrics,
+                         void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
+  metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
+  metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
+  return true;
+}
 
 static hb_font_funcs_t *static_ot_funcs = NULL;
 
@@ -341,6 +391,8 @@ retry:
   {
     funcs = hb_font_funcs_create ();
 
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
+    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
     hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);