Revert "Imported Upstream version 1.2.7"
[platform/upstream/harfbuzz.git] / src / hb-coretext.cc
index e64d265..4a45175 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 #define HB_SHAPER coretext
+#define hb_coretext_shaper_face_data_t CGFont
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-coretext.h"
@@ -77,29 +78,6 @@ HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
  * shaper face data
  */
 
-static CTFontDescriptorRef
-get_last_resort_font_desc (void)
-{
-  // TODO Handle allocation failures?
-  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
-  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
-                                          (const void **) &last_resort,
-                                          1,
-                                          &kCFTypeArrayCallBacks);
-  CFRelease (last_resort);
-  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
-                                                  (const void **) &kCTFontCascadeListAttribute,
-                                                  (const void **) &cascade_list,
-                                                  1,
-                                                  &kCFTypeDictionaryKeyCallBacks,
-                                                  &kCFTypeDictionaryValueCallBacks);
-  CFRelease (cascade_list);
-
-  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
-  CFRelease (attributes);
-  return font_desc;
-}
-
 static void
 release_data (void *info, const void *data, size_t size)
 {
@@ -109,13 +87,14 @@ release_data (void *info, const void *data, size_t size)
   hb_blob_destroy ((hb_blob_t *) info);
 }
 
-static CGFontRef
-create_cg_font (hb_face_t *face)
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
 {
-  CGFontRef cg_font = NULL;
+  hb_coretext_shaper_face_data_t *data = NULL;
+
   if (face->destroy == (hb_destroy_func_t) CGFontRelease)
   {
-    cg_font = CGFontRetain ((CGFontRef) face->user_data);
+    data = CGFontRetain ((CGFontRef) face->user_data);
   }
   else
   {
@@ -128,76 +107,13 @@ create_cg_font (hb_face_t *face)
     CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
     if (likely (provider))
     {
-      cg_font = CGFontCreateWithDataProvider (provider);
-      if (unlikely (!cg_font))
-       DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+      data = CGFontCreateWithDataProvider (provider);
       CGDataProviderRelease (provider);
     }
   }
-  return cg_font;
-}
-
-static CTFontRef
-create_ct_font (CGFontRef cg_font, CGFloat font_size)
-{
-  CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
-  if (unlikely (!ct_font)) {
-    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
-    return NULL;
-  }
-
-  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
-   * font fallback which we don't need anyway. */
-  {
-    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
-    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
-    CFRelease (last_resort_font_desc);
-    if (new_ct_font)
-    {
-      CFRelease (ct_font);
-      ct_font = new_ct_font;
-    }
-    else
-      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
-  }
 
- return ct_font;
-}
-
-struct hb_coretext_shaper_face_data_t {
-  CGFontRef cg_font;
-  CTFontRef ct_font;
-};
-
-hb_coretext_shaper_face_data_t *
-_hb_coretext_shaper_face_data_create (hb_face_t *face)
-{
-  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
-  if (unlikely (!data))
-    return NULL;
-
-  data->cg_font = create_cg_font (face);
-  if (unlikely (!data->cg_font))
-  {
-    DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
-    free (data);
-    return NULL;
-  }
-
-  /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
-   * which can make the font too tight at large sizes.  36pt should be a good semi-neutral
-   * size.
-   *
-   * Since we always create CTFont at a fixed size, our CTFont lives in face_data
-   * instead of font_data.  Which is good, because when people change scale on
-   * hb_font_t, we won't need to update our CTFont. */
-  data->ct_font = create_ct_font (data->cg_font, 36.);
-  if (unlikely (!data->ct_font))
-  {
-    DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
-    CFRelease (data->cg_font);
-    free (data);
-    return NULL;
+  if (unlikely (!data)) {
+    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
   }
 
   return data;
@@ -206,20 +122,15 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
 void
 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
-  CFRelease (data->ct_font);
-  CFRelease (data->cg_font);
-  free (data);
+  CFRelease (data);
 }
 
-/*
- * Since: 0.9.10
- */
 CGFontRef
 hb_coretext_face_get_cg_font (hb_face_t *face)
 {
   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  return face_data->cg_font;
+  return face_data;
 }
 
 
@@ -227,17 +138,48 @@ hb_coretext_face_get_cg_font (hb_face_t *face)
  * shaper font data
  */
 
-struct hb_coretext_shaper_font_data_t {};
+struct hb_coretext_shaper_font_data_t {
+  CTFontRef ct_font;
+  CGFloat x_mult, y_mult; /* From CT space to HB space. */
+};
 
 hb_coretext_shaper_font_data_t *
-_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+_hb_coretext_shaper_font_data_create (hb_font_t *font)
 {
-  return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
+
+  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  hb_face_t *face = font->face;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+  /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
+  CGFloat font_size = 36.; /* Default... */
+  /* No idea if the following is even a good idea. */
+  if (font->y_ppem)
+    font_size = font->y_ppem;
+
+  if (font_size < 0)
+    font_size = -font_size;
+  data->x_mult = (CGFloat) font->x_scale / font_size;
+  data->y_mult = (CGFloat) font->y_scale / font_size;
+  data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
+  if (unlikely (!data->ct_font)) {
+    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
+    free (data);
+    return NULL;
+  }
+
+  return data;
 }
 
 void
 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
 {
+  CFRelease (data->ct_font);
+  free (data);
 }
 
 
@@ -263,10 +205,9 @@ _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
-  hb_face_t *face = font->face;
-  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  return face_data->ct_font;
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+  return font_data->ct_font;
 }
 
 
