gfx/cairo/quartz-support-color-emoji-font.patch

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 From: Jonathan Kew <jkew@mozilla.com>
     2 bug 715798 pt 1 - support Apple Color Emoji font in cairo-quartz backend. r=jrmuizel
     4 diff --git a/gfx/cairo/cairo/src/cairo-quartz-font.c b/gfx/cairo/cairo/src/cairo-quartz-font.c
     5 --- a/gfx/cairo/cairo/src/cairo-quartz-font.c
     6 +++ b/gfx/cairo/cairo/src/cairo-quartz-font.c
     7 @@ -85,16 +85,20 @@ typedef struct {
     8      int descent;
     9      int leading;
    10  } quartz_CGFontMetrics;
    11  static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
    12  static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
    13  static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
    14  static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
    16 +/* CTFontCreateWithGraphicsFont is not public until 10.5. */
    17 +typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
    18 +static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
    19 +
    20  static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
    21  static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
    23  static void
    24  quartz_font_ensure_symbols(void)
    25  {
    26      if (_cairo_quartz_font_symbol_lookup_done)
    27  	return;
    28 @@ -122,16 +126,18 @@ quartz_font_ensure_symbols(void)
    29      CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
    30      CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
    31      CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
    32      CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
    34      CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
    35      CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
    37 +    CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
    38 +
    39      if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
    40  	CGFontGetGlyphBBoxesPtr &&
    41  	CGFontGetGlyphsForUnicharsPtr &&
    42  	CGFontGetUnitsPerEmPtr &&
    43  	CGFontGetGlyphAdvancesPtr &&
    44  	CGFontGetGlyphPathPtr &&
    45  	(CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
    46  	_cairo_quartz_font_symbols_present = TRUE;
    47 @@ -145,16 +151,17 @@ typedef struct _cairo_quartz_scaled_font
    48  struct _cairo_quartz_scaled_font {
    49      cairo_scaled_font_t base;
    50  };
    52  struct _cairo_quartz_font_face {
    53      cairo_font_face_t base;
    55      CGFontRef cgFont;
    56 +    CTFontRef ctFont;
    57  };
    59  /*
    60   * font face backend
    61   */
    63  static cairo_status_t
    64  _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
    65 @@ -229,16 +236,20 @@ static cairo_status_t
    66      return CAIRO_STATUS_SUCCESS;
    67  }
    69  static void
    70  _cairo_quartz_font_face_destroy (void *abstract_face)
    71  {
    72      cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
    74 +    if (font_face->ctFont) {
    75 +        CFRelease (font_face->ctFont);
    76 +    }
    77 +
    78      CGFontRelease (font_face->cgFont);
    79  }
    81  static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
    83  static cairo_status_t
    84  _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
    85  					    const cairo_matrix_t *font_matrix,
    86 @@ -353,16 +364,22 @@ cairo_quartz_font_face_create_for_cgfont
    87      if (!font_face) {
    88  	cairo_status_t ignore_status;
    89  	ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    90  	return (cairo_font_face_t *)&_cairo_font_face_nil;
    91      }
    93      font_face->cgFont = CGFontRetain (font);
    95 +    if (CTFontCreateWithGraphicsFontPtr) {
    96 +        font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
    97 +    } else {
    98 +        font_face->ctFont = NULL;
    99 +    }
   100 +
   101      _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
   103      return &font_face->base;
   104  }
   106  /*
   107   * scaled font backend
   108   */
   109 @@ -772,16 +789,24 @@ static const cairo_scaled_font_backend_t
   110  CGFontRef
   111  _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
   112  {
   113      cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
   115      return ffont->cgFont;
   116  }
   118 +CTFontRef
   119 +_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
   120 +{
   121 +    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
   122 +
   123 +    return ffont->ctFont;
   124 +}
   125 +
   126  #ifndef __LP64__
   127  /*
   128   * compat with old ATSUI backend
   129   */
   131  /**
   132   * cairo_quartz_font_face_create_for_atsu_font_id
   133   * @font_id: an ATSUFontID for the font.
   134 diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h
   135 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h
   136 +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
   137 @@ -45,16 +45,19 @@
   138  #include "cairo-surface-clipper-private.h"
   140  #ifdef CGFLOAT_DEFINED
   141  typedef CGFloat cairo_quartz_float_t;
   142  #else
   143  typedef float cairo_quartz_float_t;
   144  #endif
   146 +/* define CTFontRef for pre-10.5 SDKs */
   147 +typedef const struct __CTFont *CTFontRef;
   148 +
   149  typedef struct cairo_quartz_surface {
   150      cairo_surface_t base;
   152      CGContextRef cgContext;
   153      CGAffineTransform cgContextBaseCTM;
   155      void *imageData;
   156      cairo_surface_t *imageSurfaceEquiv;
   157 @@ -99,15 +102,18 @@ CGImageRef
   158  			      cairo_bool_t interpolate,
   159  			      CGColorSpaceRef colorSpaceOverride,
   160  			      CGDataProviderReleaseDataCallback releaseCallback,
   161  			      void *releaseInfo);
   163  CGFontRef
   164  _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
   166 +CTFontRef
   167 +_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
   168 +
   169  #else
   171  # error Cairo was not compiled with support for the quartz backend
   173  #endif /* CAIRO_HAS_QUARTZ_SURFACE */
   175  #endif /* CAIRO_QUARTZ_PRIVATE_H */
   176 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
   177 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
   178 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
   179 @@ -130,16 +130,19 @@ static void (*CGContextClipToMaskPtr) (C
   180  static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL;
   181  static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
   182  static void (*CGContextSetShouldAntialiasFontsPtr) (CGContextRef, bool) = NULL;
   183  static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
   184  static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
   185  static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
   186  static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
   188 +/* CTFontDrawGlyphs is not available until 10.7 */
   189 +static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
   190 +
   191  static SInt32 _cairo_quartz_osx_version = 0x0;
   193  static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
   195  /*
   196   * Utility functions
   197   */
   199 @@ -167,16 +170,18 @@ static void quartz_ensure_symbols(void)
   200      CGContextDrawTiledImagePtr = dlsym(RTLD_DEFAULT, "CGContextDrawTiledImage");
   201      CGContextGetTypePtr = dlsym(RTLD_DEFAULT, "CGContextGetType");
   202      CGContextSetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldAntialiasFonts");
   203      CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath");
   204      CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
   205      CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
   206      CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
   208 +    CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
   209 +
   210      if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
   211          // assume 10.5
   212          _cairo_quartz_osx_version = 0x1050;
   213      }
   215      _cairo_quartz_symbol_lookup_done = TRUE;
   216  }
   218 @@ -605,20 +610,23 @@ static inline void
   219      dst->d = src->yy;
   220      dst->tx = src->x0;
   221      dst->ty = src->y0;
   222  }
   224  typedef struct {
   225      bool isClipping;
   226      CGGlyph *cg_glyphs;
   227 -    CGSize *cg_advances;
   228 +    union {
   229 +      CGSize *cg_advances;
   230 +      CGPoint *cg_positions;
   231 +    } u;
   232      size_t nglyphs;
   233      CGAffineTransform textTransform;
   234 -    CGFontRef font;
   235 +    cairo_scaled_font_t *scaled_font;
   236      CGPoint origin;
   237  } unbounded_show_glyphs_t;
   239  typedef struct {
   240      CGPathRef cgPath;
   241      cairo_fill_rule_t fill_rule;
   242  } unbounded_stroke_fill_t;
   244 @@ -686,36 +694,43 @@ static void
   245  	CGContextBeginPath (cgc);
   246  	CGContextAddPath (cgc, op->u.stroke_fill.cgPath);
   248  	if (op->u.stroke_fill.fill_rule == CAIRO_FILL_RULE_WINDING)
   249  	    CGContextFillPath (cgc);
   250  	else
   251  	    CGContextEOFillPath (cgc);
   252      } else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
   253 -	CGContextSetFont (cgc, op->u.show_glyphs.font);
   254 -	CGContextSetFontSize (cgc, 1.0);
   255 -	CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
   256 -	CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
   257 -	CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
   258 -
   259  	if (op->u.show_glyphs.isClipping) {
   260  	    /* Note that the comment in show_glyphs about kCGTextClip
   261  	     * and the text transform still applies here; however, the
   262  	     * cg_advances we have were already transformed, so we
   263  	     * don't have to do anything. */
   264  	    CGContextSetTextDrawingMode (cgc, kCGTextClip);
   265  	    CGContextSaveGState (cgc);
   266  	}
   267 -
   268 -	CGContextShowGlyphsWithAdvances (cgc,
   269 -					 op->u.show_glyphs.cg_glyphs,
   270 -					 op->u.show_glyphs.cg_advances,
   271 -					 op->u.show_glyphs.nglyphs);
   272 -
   273 +        CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
   274 +        CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
   275 +        if (CTFontDrawGlyphsPtr) {
   276 +            CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
   277 +                                 op->u.show_glyphs.cg_glyphs,
   278 +                                 op->u.show_glyphs.u.cg_positions,
   279 +                                 op->u.show_glyphs.nglyphs,
   280 +                                 cgc);
   281 +        } else {
   282 +	    CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
   283 +	    CGContextSetFontSize (cgc, 1.0);
   284 +	    CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
   285 +
   286 +	    CGContextShowGlyphsWithAdvances (cgc,
   287 +					     op->u.show_glyphs.cg_glyphs,
   288 +					     op->u.show_glyphs.u.cg_advances,
   289 +					     op->u.show_glyphs.nglyphs);
   290 +
   291 +        }
   292  	if (op->u.show_glyphs.isClipping) {
   293  	    CGContextClearRect (cgc, clipBoxRound);
   294  	    CGContextRestoreGState (cgc);
   295  	}
   296      } else if (op->op == UNBOUNDED_MASK) {
   297  	CGAffineTransform ctm = CGContextGetCTM (cgc);
   298  	CGContextSaveGState (cgc);
   299  	CGContextConcatCTM (cgc, op->u.mask.maskTransform);
   300 @@ -2684,16 +2699,19 @@ static cairo_int_status_t
   301  				      cairo_clip_t *clip,
   302  				      int *remaining_glyphs)
   303  {
   304      CGAffineTransform textTransform, ctm, invTextTransform;
   305  #define STATIC_BUF_SIZE 64
   306      CGGlyph glyphs_static[STATIC_BUF_SIZE];
   307      CGSize cg_advances_static[STATIC_BUF_SIZE];
   308      CGGlyph *cg_glyphs = &glyphs_static[0];
   309 +    /* We'll use the cg_advances array for either advances or positions,
   310 +       depending which API we're using to actually draw. The types involved
   311 +       have the same size, so this is safe. */
   312      CGSize *cg_advances = &cg_advances_static[0];
   314      cairo_rectangle_int_t glyph_extents;
   315      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
   316      cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
   317      cairo_quartz_drawing_state_t state;
   318      cairo_quartz_float_t xprev, yprev;
   319      int i;
   320 @@ -2796,41 +2814,62 @@ static cairo_int_status_t
   321      invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
   322  					      -scaled_font->scale_inverse.yx,
   323  					      scaled_font->scale_inverse.xy,
   324  					      -scaled_font->scale_inverse.yy,
   325  					      0.0, 0.0);
   327      CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
   329 -    /* Convert our glyph positions to glyph advances.  We need n-1 advances,
   330 -     * since the advance at index 0 is applied after glyph 0. */
   331 -    xprev = glyphs[0].x;
   332 -    yprev = glyphs[0].y;
   333 -
   334 -    cg_glyphs[0] = glyphs[0].index;
   335 -
   336 -    for (i = 1; i < num_glyphs; i++) {
   337 -	cairo_quartz_float_t xf = glyphs[i].x;
   338 -	cairo_quartz_float_t yf = glyphs[i].y;
   339 -	cg_glyphs[i] = glyphs[i].index;
   340 -	cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
   341 -	xprev = xf;
   342 -	yprev = yf;
   343 -    }
   344 -
   345      /* Translate to the first glyph's position before drawing */
   346      ctm = CGContextGetCTM (state.context);
   347      CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
   348      CGContextConcatCTM (state.context, textTransform);
   350 -    CGContextShowGlyphsWithAdvances (state.context,
   351 -				     cg_glyphs,
   352 -				     cg_advances,
   353 -				     num_glyphs);
   354 +    if (CTFontDrawGlyphsPtr) {
   355 +        /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
   356 +         * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
   357 +         * fonts like Apple Color Emoji will render properly.
   358 +         * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
   359 +         * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
   360 +
   361 +        CGPoint *cg_positions = (CGPoint*) cg_advances;
   362 +        cairo_quartz_float_t origin_x = glyphs[0].x;
   363 +        cairo_quartz_float_t origin_y = glyphs[0].y;
   364 +
   365 +        for (i = 0; i < num_glyphs; i++) {
   366 +            CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
   367 +            cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
   368 +            cg_glyphs[i] = glyphs[i].index;
   369 +        }
   370 +
   371 +        CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
   372 +                             cg_glyphs, cg_positions, num_glyphs, state.context);
   373 +    } else {
   374 +        /* Convert our glyph positions to glyph advances.  We need n-1 advances,
   375 +         * since the advance at index 0 is applied after glyph 0. */
   376 +        xprev = glyphs[0].x;
   377 +        yprev = glyphs[0].y;
   378 +
   379 +        cg_glyphs[0] = glyphs[0].index;
   380 +
   381 +        for (i = 1; i < num_glyphs; i++) {
   382 +	    cairo_quartz_float_t xf = glyphs[i].x;
   383 +	    cairo_quartz_float_t yf = glyphs[i].y;
   384 +	    cg_glyphs[i] = glyphs[i].index;
   385 +	    cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
   386 +	    xprev = xf;
   387 +	    yprev = yf;
   388 +        }
   389 +
   390 +        CGContextShowGlyphsWithAdvances (state.context,
   391 +				         cg_glyphs,
   392 +				         cg_advances,
   393 +				         num_glyphs);
   394 +    }
   396      CGContextSetCTM (state.context, ctm);
   398      if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
   399          state.action == DO_LAYER) {
   400  	_cairo_quartz_draw_image (&state, op);
   401      } else if (state.action == DO_SHADING) {
   402  	CGContextConcatCTM (state.context, state.transform);
   403 @@ -2847,20 +2886,27 @@ BAIL:
   404  	cgfref &&
   405  	!_cairo_operator_bounded_by_mask (op))
   406      {
   407  	unbounded_op_data_t ub;
   408  	ub.op = UNBOUNDED_SHOW_GLYPHS;
   410  	ub.u.show_glyphs.isClipping = isClipping;
   411  	ub.u.show_glyphs.cg_glyphs = cg_glyphs;
   412 -	ub.u.show_glyphs.cg_advances = cg_advances;
   413 +	if (CTFontDrawGlyphsPtr) {
   414 +	    /* we're using Core Text API: the cg_advances array was
   415 +	       reused (above) for glyph positions */
   416 +            CGPoint *cg_positions = (CGPoint*) cg_advances;
   417 +	    ub.u.show_glyphs.u.cg_positions = cg_positions;
   418 +	} else {
   419 +	    ub.u.show_glyphs.u.cg_advances = cg_advances;
   420 +	}
   421  	ub.u.show_glyphs.nglyphs = num_glyphs;
   422  	ub.u.show_glyphs.textTransform = textTransform;
   423 -	ub.u.show_glyphs.font = cgfref;
   424 +	ub.u.show_glyphs.scaled_font = scaled_font;
   425  	ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
   427  	_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
   428      }
   431      if (cg_advances != &cg_advances_static[0]) {
   432  	free (cg_advances);

mercurial