summaryrefslogtreecommitdiff
path: root/src/cairo-quartz-surface.c
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2022-04-27 00:04:43 +0000
committerAdrian Johnson <ajohnson@redneon.com>2022-04-27 00:04:43 +0000
commit455a4cca5472a309d036b6393f1db0dc4403d303 (patch)
treeeadac9e15f0bcb4688020670a74e89655df96ef3 /src/cairo-quartz-surface.c
parentf07d539c07488edccd0bea241073572bc20c8ed1 (diff)
parentcfb3835f57abd05b5d862904dd1d4300ae990a8a (diff)
downloadcairo-455a4cca5472a309d036b6393f1db0dc4403d303.tar.gz
Merge branch 'quartz-core-text' into 'master'
quartz: support rendering colored bitmap fonts See merge request cairo/cairo!289
Diffstat (limited to 'src/cairo-quartz-surface.c')
-rw-r--r--src/cairo-quartz-surface.c259
1 files changed, 41 insertions, 218 deletions
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index fa6d9b1c9..97ddf2c28 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
@@ -85,46 +91,22 @@
* Since: 1.6
**/
-#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
-/* This method is private, but it exists. Its params are are exposed
- * as args to the NS* method, but not as CG.
- */
-enum PrivateCGCompositeMode {
- kPrivateCGCompositeClear = 0,
- kPrivateCGCompositeCopy = 1,
- kPrivateCGCompositeSourceOver = 2,
- kPrivateCGCompositeSourceIn = 3,
- kPrivateCGCompositeSourceOut = 4,
- kPrivateCGCompositeSourceAtop = 5,
- kPrivateCGCompositeDestinationOver = 6,
- kPrivateCGCompositeDestinationIn = 7,
- kPrivateCGCompositeDestinationOut = 8,
- kPrivateCGCompositeDestinationAtop = 9,
- kPrivateCGCompositeXOR = 10,
- kPrivateCGCompositePlusDarker = 11, // (max (0, (1-d) + (1-s)))
- kPrivateCGCompositePlusLighter = 12, // (min (1, s + d))
-};
-typedef enum PrivateCGCompositeMode PrivateCGCompositeMode;
-CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
-#endif
-
-/* Some of these are present in earlier versions of the OS than where
- * they are public; other are not public at all
- */
-
-/* public since 10.6 */
-static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
-static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
-
-/* not yet public */
-static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
-static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
-
-static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
-
/*
- * Utility functions
+ * macOS Private functions
*/
+static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
+static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
+static void
+quartz_ensure_symbols()
+{
+ static cairo_bool_t symbol_lookup_done = FALSE;
+ if (!symbol_lookup_done) {
+ CGContextGetTypePtr = dlsym (RTLD_DEFAULT, "CGContextGetType");
+ CGContextGetAllowsFontSmoothingPtr =
+ dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+ symbol_lookup_done = TRUE;
+ }
+}
#ifdef QUARTZ_DEBUG
static void quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest);
@@ -152,20 +134,6 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
unsigned int width,
unsigned int height);
-/* Load all extra symbols */
-static void quartz_ensure_symbols (void)
-{
- if (likely (_cairo_quartz_symbol_lookup_done))
- return;
-
- CGContextGetTypePtr = dlsym (RTLD_DEFAULT, "CGContextGetType");
- CGContextCopyPathPtr = dlsym (RTLD_DEFAULT, "CGContextCopyPath");
- CGContextGetAllowsFontSmoothingPtr = dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
- CGContextSetAllowsFontSmoothingPtr = dlsym (RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
-
- _cairo_quartz_symbol_lookup_done = TRUE;
-}
-
CGImageRef
CairoQuartzCreateCGImage (cairo_format_t format,
unsigned int width,
@@ -270,6 +238,7 @@ _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc)
if (unlikely (cgc == NULL))
return FALSE;
+ quartz_ensure_symbols ();
if (likely (CGContextGetTypePtr)) {
/* 4 is the type value of a bitmap context */
return CGContextGetTypePtr (cgc) == 4;
@@ -377,58 +346,6 @@ _cairo_quartz_cairo_path_to_quartz_context (const cairo_path_fixed_t *path,
* Misc helpers/callbacks
*/
-#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
-static PrivateCGCompositeMode
-_cairo_quartz_cairo_operator_to_quartz_composite (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return kPrivateCGCompositeClear;
- case CAIRO_OPERATOR_SOURCE:
- return kPrivateCGCompositeCopy;
- case CAIRO_OPERATOR_OVER:
- return kPrivateCGCompositeSourceOver;
- case CAIRO_OPERATOR_IN:
- return kPrivateCGCompositeSourceIn;
- case CAIRO_OPERATOR_OUT:
- return kPrivateCGCompositeSourceOut;
- case CAIRO_OPERATOR_ATOP:
- return kPrivateCGCompositeSourceAtop;
- case CAIRO_OPERATOR_DEST_OVER:
- return kPrivateCGCompositeDestinationOver;
- case CAIRO_OPERATOR_DEST_IN:
- return kPrivateCGCompositeDestinationIn;
- case CAIRO_OPERATOR_DEST_OUT:
- return kPrivateCGCompositeDestinationOut;
- case CAIRO_OPERATOR_DEST_ATOP:
- return kPrivateCGCompositeDestinationAtop;
- case CAIRO_OPERATOR_XOR:
- return kPrivateCGCompositeXOR;
- case CAIRO_OPERATOR_ADD:
- return kPrivateCGCompositePlusLighter;
-
- case CAIRO_OPERATOR_DEST:
- case CAIRO_OPERATOR_SATURATE:
- case CAIRO_OPERATOR_MULTIPLY:
- case CAIRO_OPERATOR_SCREEN:
- case CAIRO_OPERATOR_OVERLAY:
- case CAIRO_OPERATOR_DARKEN:
- case CAIRO_OPERATOR_LIGHTEN:
- case CAIRO_OPERATOR_COLOR_DODGE:
- case CAIRO_OPERATOR_COLOR_BURN:
- case CAIRO_OPERATOR_HARD_LIGHT:
- case CAIRO_OPERATOR_SOFT_LIGHT:
- case CAIRO_OPERATOR_DIFFERENCE:
- case CAIRO_OPERATOR_EXCLUSION:
- case CAIRO_OPERATOR_HSL_HUE:
- case CAIRO_OPERATOR_HSL_SATURATION:
- case CAIRO_OPERATOR_HSL_COLOR:
- case CAIRO_OPERATOR_HSL_LUMINOSITY:
- default:
- ASSERT_NOT_REACHED;
- }
-}
-#endif
static CGBlendMode
_cairo_quartz_cairo_operator_to_quartz_blend (cairo_operator_t op)
@@ -465,7 +382,6 @@ _cairo_quartz_cairo_operator_to_quartz_blend (cairo_operator_t op)
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return kCGBlendModeLuminosity;
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
case CAIRO_OPERATOR_CLEAR:
return kCGBlendModeClear;
case CAIRO_OPERATOR_SOURCE:
@@ -490,21 +406,6 @@ _cairo_quartz_cairo_operator_to_quartz_blend (cairo_operator_t op)
return kCGBlendModeXOR;
case CAIRO_OPERATOR_ADD:
return kCGBlendModePlusLighter;
-#else
- case CAIRO_OPERATOR_CLEAR:
- case CAIRO_OPERATOR_SOURCE:
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_ATOP:
- case CAIRO_OPERATOR_DEST_OVER:
- case CAIRO_OPERATOR_DEST_IN:
- case CAIRO_OPERATOR_DEST_OUT:
- case CAIRO_OPERATOR_DEST_ATOP:
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_ADD:
-#endif
-
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_SATURATE:
default:
@@ -534,16 +435,6 @@ _cairo_cgcontext_set_cairo_operator (CGContextRef context, cairo_operator_t op)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
- if (op <= CAIRO_OPERATOR_ADD) {
- PrivateCGCompositeMode compmode;
-
- compmode = _cairo_quartz_cairo_operator_to_quartz_composite (op);
- CGContextSetCompositeOperation (context, compmode);
- return CAIRO_STATUS_SUCCESS;
- }
-#endif
-
blendmode = _cairo_quartz_cairo_operator_to_quartz_blend (op);
CGContextSetBlendMode (context, blendmode);
return CAIRO_STATUS_SUCCESS;
@@ -1472,7 +1363,7 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface,
cairo_surface_t *return_surface = NULL;
unsigned int stride, bitinfo, bpp, color_comps;
CGColorSpaceRef colorspace;
- void *imageData;
+ unsigned char *imageData;
cairo_format_t format;
if (IS_EMPTY (surface))
@@ -1558,13 +1449,6 @@ _cairo_quartz_surface_finish (void *abstract_surface)
surface->cgContext = NULL;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 10600
- if (surface->imageData) {
- free (surface->imageData);
- surface->imageData = NULL;
- }
-#endif
-
if (surface->cgLayer)
{
CGLayerRelease (surface->cgLayer);
@@ -2016,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;
@@ -2045,44 +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);
- if (CGContextSetAllowsFontSmoothingPtr &&
- !CGContextGetAllowsFontSmoothingPtr (state.cgMaskContext))
- {
- didForceFontSmoothing = TRUE;
- CGContextSetAllowsFontSmoothingPtr (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 */
@@ -2099,43 +1954,30 @@ _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);
BAIL:
if (didForceFontSmoothing)
- CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, FALSE);
+ CGContextSetAllowsFontSmoothing (state.cgMaskContext, FALSE);
_cairo_quartz_teardown_state (&state, extents);
@@ -2319,8 +2161,6 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
{
cairo_quartz_surface_t *surface;
- quartz_ensure_symbols ();
-
/* Init the base surface */
surface = _cairo_malloc (sizeof (cairo_quartz_surface_t));
if (unlikely (surface == NULL))
@@ -2342,9 +2182,6 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
surface->extents.width = width;
surface->extents.height = height;
surface->virtual_extents = surface->extents;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 10600
- surface->imageData = NULL;
-#endif
if (IS_EMPTY (surface)) {
surface->cgContext = NULL;
@@ -2473,16 +2310,6 @@ cairo_quartz_surface_create (cairo_format_t format,
* so we don't have to anything special on allocation.
*/
stride = (stride + 15) & ~15;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 10600
- imageData = _cairo_malloc_ab (height, stride);
- if (unlikely (!imageData)) {
- CGColorSpaceRelease (cgColorspace);
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
-
- /* zero the memory to match the image surface behavior */
- memset (imageData, 0, height * stride);
-#endif /* For newer macOS versions let Core Graphics manage the buffer. */
cgc = CGBitmapContextCreate (imageData,
width,
height,
@@ -2515,9 +2342,6 @@ cairo_quartz_surface_create (cairo_format_t format,
return &surf->base;
}
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 10600
- surf->imageData = imageData;
-#endif
surf->base.is_clear = TRUE;
return &surf->base;
@@ -2633,7 +2457,7 @@ quartz_image_to_png (CGImageRef image, const char *dest)
memset (pathbuf, 0, sizeof (pathbuf));
dest = dest ? dest : image_name;
- snprintf (pathbuf, sizeof (pathbuf), "%s/Desktop/%s%d.png",getenv ("HOME"), dest, sctr++, ext);
+ snprintf (pathbuf, sizeof (pathbuf), "%s/Desktop/%s%d.png",getenv ("HOME"), dest, sctr++);
path = CFStringCreateWithCString (NULL, pathbuf, kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE);
image_dest = CGImageDestinationCreateWithURL (url, png_utti, 1, NULL);
@@ -2648,7 +2472,6 @@ quartz_image_to_png (CGImageRef image, const char *dest)
void
quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest)
{
- static int sctr = 0;
CGImageRef image;
if (nq->base.type != CAIRO_SURFACE_TYPE_QUARTZ) {