@@ -499,10 +440,7 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
 {
   hb_face_t *face = font->face;
   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-
-  CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
-  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
-  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
 
   /* Attach marks to their bases, to match the 'ot' shaper.
    * Adapted from hb-ot-shape:hb_form_clusters().
@@ -511,7 +449,6 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
    * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
    * continue pointing to B2 even though B2 was merged into B1's
    * cluster... */
-  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
   {
     hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
@@ -634,7 +571,7 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
          CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
          CFRelease (attributes);
 
-         range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
+         range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
          CFRelease (font_desc);
        }
        else
@@ -752,6 +689,7 @@ resize_and_retry:
     scratch += old_scratch_used;
     scratch_size -= old_scratch_used;
   }
+retry:
   {
     string_ref = CFStringCreateWithCharactersNoCopy (NULL,
                                                     pchars, chars_len,
@@ -791,7 +729,7 @@ resize_and_retry:
        CFRelease (lang);
       }
       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
-                                     kCTFontAttributeName, face_data->ct_font);
+                                     kCTFontAttributeName, font_data->ct_font);
 
       if (num_features)
       {
@@ -850,17 +788,6 @@ resize_and_retry:
     buffer->len = 0;
     uint32_t status_and = ~0, status_or = 0;
     double advances_so_far = 0;
-    /* For right-to-left runs, CoreText returns the glyphs positioned such that
-     * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
-     * to fix for that.  Test with any RTL string with trailing spaces.
-     * https://code.google.com/p/chromium/issues/detail?id=469028
-     */
-    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
-    {
-      advances_so_far -= CTLineGetTrailingWhitespaceWidth (line);
-      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
-         advances_so_far = -advances_so_far;
-    }
 
     const CFRange range_all = CFRangeMake (0, 0);
 
@@ -884,7 +811,7 @@ resize_and_retry:
        */
       CFDictionaryRef attributes = CTRunGetAttributes (run);
       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
-      if (!CFEqual (run_ct_font, face_data->ct_font))
+      if (!CFEqual (run_ct_font, font_data->ct_font))
       {
        /* The run doesn't use our main font instance.  We have to figure out
         * whether font fallback happened, or this is just CoreText giving us
@@ -904,11 +831,15 @@ resize_and_retry:
         * backend.
         *
         * However, even that wouldn't work if we were passed in the CGFont to
-        * construct a hb_face to begin with.
+        * begin with.
         *
-        * See: http://github.com/behdad/harfbuzz/pull/36
+        * Webkit uses a slightly different approach: it installs LastResort
+        * as fallback chain, and then checks PS name of used font against
+        * LastResort.  That one is safe for any font except for LastResort,
+        * as opposed to ours, which can fail if we are using any uninstalled
+        * font that has the same name as an installed font.
         *
-        * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
+        * See: http://github.com/behdad/harfbuzz/pull/36
         */
        bool matched = false;
        for (unsigned int i = 0; i < range_records.len; i++)
@@ -922,13 +853,13 @@ resize_and_retry:
          CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
          if (run_cg_font)
          {
-           matched = CFEqual (run_cg_font, face_data->cg_font);
+           matched = CFEqual (run_cg_font, face_data);
            CFRelease (run_cg_font);
          }
        }
        if (!matched)
        {
-         CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
+         CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
          CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
          CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
          CFRelease (run_ps_name);
@@ -973,8 +904,8 @@ resize_and_retry:
              info->cluster = log_clusters[j];
 
              info->mask = advance;
-             info->var1.i32 = x_offset;
-             info->var2.i32 = y_offset;
+             info->var1.u32 = x_offset;
+             info->var2.u32 = y_offset;
 
              info++;
              buffer->len++;
@@ -1048,6 +979,7 @@ resize_and_retry:
          positions = position_buf;
        }
        hb_glyph_info_t *info = run_info;
+       CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
        if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
        {
          hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
@@ -1059,8 +991,8 @@ resize_and_retry:
            else /* last glyph */
              advance = run_advance - (positions[j].x - positions[0].x);
            info->mask = advance * x_mult;
-           info->var1.i32 = x_offset;
-           info->var2.i32 = positions[j].y * y_mult;
+           info->var1.u32 = x_offset;
+           info->var2.u32 = positions[j].y * y_mult;
            info++;
          }
        }
