summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ralls <jralls@ceridwen.us>2022-04-21 17:19:15 -0700
committerJohn Ralls <jralls@ceridwen.us>2022-04-24 13:08:48 -0700
commitc6dc5df61264be1bec2e622355b97c6c45d236fc (patch)
treea1813c4b01a33a4a944fe57ece09ac48526e8365
parentcf351a8a0a5c0be291061f58db9853a95b9044d3 (diff)
[quartz] Convert font handling from CGFont to CTFont.
-rw-r--r--src/cairo-quartz-font.c301
-rw-r--r--src/cairo-quartz-private.h2
-rw-r--r--src/cairo-quartz-surface.c83
-rw-r--r--test/reference/overlapping-glyphs.quartz.argb32.ref.pngbin2766 -> 2687 bytes
-rw-r--r--test/reference/overlapping-glyphs.quartz.rgb24.ref.pngbin1667 -> 1630 bytes
5 files changed, 184 insertions, 202 deletions
diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
index 3a702ca0e..9e667e0d6 100644
--- a/src/cairo-quartz-font.c
+++ b/src/cairo-quartz-font.c
@@ -44,6 +44,7 @@
#include "cairo-error-private.h"
+//#define DEBUG /* Uncomment this to get debug messages on the console. */
/**
* SECTION:cairo-quartz-fonts
* @Title: Quartz (CGFont) Fonts
@@ -66,11 +67,19 @@ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
+/* Cairo's transformations assume a unit-scaled font. */
+static const CGFloat font_scale = 1.0;
/* Defined in 10.11 */
#define CGGLYPH_MAX ((CGGlyph) 0xFFFE) /* kCGFontIndexMax */
#define CGGLYPH_INVALID ((CGGlyph) 0xFFFF) /* kCGFontIndexInvalid */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation
+#else
+#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
+#endif
+
static void
quartz_font_ensure_symbols(void)
{
@@ -90,14 +99,13 @@ typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;
struct _cairo_quartz_scaled_font {
cairo_scaled_font_t base;
+ CTFontRef ctFont;
};
struct _cairo_quartz_font_face {
cairo_font_face_t base;
CGFontRef cgFont;
- CTFontRef ctFont;
- double ctFont_scale;
};
/*
@@ -111,7 +119,7 @@ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
const char *family;
char *full_name;
CFStringRef FontName = NULL;
- CTFontRef ctFont = NULL;
+ CGFontRef cgFont = NULL;
int loop;
family = toy_face->family;
@@ -151,20 +159,20 @@ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
}
FontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
- ctFont = CTFontCreateWithName (FontName, 1.0, NULL);
+ cgFont = CGFontCreateWithFontName (FontName);
CFRelease (FontName);
- if (ctFont)
+ if (cgFont)
break;
}
- if (!ctFont) {
+ if (!cgFont) {
/* Give up */
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- *font_face = _cairo_quartz_font_face_create_for_ctfont (ctFont);
- CFRelease (ctFont);
+ *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
+ CFRelease (cgFont);
return CAIRO_STATUS_SUCCESS;
}
@@ -175,12 +183,56 @@ _cairo_quartz_font_face_destroy (void *abstract_face)
cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
CGFontRelease (font_face->cgFont);
- CFRelease (font_face->ctFont);
return TRUE;
}
static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
+#ifdef DEBUG
+static void
+_cairo_quartz_debug_font_characteristics (cairo_quartz_scaled_font_t *font)
+{
+ CGRect ct_bbox = CTFontGetBoundingBox (font->ctFont);
+ CGFloat ct_ascent = CTFontGetAscent (font->ctFont);
+ CGFloat ct_descent = CTFontGetDescent (font->ctFont);
+ CGFloat ct_leading = CTFontGetLeading (font->ctFont);
+ CGFloat ct_capheight = CTFontGetCapHeight (font->ctFont);
+ CGFloat ct_xheight = CTFontGetXHeight (font->ctFont);
+ char chars[] = "ymMW";
+ CGGlyph glyphs[4];
+ UniChar *utf16 = NULL;
+ CGSize ct_advances[4];
+ CGRect ct_gbbox[4], ct_gobox[4], ct_rbbox, ct_robox;
+ double ct_radvance;
+ int converted;
+ cairo_status_t rv;
+
+ rv = _cairo_utf8_to_utf16 (chars, 4, &utf16, &converted);
+ if (rv) return;
+ CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyphs, 4);
+ free (utf16);
+ ct_rbbox = CTFontGetBoundingRectsForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, glyphs, ct_gbbox, 4);
+ ct_robox = CTFontGetOpticalBoundsForGlyphs (font->ctFont, glyphs, ct_gobox, 4, 0);
+ ct_radvance = CTFontGetAdvancesForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, glyphs, ct_advances, 4);
+
+ fprintf (stderr, "\nCTFont Bounding Box: %f %f %f %f\nAscent %f Descent %f Leading %f Cap Height %f X-Height %f\n",
+ ct_bbox.origin.x, ct_bbox.origin.y, ct_bbox.size.width, ct_bbox.size.height, ct_ascent, ct_descent,
+ ct_leading, ct_capheight, ct_xheight);
+ fprintf (stderr, "CTFont string\n\t bounding box %f %f %f %f advance %f\n\toptical box %f %f %f %f\n\n",
+ ct_rbbox.origin.x, ct_rbbox.origin.y, ct_rbbox.size.width, ct_rbbox.size.height, ct_radvance,
+ ct_robox.origin.x, ct_robox.origin.y, ct_robox.size.width, ct_robox.size.height);
+ for (int i = 0; i < 4; ++i)
+ {
+ fprintf (stderr, "Character %c\n", chars[i]);
+ fprintf (stderr, "\tbox %f %f %f %f\n\toptical %f %f %f %f advance %f %f\n",
+ ct_gbbox[i].origin.x, ct_gbbox[i].origin.y, ct_gbbox[i].size.width, ct_gbbox[i].size.height,
+ ct_advances[i].width, ct_advances[i].height,
+ ct_gobox[i].origin.x, ct_gobox[i].origin.y, ct_gobox[i].size.width, ct_gobox[i].size.height);
+ }
+ fprintf (stderr, "\n");
+}
+#endif
+
static cairo_status_t
_cairo_quartz_font_face_scaled_font_create (void *abstract_face,
const cairo_matrix_t *font_matrix,
@@ -192,7 +244,7 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
cairo_quartz_scaled_font_t *font = NULL;
cairo_status_t status;
cairo_font_extents_t fs_metrics;
- double ems;
+ CTFontRef ctFont;
CGRect bbox;
font = _cairo_malloc (sizeof(cairo_quartz_scaled_font_t));
@@ -207,19 +259,29 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
if (status)
goto FINISH;
- ems = CGFontGetUnitsPerEm (font_face->cgFont);
-
+ ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, font_scale, NULL, NULL);
/* initialize metrics */
- fs_metrics.ascent = (CGFontGetAscent (font_face->cgFont) / ems);
- fs_metrics.descent = - (CGFontGetDescent (font_face->cgFont) / ems);
+ fs_metrics.ascent = CTFontGetAscent (ctFont);
+ fs_metrics.descent = CTFontGetDescent (ctFont);
fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
- (CGFontGetLeading (font_face->cgFont) / ems);
+ CTFontGetLeading (ctFont);
- bbox = CGFontGetFontBBox (font_face->cgFont);
- fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
+ bbox = CTFontGetBoundingBox (ctFont);
+ fs_metrics.max_x_advance = CGRectGetMaxX(bbox);
fs_metrics.max_y_advance = 0.0;
-
+ font->ctFont = CFRetain (ctFont);
status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
+#ifdef DEBUG
+ {
+ CFStringRef fontFullName = CTFontCopyFullName (ctFont);
+ const char* font_full_name = CFStringGetCStringPtr(fontFullName, kCFStringEncodingUTF8);
+
+ fprintf (stderr, "Create scaled font %s with scale %f ascent %f, descent %f, height %f, x-advance %f\n",
+ font_full_name, fs_metrics.ascent, fs_metrics.descent, fs_metrics.height,
+ fs_metrics.max_x_advance);
+ _cairo_quartz_debug_font_characteristics (font);
+ }
+#endif
FINISH:
if (status != CAIRO_STATUS_SUCCESS) {
@@ -272,29 +334,11 @@ cairo_font_face_t *
cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
{
cairo_quartz_font_face_t* font_face = _cairo_quartz_font_face_create ();
- double font_scale = 1.0; /* 1.0 produces glyphs of the right size to pass tests. */
if (cairo_font_face_status (&font_face->base))
return &font_face->base;
font_face->cgFont = CGFontRetain (font);
- font_face->ctFont = CTFontCreateWithGraphicsFont (font, font_scale, NULL, NULL);
- font_face->ctFont_scale = CTFontGetUnitsPerEm(font_face->ctFont);
-
- return &font_face->base;
-}
-
-cairo_font_face_t *
-_cairo_quartz_font_face_create_for_ctfont (CTFontRef font)
-{
- cairo_quartz_font_face_t* font_face = _cairo_quartz_font_face_create ();
-
- if (cairo_font_face_status (&font_face->base))
- return &font_face->base;
-
- font_face->ctFont = CFRetain (font);
- font_face->cgFont = CTFontCopyGraphicsFont (font, NULL);
- font_face->ctFont_scale = CTFontGetUnitsPerEm(font_face->ctFont);
return &font_face->base;
}
@@ -315,6 +359,8 @@ _cairo_quartz_scaled_to_face (void *abstract_font)
static void
_cairo_quartz_scaled_font_fini(void *abstract_font)
{
+ cairo_quartz_scaled_font_t* font = (cairo_quartz_scaled_font_t*)abstract_font;
+ CFRelease (font->ctFont);
}
static inline CGGlyph
@@ -329,21 +375,17 @@ _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
- int advance;
+ CGSize advance;
CGRect bbox;
- double emscale = CGFontGetUnitsPerEm (font_face->cgFont);
double xmin, ymin, xmax, ymax;
if (unlikely (glyph == CGGLYPH_INVALID))
goto FAIL;
- if (!CGFontGetGlyphAdvances (font_face->cgFont, &glyph, 1, &advance) ||
- !CGFontGetGlyphBBoxes (font_face->cgFont, &glyph, 1, &bbox))
- goto FAIL;
-
+ CTFontGetAdvancesForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &advance, 1);
+ CTFontGetBoundingRectsForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &bbox, 1);
/* broken fonts like Al Bayan return incorrect bounds for some null characters,
see https://bugzilla.mozilla.org/show_bug.cgi?id=534260 */
if (unlikely (bbox.origin.x == -32767 &&
@@ -354,31 +396,9 @@ _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
bbox.size.width = bbox.size.height = 0;
}
- bbox = CGRectMake (bbox.origin.x / emscale,
- bbox.origin.y / emscale,
- bbox.size.width / emscale,
- bbox.size.height / emscale);
-
- /* Should we want to always integer-align glyph extents, we can do so in this way */
-#if 0
- {
- CGAffineTransform textMatrix;
- textMatrix = CGAffineTransformMake (font->base.scale.xx,
- -font->base.scale.yx,
- -font->base.scale.xy,
- font->base.scale.yy,
- 0.0f, 0.0f);
-
- bbox = CGRectApplyAffineTransform (bbox, textMatrix);
- bbox = CGRectIntegral (bbox);
- bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix));
- }
-#endif
-
-#if 0
- fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph,
- bbox.origin.x / emscale, bbox.origin.y / emscale,
- bbox.size.width / emscale, bbox.size.height / emscale);
+#ifdef DEBUG
+ fprintf (stderr, "[0x%04x] bbox: x %f y %f width %f height %f\n", glyph,
+ bbox.origin.x, bbox.origin.y, bbox.size.width, bbox.size.height);
#endif
xmin = CGRectGetMinX(bbox);
@@ -391,12 +411,12 @@ _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
extents.width = xmax - xmin;
extents.height = ymax - ymin;
- extents.x_advance = (double) advance / emscale;
- extents.y_advance = 0.0;
+ extents.x_advance = advance.width;
+ extents.y_advance = advance.height;
-#if 0
- fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph,
- extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance);
+#ifdef DEBUG
+ fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f %f\n\n", glyph,
+ extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance, extents.y_advance);
#endif
FAIL:
@@ -452,7 +472,7 @@ _cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
_cairo_fixed_from_double(el->points[1].y),
_cairo_fixed_from_double(el->points[2].x),
_cairo_fixed_from_double(el->points[2].y));
- assert(!status);
+ assert(!status);
break;
case kCGPathElementCloseSubpath:
status = _cairo_path_fixed_close_path (path);
@@ -465,7 +485,6 @@ static cairo_int_status_t
_cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
cairo_scaled_glyph_t *scaled_glyph)
{
- cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
CGAffineTransform textMatrix;
CGPathRef glyphPath;
@@ -483,7 +502,7 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
-font->base.scale.yy,
0, 0);
- glyphPath = CTFontCreatePathForGlyph (font_face->ctFont, glyph, &textMatrix);
+ glyphPath = CTFontCreatePathForGlyph (font->ctFont, glyph, &textMatrix);
if (!glyphPath)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -508,25 +527,25 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-
- cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
-
cairo_image_surface_t *surface = NULL;
CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
-
- int advance;
- CGRect bbox;
+ cairo_text_extents_t metrics = scaled_glyph->fs_metrics;
+ CGRect bbox = CGRectMake (metrics.x_bearing, -(metrics.y_bearing + metrics.height),
+ metrics.width, metrics.height);
double width, height;
- double emscale = CGFontGetUnitsPerEm (font_face->cgFont);
- CGContextRef cgContext = NULL;
CGAffineTransform textMatrix;
CGRect glyphRect, glyphRectInt;
CGPoint glyphOrigin;
- //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface);
-
+#ifdef DEBUG
+ fprintf (stderr, "[0x%04x] bearing: %f %f width %f height %f advances %f %f\n",
+ glyph, metrics.x_bearing, metrics.y_bearing, metrics.width, metrics.height,
+ metrics.x_advance, metrics.y_advance);
+ fprintf (stderr, "[0x%04x] bounds: origin %f %f, size %f %f\n", glyph, bbox.origin.x,
+ bbox.origin.y, bbox.size.width, bbox.size.height);
+#endif
/* Create blank 2x2 image if we don't have this character.
* Maybe we should draw a better missing-glyph slug or something,
* but this is ok for now.
@@ -543,27 +562,20 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
return CAIRO_STATUS_SUCCESS;
}
- CTFontGetBoundingRectsForGlyphs (font_face->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &bbox, 1);
-
/* scale(1,-1) * font->base.scale * scale(1,-1) */
textMatrix = CGAffineTransformMake (font->base.scale.xx,
-font->base.scale.yx,
-font->base.scale.xy,
font->base.scale.yy,
- 0, -0);
- glyphRect = CGRectMake (bbox.origin.x / emscale,
- bbox.origin.y / emscale,
- bbox.size.width / emscale,
- bbox.size.height / emscale);
-
- glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix);
+ 0, 0);
+ glyphRect = CGRectApplyAffineTransform (bbox, textMatrix);
/* Round the rectangle outwards, so that we don't have to deal
* with non-integer-pixel origins or dimensions.
*/
glyphRectInt = CGRectIntegral (glyphRect);
-#if 0
+#ifdef DEBUG
fprintf (stderr, "glyphRect[o]: %f %f %f %f\n",
glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
fprintf (stderr, "glyphRectInt: %f %f %f %f\n",
@@ -572,63 +584,32 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
glyphOrigin = glyphRectInt.origin;
- //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm));
-
width = glyphRectInt.size.width;
height = glyphRectInt.size.height;
- //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
-
surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
if (surface->base.status)
return surface->base.status;
if (surface->width != 0 && surface->height != 0) {
- cgContext = CGBitmapContextCreate (surface->data,
- surface->width,
- surface->height,
- 8,
- surface->stride,
- NULL,
- kCGImageAlphaOnly);
+ CGContextRef cgContext = CGBitmapContextCreate (surface->data,
+ surface->width,
+ surface->height,
+ 8,
+ surface->stride,
+ NULL,
+ kCGImageAlphaOnly);
if (cgContext == NULL) {
cairo_surface_destroy (&surface->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- CGContextSetFont (cgContext, font_face->cgFont);
- CGContextSetFontSize (cgContext, 1.0);
- CGContextSetTextMatrix (cgContext, textMatrix);
-
- switch (font->base.options.antialias) {
- case CAIRO_ANTIALIAS_SUBPIXEL:
- case CAIRO_ANTIALIAS_BEST:
- CGContextSetShouldAntialias (cgContext, TRUE);
- CGContextSetShouldSmoothFonts (cgContext, TRUE);
- quartz_font_ensure_symbols ();
- if (CGContextGetAllowsFontSmoothingPtr &&
- !CGContextGetAllowsFontSmoothingPtr (cgContext))
- CGContextSetAllowsFontSmoothing (cgContext, TRUE);
- break;
- case CAIRO_ANTIALIAS_NONE:
- CGContextSetShouldAntialias (cgContext, FALSE);
- break;
- case CAIRO_ANTIALIAS_GRAY:
- case CAIRO_ANTIALIAS_GOOD:
- case CAIRO_ANTIALIAS_FAST:
- CGContextSetShouldAntialias (cgContext, TRUE);
- CGContextSetShouldSmoothFonts (cgContext, FALSE);
- break;
- case CAIRO_ANTIALIAS_DEFAULT:
- default:
- /* Don't do anything */
- break;
- }
-
+ _cairo_quartz_set_antialiasing (cgContext, font->base.options.antialias);
CGContextSetAlpha (cgContext, 1.0);
- CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1);
-
+ CGContextTranslateCTM (cgContext, -glyphOrigin.x, -glyphOrigin.y);
+ CGContextConcatCTM (cgContext, textMatrix);
+ CTFontDrawGlyphs (font->ctFont, &glyph, &CGPointZero, 1, cgContext);
CGContextRelease (cgContext);
}
@@ -667,12 +648,11 @@ _cairo_quartz_ucs4_to_index (void *abstract_font,
uint32_t ucs4)
{
cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
- cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(font);
CGGlyph glyph[2];
UniChar utf16[2];
int len = _cairo_ucs4_to_utf16 (ucs4, utf16);
- CTFontGetGlyphsForCharacters (ffont->ctFont, utf16, glyph, len);
+ CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyph, len);
return glyph[0];
}
@@ -683,8 +663,8 @@ _cairo_quartz_load_truetype_table (void *abstract_font,
unsigned char *buffer,
unsigned long *length)
{
- cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face (abstract_font);
- CFDataRef data = CGFontCopyTableForTag (font_face->cgFont, tag);
+ cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
+ CFDataRef data = CTFontCopyTable (font->ctFont, tag, kCTFontTableOptionNoOptions);
if (!data)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -728,6 +708,43 @@ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
return ffont->cgFont;
}
+CTFontRef
+_cairo_quartz_scaled_font_get_ct_font (cairo_scaled_font_t *abstract_font)
+{
+ cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
+
+ return font->ctFont;
+}
+
+ void
+ _cairo_quartz_set_antialiasing (CGContextRef cgContext, cairo_antialias_t antialias)
+{
+ switch (antialias) {
+ case CAIRO_ANTIALIAS_SUBPIXEL:
+ case CAIRO_ANTIALIAS_BEST:
+ CGContextSetShouldAntialias (cgContext, TRUE);
+ CGContextSetShouldSmoothFonts (cgContext, TRUE);
+ quartz_font_ensure_symbols ();
+ if (CGContextGetAllowsFontSmoothingPtr &&
+ !CGContextGetAllowsFontSmoothingPtr (cgContext))
+ CGContextSetAllowsFontSmoothing (cgContext, TRUE);
+ break;
+ case CAIRO_ANTIALIAS_NONE:
+ CGContextSetShouldAntialias (cgContext, FALSE);
+ break;
+ case CAIRO_ANTIALIAS_GRAY:
+ case CAIRO_ANTIALIAS_GOOD:
+ case CAIRO_ANTIALIAS_FAST:
+ CGContextSetShouldAntialias (cgContext, TRUE);
+ CGContextSetShouldSmoothFonts (cgContext, FALSE);
+ break;
+ case CAIRO_ANTIALIAS_DEFAULT:
+ default:
+ /* Don't do anything */
+ break;
+ }
+
+}
/*
* compat with old ATSUI backend
*/
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index e3600d5fc..f142f8471 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -109,6 +109,8 @@ cairo_private CTFontRef
_cairo_quartz_scaled_font_get_ct_font (cairo_scaled_font_t *sfont);
cairo_private cairo_font_face_t*
_cairo_quartz_font_face_create_for_ctfont (CTFontRef ctFont);
+cairo_private void
+_cairo_quartz_set_antialiasing (CGContextRef context, cairo_antialias_t antialias);
#else
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index bc6968c06..ae6546029 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -65,6 +65,12 @@
#endif
#define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0)
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation
+#else
+#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
+#endif
+
/**
* SECTION:cairo-quartz
@@ -1894,17 +1900,15 @@ _cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
cairo_bool_t overlap)
{
CGAffineTransform textTransform, invTextTransform;
- CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
- CGSize cg_advances_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
+ CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGGlyph)];
+ CGPoint cg_positions_static[CAIRO_STACK_ARRAY_LENGTH (CGPoint)];
CGGlyph *cg_glyphs = &glyphs_static[0];
- CGSize *cg_advances = &cg_advances_static[0];
- COMPILE_TIME_ASSERT (sizeof (CGGlyph) <= sizeof (CGSize));
+ CGPoint *cg_positions = &cg_positions_static[0];
cairo_quartz_drawing_state_t state;
cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
- cairo_quartz_float_t xprev, yprev;
- int i;
- CGFontRef cgfref = NULL;
+ CGPoint origin;
+ CTFontRef ctFont = NULL;
cairo_bool_t didForceFontSmoothing = FALSE;
@@ -1923,45 +1927,17 @@ _cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
}
/* this doesn't addref */
- cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
- CGContextSetFont (state.cgMaskContext, cgfref);
- CGContextSetFontSize (state.cgMaskContext, 1.0);
-
- switch (scaled_font->options.antialias) {
- case CAIRO_ANTIALIAS_SUBPIXEL:
- case CAIRO_ANTIALIAS_BEST:
- CGContextSetShouldAntialias (state.cgMaskContext, TRUE);
- CGContextSetShouldSmoothFonts (state.cgMaskContext, TRUE);
- quartz_ensure_symbols();
- if (CGContextGetAllowsFontSmoothingPtr &&
- !CGContextGetAllowsFontSmoothingPtr (state.cgMaskContext))
- {
- didForceFontSmoothing = TRUE;
- CGContextSetAllowsFontSmoothing (state.cgMaskContext, TRUE);
- }
- break;
- case CAIRO_ANTIALIAS_NONE:
- CGContextSetShouldAntialias (state.cgMaskContext, FALSE);
- break;
- case CAIRO_ANTIALIAS_GRAY:
- case CAIRO_ANTIALIAS_GOOD:
- case CAIRO_ANTIALIAS_FAST:
- CGContextSetShouldAntialias (state.cgMaskContext, TRUE);
- CGContextSetShouldSmoothFonts (state.cgMaskContext, FALSE);
- break;
- case CAIRO_ANTIALIAS_DEFAULT:
- /* Don't do anything */
- break;
- }
+ ctFont = _cairo_quartz_scaled_font_get_ct_font (scaled_font);
+ _cairo_quartz_set_antialiasing (state.cgMaskContext, scaled_font->options.antialias);
if (num_glyphs > ARRAY_LENGTH (glyphs_static)) {
- cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof (CGGlyph) + sizeof (CGSize));
+ cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof (CGGlyph) + sizeof (CGPoint));
if (unlikely (cg_glyphs == NULL)) {
rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
- cg_advances = (CGSize*) (cg_glyphs + num_glyphs);
+ cg_positions = (CGPoint*) (cg_glyphs + num_glyphs);
}
/* scale(1,-1) * scaled_font->scale */
@@ -1978,36 +1954,23 @@ _cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
-scaled_font->scale_inverse.yy,
0.0, 0.0);
- CGContextSetTextPosition (state.cgMaskContext, 0.0, 0.0);
- CGContextSetTextMatrix (state.cgMaskContext, CGAffineTransformIdentity);
- /* Convert our glyph positions to glyph advances. We need n-1 advances,
- * since the advance at index 0 is applied after glyph 0. */
- xprev = glyphs[0].x;
- yprev = glyphs[0].y;
-
- cg_glyphs[0] = glyphs[0].index;
-
- for (i = 1; i < num_glyphs; i++) {
- cairo_quartz_float_t xf = glyphs[i].x;
- cairo_quartz_float_t yf = glyphs[i].y;
+ origin = CGPointMake (glyphs[0].x, glyphs[0].y);
+ for (int i = 0; i < num_glyphs; ++i)
+ {
cg_glyphs[i] = glyphs[i].index;
- cg_advances[i - 1] = CGSizeApplyAffineTransform (CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
- xprev = xf;
- yprev = yf;
+ cg_positions[i] = CGPointMake (glyphs[i].x - origin.x, glyphs[i].y - origin.y);
+ cg_positions[i] = CGPointApplyAffineTransform (cg_positions[i], invTextTransform);
}
/* Translate to the first glyph's position before drawing */
- CGContextTranslateCTM (state.cgMaskContext, glyphs[0].x, glyphs[0].y);
+ CGContextTranslateCTM (state.cgMaskContext, origin.x, origin.y);
CGContextConcatCTM (state.cgMaskContext, textTransform);
- CGContextShowGlyphsWithAdvances (state.cgMaskContext,
- cg_glyphs,
- cg_advances,
- num_glyphs);
+ CTFontDrawGlyphs (ctFont, cg_glyphs, cg_positions, num_glyphs, state.cgMaskContext);
CGContextConcatCTM (state.cgMaskContext, invTextTransform);
- CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
+ CGContextTranslateCTM (state.cgMaskContext, -origin.x, -origin.y);
if (state.action != DO_DIRECT)
_cairo_quartz_draw_source (&state, extents->op);
diff --git a/test/reference/overlapping-glyphs.quartz.argb32.ref.png b/test/reference/overlapping-glyphs.quartz.argb32.ref.png
index 2bbbb3944..44200d59e 100644
--- a/test/reference/overlapping-glyphs.quartz.argb32.ref.png
+++ b/test/reference/overlapping-glyphs.quartz.argb32.ref.png
Binary files differ
diff --git a/test/reference/overlapping-glyphs.quartz.rgb24.ref.png b/test/reference/overlapping-glyphs.quartz.rgb24.ref.png
index a3961f8bf..d236e19a5 100644
--- a/test/reference/overlapping-glyphs.quartz.rgb24.ref.png
+++ b/test/reference/overlapping-glyphs.quartz.rgb24.ref.png
Binary files differ