diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2022-04-27 00:04:43 +0000 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2022-04-27 00:04:43 +0000 |
commit | 455a4cca5472a309d036b6393f1db0dc4403d303 (patch) | |
tree | eadac9e15f0bcb4688020670a74e89655df96ef3 /src/cairo-quartz-surface.c | |
parent | f07d539c07488edccd0bea241073572bc20c8ed1 (diff) | |
parent | cfb3835f57abd05b5d862904dd1d4300ae990a8a (diff) | |
download | cairo-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.c | 259 |
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) { |