@@ -1075,8 +1007,8 @@ resize_and_retry:
            else /* last glyph */
              advance = run_advance - (positions[j].y - positions[0].y);
            info->mask = advance * y_mult;
-           info->var1.i32 = positions[j].x * x_mult;
-           info->var2.i32 = y_offset;
+           info->var1.u32 = positions[j].x * x_mult;
+           info->var2.u32 = y_offset;
            info++;
          }
        }
@@ -1091,20 +1023,10 @@ resize_and_retry:
       buffer->len += num_glyphs;
     }
 
-    /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
-     * or if it does, it doesn't resepct it.  So we get runs with wrong
-     * directions.  As such, disable the assert...  It wouldn't crash, but
-     * cursoring will be off...
-     *
-     * http://crbug.com/419769
-     */
-    if (0)
-    {
-      /* Make sure all runs had the expected direction. */
-      bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
-      assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
-      assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
-    }
+    /* Make sure all runs had the expected direction. */
+    bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+    assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
+    assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
 
     buffer->clear_positions ();
 
@@ -1115,16 +1037,16 @@ resize_and_retry:
       for (unsigned int i = 0; i < count; i++)
       {
        pos->x_advance = info->mask;
-       pos->x_offset = info->var1.i32;
-       pos->y_offset = info->var2.i32;
+       pos->x_offset = info->var1.u32;
+       pos->y_offset = info->var2.u32;
        info++, pos++;
       }
     else
       for (unsigned int i = 0; i < count; i++)
       {
        pos->y_advance = info->mask;
-       pos->x_offset = info->var1.i32;
-       pos->y_offset = info->var2.i32;
+       pos->x_offset = info->var1.u32;
+       pos->y_offset = info->var2.u32;
        info++, pos++;
       }
 
@@ -1182,6 +1104,10 @@ fail:
  * AAT shaper
  */
 
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
+
+
 /*
  * shaper face data
  */