Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / src / hb-ot-shape-fallback.cc
index fbf31ab..f9d4a75 100644 (file)
@@ -24,8 +24,8 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-ot-shape-fallback-private.hh"
-#include "hb-ot-layout-gsubgpos-private.hh"
+#include "hb-ot-shape-fallback.hh"
+#include "hb-kern.hh"
 
 static unsigned int
 recategorize_combining_class (hb_codepoint_t u,
@@ -162,9 +162,9 @@ recategorize_combining_class (hb_codepoint_t u,
 }
 
 void
-_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                                                  hb_font_t *font HB_UNUSED,
-                                                  hb_buffer_t  *buffer)
+_hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                                       hb_font_t *font HB_UNUSED,
+                                                       hb_buffer_t  *buffer)
 {
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
@@ -180,19 +180,25 @@ _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *pla
 static void
 zero_mark_advances (hb_buffer_t *buffer,
                    unsigned int start,
-                   unsigned int end)
+                   unsigned int end,
+                   bool adjust_offsets_when_zeroing)
 {
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
+      if (adjust_offsets_when_zeroing)
+      {
+       buffer->pos[i].x_offset -= buffer->pos[i].x_advance;
+       buffer->pos[i].y_offset -= buffer->pos[i].y_advance;
+      }
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
     }
 }
 
 static inline void
-position_mark (const hb_ot_shape_plan_t *plan,
+position_mark (const hb_ot_shape_plan_t *plan HB_UNUSED,
               hb_font_t *font,
               hb_buffer_t  *buffer,
               hb_glyph_extents_t &base_extents,
@@ -303,7 +309,8 @@ position_around_base (const hb_ot_shape_plan_t *plan,
                      hb_font_t *font,
                      hb_buffer_t  *buffer,
                      unsigned int base,
-                     unsigned int end)
+                     unsigned int end,
+                     bool adjust_offsets_when_zeroing)
 {
   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
 
@@ -314,11 +321,15 @@ position_around_base (const hb_ot_shape_plan_t *plan,
                                &base_extents))
   {
     /* If extents don't work, zero marks and go home. */
-    zero_mark_advances (buffer, base + 1, end);
+    zero_mark_advances (buffer, base + 1, end, adjust_offsets_when_zeroing);
     return;
   }
-  base_extents.x_bearing += buffer->pos[base].x_offset;
   base_extents.y_bearing += buffer->pos[base].y_offset;
+  /* Use horizontal advance for horizontal positioning.
+   * Generally a better idea.  Also works for zero-ink glyphs.  See:
+   * https://github.com/harfbuzz/harfbuzz/issues/1532 */
+  base_extents.x_bearing = 0;
+  base_extents.width = font->get_glyph_h_advance (buffer->info[base].codepoint);
 
   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
   /* Use integer for num_lig_components such that it doesn't convert to unsigned
@@ -394,7 +405,8 @@ position_cluster (const hb_ot_shape_plan_t *plan,
                  hb_font_t *font,
                  hb_buffer_t  *buffer,
                  unsigned int start,
-                 unsigned int end)
+                 unsigned int end,
+                 bool adjust_offsets_when_zeroing)
 {
   if (end - start < 2)
     return;
@@ -410,16 +422,17 @@ position_cluster (const hb_ot_shape_plan_t *plan,
        if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
          break;
 
-      position_around_base (plan, font, buffer, i, j);
+      position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
 
       i = j - 1;
     }
 }
 
 void
-_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
-                               hb_font_t *font,
-                               hb_buffer_t  *buffer)
+_hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
+                                    hb_font_t *font,
+                                    hb_buffer_t  *buffer,
+                                    bool adjust_offsets_when_zeroing)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
@@ -428,81 +441,66 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
-      position_cluster (plan, font, buffer, start, i);
+      position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }
-  position_cluster (plan, font, buffer, start, count);
+  position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing);
 }
 
 
-/* Performs old-style TrueType kerning. */
+struct hb_ot_shape_fallback_kern_driver_t
+{
+  hb_ot_shape_fallback_kern_driver_t (hb_font_t   *font_,
+                                     hb_buffer_t *buffer) :
+    font (font_), direction (buffer->props.direction) {}
+
+  hb_position_t get_kerning (hb_codepoint_t first, hb_codepoint_t second) const
+  {
+    hb_position_t kern = 0;
+    font->get_glyph_kerning_for_direction (first, second,
+                                          direction,
+                                          &kern, &kern);
+    return kern;
+  }
+
+  hb_font_t *font;
+  hb_direction_t direction;
+};
+
+/* Performs font-assisted kerning. */
 void
 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
                            hb_font_t *font,
-                           hb_buffer_t  *buffer)
+                           hb_buffer_t *buffer)
 {
-  if (!plan->has_kern) return;
-
-  OT::hb_ot_apply_context_t c (1, font, buffer);
-  c.set_lookup_mask (plan->kern_mask);
-  c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
-  OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
-  skippy_iter.init (&c);
-
-  unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
-  hb_glyph_position_t *pos = buffer->pos;
-  for (unsigned int idx = 0; idx < count;)
-  {
-    skippy_iter.reset (idx, 1);
-    if (!skippy_iter.next ())
-    {
-      idx++;
-      continue;
-    }
+  if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
+      !font->has_glyph_h_kerning_func () :
+      !font->has_glyph_v_kerning_func ())
+    return;
 
-    hb_position_t x_kern, y_kern;
-    font->get_glyph_kerning_for_direction (info[idx].codepoint,
-                                          info[skippy_iter.idx].codepoint,
-                                          buffer->props.direction,
-                                          &x_kern, &y_kern);
+  bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
-    if (x_kern)
-    {
-      hb_position_t kern1 = x_kern >> 1;
-      hb_position_t kern2 = x_kern - kern1;
-      pos[idx].x_advance += kern1;
-      pos[skippy_iter.idx].x_advance += kern2;
-      pos[skippy_iter.idx].x_offset += kern2;
-      buffer->unsafe_to_break (idx, skippy_iter.idx + 1);
-    }
+  if (reverse)
+    buffer->reverse ();
 
-    if (y_kern)
-    {
-      hb_position_t kern1 = y_kern >> 1;
-      hb_position_t kern2 = y_kern - kern1;
-      pos[idx].y_advance += kern1;
-      pos[skippy_iter.idx].y_advance += kern2;
-      pos[skippy_iter.idx].y_offset += kern2;
-      buffer->unsafe_to_break (idx, skippy_iter.idx + 1);
-    }
+  hb_ot_shape_fallback_kern_driver_t driver (font, buffer);
+  OT::hb_kern_machine_t<hb_ot_shape_fallback_kern_driver_t> machine (driver);
+  machine.kern (font, buffer, plan->kern_mask, false);
 
-    idx = skippy_iter.idx;
-  }
+  if (reverse)
+    buffer->reverse ();
 }
 
 
 /* Adjusts width of various spaces. */
 void
-_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED,
                              hb_font_t *font,
                              hb_buffer_t  *buffer)
 {
-  if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
-    return;
-
   hb_glyph_info_t *info = buffer->info;
   hb_glyph_position_t *pos = buffer->pos;
+  bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
     if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
@@ -523,27 +521,40 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
        case t::SPACE_EM_5:
        case t::SPACE_EM_6:
        case t::SPACE_EM_16:
-         pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
+         if (horizontal)
+           pos[i].x_advance = +(font->x_scale + ((int) space_type)/2) / (int) space_type;
+         else
+           pos[i].y_advance = -(font->y_scale + ((int) space_type)/2) / (int) space_type;
          break;
 
        case t::SPACE_4_EM_18:
-         pos[i].x_advance = (int64_t) font->x_scale * 4 / 18;
+         if (horizontal)
+           pos[i].x_advance = (int64_t) +font->x_scale * 4 / 18;
+         else
+           pos[i].y_advance = (int64_t) -font->y_scale * 4 / 18;
          break;
 
        case t::SPACE_FIGURE:
          for (char u = '0'; u <= '9'; u++)
            if (font->get_nominal_glyph (u, &glyph))
            {
-             pos[i].x_advance = font->get_glyph_h_advance (glyph);
+             if (horizontal)
+               pos[i].x_advance = font->get_glyph_h_advance (glyph);
+             else
+               pos[i].y_advance = font->get_glyph_v_advance (glyph);
              break;
            }
          break;
 
        case t::SPACE_PUNCTUATION:
-         if (font->get_nominal_glyph ('.', &glyph))
-           pos[i].x_advance = font->get_glyph_h_advance (glyph);
-         else if (font->get_nominal_glyph (',', &glyph))
-           pos[i].x_advance = font->get_glyph_h_advance (glyph);
+         if (font->get_nominal_glyph ('.', &glyph) ||
+             font->get_nominal_glyph (',', &glyph))
+         {
+           if (horizontal)
+             pos[i].x_advance = font->get_glyph_h_advance (glyph);
+           else
+             pos[i].y_advance = font->get_glyph_v_advance (glyph);
+         }
          break;
 
        case t::SPACE_NARROW:
@@ -552,7 +563,10 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
           * However, in my testing, many fonts have their regular space being about that
           * size.  To me, a percentage of the space width makes more sense.  Half is as
           * good as any. */
-         pos[i].x_advance /= 2;
+         if (horizontal)
+           pos[i].x_advance /= 2;
+         else
+           pos[i].y_advance /= 2;
          break;
       }
     }