Merge branch 'quartz-core-text' into 'master'
quartz: support rendering colored bitmap fonts See merge request cairo/cairo!289
|
|
@ -193,11 +193,8 @@ dnl ===========================================================================
|
|||
CAIRO_ENABLE_SURFACE_BACKEND(quartz, Quartz, auto, [
|
||||
dnl There is no pkgconfig for quartz; lets do a header check
|
||||
AC_CHECK_HEADER(ApplicationServices/ApplicationServices.h, , [use_quartz="no (requires ApplicationServices framework)"])
|
||||
if test "x$use_quartz" != "xyes" ; then
|
||||
dnl check for CoreGraphics as a separate framework
|
||||
AC_CHECK_HEADER(CoreGraphics/CoreGraphics.h, , [use_quartz="no (requires CoreGraphics framework)"])
|
||||
quartz_LIBS="-Xlinker -framework -Xlinker CoreGraphics"
|
||||
else
|
||||
AC_CHECK_FUNC([CTFontDrawGlyphs],,[use_quartz_fonts="no (requires Mac OS X 10.7 or later)"])
|
||||
if test "x$use_quartz" = "xyes" ; then
|
||||
quartz_LIBS="-Xlinker -framework -Xlinker ApplicationServices"
|
||||
fi
|
||||
])
|
||||
|
|
|
|||
20
meson.build
|
|
@ -455,7 +455,6 @@ if host_machine.system() == 'darwin' and not get_option('quartz').disabled()
|
|||
deps += [quartz_deps]
|
||||
|
||||
feature_conf.set('CAIRO_HAS_QUARTZ_SURFACE', 1)
|
||||
feature_conf.set('CAIRO_HAS_QUARTZ_FONT', 1)
|
||||
feature_conf.set('CAIRO_HAS_QUARTZ_IMAGE_SURFACE', 1)
|
||||
|
||||
built_features += [
|
||||
|
|
@ -468,13 +467,18 @@ if host_machine.system() == 'darwin' and not get_option('quartz').disabled()
|
|||
'name': 'cairo-quartz-image',
|
||||
'description': 'Quartz Image surface backend',
|
||||
'deps': quartz_deps,
|
||||
},
|
||||
{
|
||||
'name': 'cairo-quartz-font',
|
||||
'description': 'Quartz font backend',
|
||||
'deps': quartz_deps,
|
||||
},
|
||||
]
|
||||
}]
|
||||
compiler = meson.get_compiler('c')
|
||||
if compiler.has_function('CTFontDrawGlyphs', prefix: '#include <ApplicationServices/ApplicationServices.h>',
|
||||
dependencies: quartz_deps)
|
||||
built_features += [
|
||||
{
|
||||
'name': 'cairo-quartz-font',
|
||||
'description': 'Quartz font backend',
|
||||
'deps': quartz_deps,
|
||||
}]
|
||||
feature_conf.set('CAIRO_HAS_QUARTZ_FONT', 1)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
|||
|
|
@ -44,15 +44,13 @@
|
|||
|
||||
#include "cairo-error-private.h"
|
||||
|
||||
//#define DEBUG /* Uncomment this to get debug messages on the console. */
|
||||
/**
|
||||
* SECTION:cairo-quartz-fonts
|
||||
* @Title: Quartz (CGFont) Fonts
|
||||
* @Short_Description: Font support via CGFont on OS X
|
||||
* @Short_Description: Font support via Core Text on Apple operating systems.
|
||||
* @See_Also: #cairo_font_face_t
|
||||
*
|
||||
* The Quartz font backend is primarily used to render text on Apple
|
||||
* MacOS X systems. The CGFont API is used for the internal
|
||||
* implementation of the font backend methods.
|
||||
**/
|
||||
|
||||
/**
|
||||
|
|
@ -64,103 +62,37 @@
|
|||
* Since: 1.6
|
||||
**/
|
||||
|
||||
static CFDataRef (*CGFontCopyTableForTagPtr) (CGFontRef font, uint32_t tag) = NULL;
|
||||
|
||||
/* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */
|
||||
static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL;
|
||||
static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL;
|
||||
|
||||
/* These aren't public before 10.5, and some have different names in 10.4 */
|
||||
static int (*CGFontGetUnitsPerEmPtr) (CGFontRef) = NULL;
|
||||
static bool (*CGFontGetGlyphAdvancesPtr) (CGFontRef, const CGGlyph[], size_t, int[]) = NULL;
|
||||
static bool (*CGFontGetGlyphBBoxesPtr) (CGFontRef, const CGGlyph[], size_t, CGRect[]) = NULL;
|
||||
static CGRect (*CGFontGetFontBBoxPtr) (CGFontRef) = NULL;
|
||||
|
||||
/* Not public, but present */
|
||||
static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const CGGlyph[], size_t) = NULL;
|
||||
static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
|
||||
/* These are private functions */
|
||||
static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
|
||||
|
||||
/* Not public in the least bit */
|
||||
static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL;
|
||||
|
||||
/* CTFontCreateWithGraphicsFont is not available until 10.5 */
|
||||
typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
|
||||
static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform*, CTFontDescriptorRef) = NULL;
|
||||
static CGPathRef (*CTFontCreatePathForGlyphPtr) (CTFontRef, CGGlyph, CGAffineTransform *) = NULL;
|
||||
|
||||
/* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */
|
||||
typedef struct {
|
||||
int ascent;
|
||||
int descent;
|
||||
int leading;
|
||||
} quartz_CGFontMetrics;
|
||||
static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
|
||||
static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
|
||||
static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
|
||||
static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
|
||||
|
||||
/* Not public anymore in 64-bits nor in 10.7 */
|
||||
static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
|
||||
|
||||
static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
|
||||
static cairo_bool_t _cairo_quartz_font_symbols_present = 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
|
||||
#define FONT_COLOR_GLYPHS kCTFontTraitColorGlyphs
|
||||
#else
|
||||
#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
|
||||
#define FONT_COLOR_GLYPHS kCTFontColorGlyphsTrait
|
||||
#endif
|
||||
|
||||
static void
|
||||
quartz_font_ensure_symbols(void)
|
||||
{
|
||||
if (_cairo_quartz_font_symbol_lookup_done)
|
||||
return;
|
||||
|
||||
CGFontCopyTableForTagPtr = dlsym(RTLD_DEFAULT, "CGFontCopyTableForTag");
|
||||
|
||||
/* Look for the 10.5 versions first */
|
||||
CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBBoxes");
|
||||
if (!CGFontGetGlyphBBoxesPtr)
|
||||
CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBoundingBoxes");
|
||||
|
||||
CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars");
|
||||
if (!CGFontGetGlyphsForUnicharsPtr)
|
||||
CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
|
||||
|
||||
CGFontGetFontBBoxPtr = dlsym(RTLD_DEFAULT, "CGFontGetFontBBox");
|
||||
|
||||
/* We just need one of these two */
|
||||
CGFontCreateWithFontNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithFontName");
|
||||
CGFontCreateWithNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithName");
|
||||
|
||||
/* These have the same name in 10.4 and 10.5 */
|
||||
CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
|
||||
CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
|
||||
|
||||
CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
|
||||
CTFontCreatePathForGlyphPtr = dlsym(RTLD_DEFAULT, "CTFontCreatePathForGlyph");
|
||||
if (!CTFontCreateWithGraphicsFontPtr || !CTFontCreatePathForGlyphPtr)
|
||||
CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath");
|
||||
|
||||
CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
|
||||
CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
|
||||
CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
|
||||
CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
|
||||
|
||||
CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
|
||||
CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
|
||||
CGContextGetAllowsFontSmoothingPtr =
|
||||
dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
|
||||
|
||||
FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
|
||||
|
||||
if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
|
||||
CGFontGetGlyphBBoxesPtr &&
|
||||
CGFontGetGlyphsForUnicharsPtr &&
|
||||
CGFontGetUnitsPerEmPtr &&
|
||||
CGFontGetGlyphAdvancesPtr &&
|
||||
((CTFontCreateWithGraphicsFontPtr && CTFontCreatePathForGlyphPtr) || CGFontGetGlyphPathPtr) &&
|
||||
(CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
|
||||
_cairo_quartz_font_symbols_present = TRUE;
|
||||
|
||||
_cairo_quartz_font_symbol_lookup_done = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +101,7 @@ 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 {
|
||||
|
|
@ -187,14 +120,10 @@ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
|
|||
{
|
||||
const char *family;
|
||||
char *full_name;
|
||||
CFStringRef cgFontName = NULL;
|
||||
CFStringRef FontName = NULL;
|
||||
CGFontRef cgFont = NULL;
|
||||
int loop;
|
||||
|
||||
quartz_font_ensure_symbols();
|
||||
if (! _cairo_quartz_font_symbols_present)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
family = toy_face->family;
|
||||
full_name = _cairo_malloc (strlen (family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
|
||||
/* handle CSS-ish faces */
|
||||
|
|
@ -221,23 +150,19 @@ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
|
|||
|
||||
if (loop < 3 && (loop & 1) == 0) {
|
||||
if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
|
||||
strcat (full_name, " Bold");
|
||||
strcat (full_name, "-Bold");
|
||||
}
|
||||
|
||||
if (loop < 3 && (loop & 2) == 0) {
|
||||
if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
|
||||
strcat (full_name, " Italic");
|
||||
strcat (full_name, "-Italic");
|
||||
else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
|
||||
strcat (full_name, " Oblique");
|
||||
strcat (full_name, "-Oblique");
|
||||
}
|
||||
|
||||
if (CGFontCreateWithFontNamePtr) {
|
||||
cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
|
||||
cgFont = CGFontCreateWithFontNamePtr (cgFontName);
|
||||
CFRelease (cgFontName);
|
||||
} else {
|
||||
cgFont = CGFontCreateWithNamePtr (full_name);
|
||||
}
|
||||
FontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
|
||||
cgFont = CGFontCreateWithFontName (FontName);
|
||||
CFRelease (FontName);
|
||||
|
||||
if (cgFont)
|
||||
break;
|
||||
|
|
@ -249,7 +174,7 @@ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
|
|||
}
|
||||
|
||||
*font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
|
||||
CGFontRelease (cgFont);
|
||||
CFRelease (cgFont);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -265,6 +190,51 @@ _cairo_quartz_font_face_destroy (void *abstract_face)
|
|||
|
||||
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,
|
||||
|
|
@ -276,13 +246,9 @@ _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;
|
||||
|
||||
quartz_font_ensure_symbols();
|
||||
if (!_cairo_quartz_font_symbols_present)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
font = _cairo_malloc (sizeof(cairo_quartz_scaled_font_t));
|
||||
if (font == NULL)
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
|
@ -295,48 +261,29 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
|
|||
if (status)
|
||||
goto FINISH;
|
||||
|
||||
ems = CGFontGetUnitsPerEmPtr (font_face->cgFont);
|
||||
|
||||
ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, font_scale, NULL, NULL);
|
||||
/* initialize metrics */
|
||||
if (CGFontGetFontBBoxPtr && CGFontGetAscentPtr) {
|
||||
fs_metrics.ascent = (CGFontGetAscentPtr (font_face->cgFont) / ems);
|
||||
fs_metrics.descent = - (CGFontGetDescentPtr (font_face->cgFont) / ems);
|
||||
fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
|
||||
(CGFontGetLeadingPtr (font_face->cgFont) / ems);
|
||||
|
||||
bbox = CGFontGetFontBBoxPtr (font_face->cgFont);
|
||||
fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
|
||||
fs_metrics.max_y_advance = 0.0;
|
||||
} else {
|
||||
CGGlyph wGlyph;
|
||||
UniChar u;
|
||||
|
||||
quartz_CGFontMetrics *m;
|
||||
m = CGFontGetHMetricsPtr (font_face->cgFont);
|
||||
|
||||
/* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
|
||||
if (!m) {
|
||||
status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
|
||||
goto FINISH;
|
||||
}
|
||||
|
||||
fs_metrics.ascent = (m->ascent / ems);
|
||||
fs_metrics.descent = - (m->descent / ems);
|
||||
fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (m->leading / ems);
|
||||
|
||||
/* We kind of have to guess here; W's big, right? */
|
||||
u = (UniChar) 'W';
|
||||
CGFontGetGlyphsForUnicharsPtr (font_face->cgFont, &u, &wGlyph, 1);
|
||||
if (wGlyph && CGFontGetGlyphBBoxesPtr (font_face->cgFont, &wGlyph, 1, &bbox)) {
|
||||
fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
|
||||
fs_metrics.max_y_advance = 0.0;
|
||||
} else {
|
||||
fs_metrics.max_x_advance = 0.0;
|
||||
fs_metrics.max_y_advance = 0.0;
|
||||
}
|
||||
}
|
||||
fs_metrics.ascent = CTFontGetAscent (ctFont);
|
||||
fs_metrics.descent = CTFontGetDescent (ctFont);
|
||||
fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
|
||||
CTFontGetLeading (ctFont);
|
||||
|
||||
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) {
|
||||
|
|
@ -355,6 +302,23 @@ const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
|
|||
_cairo_quartz_font_face_scaled_font_create
|
||||
};
|
||||
|
||||
static inline cairo_quartz_font_face_t*
|
||||
_cairo_quartz_font_face_create ()
|
||||
{
|
||||
cairo_quartz_font_face_t *font_face =
|
||||
_cairo_malloc (sizeof (cairo_quartz_font_face_t));
|
||||
|
||||
if (!font_face) {
|
||||
cairo_status_t ignore_status;
|
||||
ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_quartz_font_face_t *)&_cairo_font_face_nil;
|
||||
}
|
||||
|
||||
_cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
|
||||
|
||||
return font_face;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_quartz_font_face_create_for_cgfont:
|
||||
* @font: a #CGFontRef obtained through a method external to cairo.
|
||||
|
|
@ -371,21 +335,13 @@ const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
|
|||
cairo_font_face_t *
|
||||
cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
|
||||
{
|
||||
cairo_quartz_font_face_t *font_face;
|
||||
cairo_quartz_font_face_t* font_face = _cairo_quartz_font_face_create ();
|
||||
|
||||
quartz_font_ensure_symbols();
|
||||
|
||||
font_face = _cairo_malloc (sizeof (cairo_quartz_font_face_t));
|
||||
if (!font_face) {
|
||||
cairo_status_t ignore_status;
|
||||
ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_font_face_t *)&_cairo_font_face_nil;
|
||||
}
|
||||
if (cairo_font_face_status (&font_face->base))
|
||||
return &font_face->base;
|
||||
|
||||
font_face->cgFont = CGFontRetain (font);
|
||||
|
||||
_cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
|
||||
|
||||
return &font_face->base;
|
||||
}
|
||||
|
||||
|
|
@ -405,6 +361,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
|
||||
|
|
@ -419,21 +377,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 = CGFontGetUnitsPerEmPtr (font_face->cgFont);
|
||||
double xmin, ymin, xmax, ymax;
|
||||
|
||||
if (unlikely (glyph == CGGLYPH_INVALID))
|
||||
goto FAIL;
|
||||
|
||||
if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
|
||||
!CGFontGetGlyphBBoxesPtr (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 &&
|
||||
|
|
@ -444,31 +398,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);
|
||||
|
|
@ -480,13 +412,17 @@ _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
|
|||
extents.y_bearing = - ymax;
|
||||
extents.width = xmax - xmin;
|
||||
extents.height = ymax - ymin;
|
||||
/* At the necessary 1.0pt ctFont size some glyphs get a reduced
|
||||
* advance that causes overlaps when scaled up. We can avoid that by
|
||||
* using the width instead if it's wider. Since cairo doesn't support
|
||||
* vertical font layout we don't do the same for y_advance.
|
||||
*/
|
||||
extents.x_advance = MAX(extents.width, advance.width);
|
||||
extents.y_advance = advance.height;
|
||||
|
||||
extents.x_advance = (double) advance / emscale;
|
||||
extents.y_advance = 0.0;
|
||||
|
||||
#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:
|
||||
|
|
@ -542,7 +478,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);
|
||||
|
|
@ -555,7 +491,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;
|
||||
|
|
@ -573,13 +508,7 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
|
|||
-font->base.scale.yy,
|
||||
0, 0);
|
||||
|
||||
if (CTFontCreateWithGraphicsFontPtr && CTFontCreatePathForGlyphPtr) {
|
||||
CTFontRef ctFont = CTFontCreateWithGraphicsFontPtr (font_face->cgFont, 1.0, NULL, NULL);
|
||||
glyphPath = CTFontCreatePathForGlyphPtr (ctFont, glyph, &textMatrix);
|
||||
CFRelease (ctFont);
|
||||
} else {
|
||||
glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph);
|
||||
}
|
||||
glyphPath = CTFontCreatePathForGlyph (font->ctFont, glyph, &textMatrix);
|
||||
|
||||
if (!glyphPath)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
|
@ -599,30 +528,42 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_quartz_font_has_color_glyphs (void *abstract_font)
|
||||
{
|
||||
cairo_quartz_scaled_font_t *face = (cairo_quartz_scaled_font_t*)abstract_font;
|
||||
CTFontSymbolicTraits traits = CTFontGetSymbolicTraits (face->ctFont);
|
||||
return traits & FONT_COLOR_GLYPHS;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
|
||||
cairo_scaled_glyph_t *scaled_glyph)
|
||||
cairo_scaled_glyph_t *scaled_glyph,
|
||||
cairo_scaled_glyph_info_t info,
|
||||
const cairo_color_t *fg_color)
|
||||
{
|
||||
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 = CGFontGetUnitsPerEmPtr (font_face->cgFont);
|
||||
|
||||
CGContextRef cgContext = NULL;
|
||||
CGAffineTransform textMatrix;
|
||||
CGRect glyphRect, glyphRectInt;
|
||||
CGPoint glyphOrigin;
|
||||
cairo_bool_t is_color = info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
|
||||
cairo_format_t format = is_color ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
|
||||
|
||||
//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.
|
||||
|
|
@ -639,31 +580,33 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
|
||||
!CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
|
||||
{
|
||||
/* Note: Certain opentype color fonts have the ability to provide a
|
||||
* mixture of color and not-color glyphs. The Core Text API doesn't
|
||||
* expose a way to query individual glyphs and at the level that that
|
||||
* API is written it's not supposed to matter. The following code will
|
||||
* cheerfully render any glyph requested onto the image surface. If
|
||||
* the font is capable of color and
|
||||
* COLOR_SCALED_GLYPH_INFO_COLOR_SURFACE is set then you get back a
|
||||
* CAIRO_FORMAT_ARGB32 surface. If a foreground color is provided then
|
||||
* the glyph will be drawn in that color, otherwise it will be black.
|
||||
*/
|
||||
if (unlikely (is_color && ! _cairo_quartz_font_has_color_glyphs (font)))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* 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",
|
||||
|
|
@ -672,70 +615,50 @@ _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);
|
||||
surface = (cairo_image_surface_t*) cairo_image_surface_create (format, 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);
|
||||
CGColorSpaceRef colorspace = is_color ? CGColorSpaceCreateDeviceRGB () : NULL;
|
||||
CGBitmapInfo bitinfo = is_color ? kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst : kCGImageAlphaOnly;
|
||||
|
||||
CGContextRef cgContext = CGBitmapContextCreate (surface->data,
|
||||
surface->width,
|
||||
surface->height,
|
||||
8,
|
||||
surface->stride,
|
||||
colorspace,
|
||||
bitinfo);
|
||||
|
||||
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);
|
||||
if (CGContextSetAllowsFontSmoothingPtr &&
|
||||
!CGContextGetAllowsFontSmoothingPtr (cgContext))
|
||||
CGContextSetAllowsFontSmoothingPtr (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;
|
||||
}
|
||||
|
||||
if (fg_color)
|
||||
CGContextSetRGBFillColor (cgContext, fg_color->red, fg_color->green, fg_color->blue, fg_color->alpha);
|
||||
_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);
|
||||
CGColorSpaceRelease (colorspace);
|
||||
}
|
||||
|
||||
cairo_surface_set_device_offset (&surface->base,
|
||||
- glyphOrigin.x,
|
||||
height + glyphOrigin.y);
|
||||
cairo_surface_mark_dirty (&surface->base);
|
||||
|
||||
_cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
|
||||
if (is_color)
|
||||
_cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color != NULL);
|
||||
else
|
||||
_cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -755,8 +678,10 @@ _cairo_quartz_scaled_glyph_init (void *abstract_font,
|
|||
if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
|
||||
status = _cairo_quartz_init_glyph_path (font, scaled_glyph);
|
||||
|
||||
if (!status && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE))
|
||||
status = _cairo_quartz_init_glyph_surface (font, scaled_glyph);
|
||||
if (!status && (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE |
|
||||
CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE )))
|
||||
status = _cairo_quartz_init_glyph_surface (font, scaled_glyph,
|
||||
info, foreground_color);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -766,13 +691,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);
|
||||
CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, utf16, glyph, len);
|
||||
|
||||
CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyph, len);
|
||||
return glyph[0];
|
||||
}
|
||||
|
||||
|
|
@ -783,11 +706,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 = NULL;
|
||||
|
||||
if (likely (CGFontCopyTableForTagPtr))
|
||||
data = CGFontCopyTableForTagPtr (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;
|
||||
|
|
@ -816,9 +736,12 @@ static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
|
|||
NULL, /* text_to_glyphs */
|
||||
_cairo_quartz_ucs4_to_index,
|
||||
_cairo_quartz_load_truetype_table,
|
||||
NULL, /* map_glyphs_to_unicode */
|
||||
NULL, /*index_to_ucs4*/
|
||||
NULL, /* is_synthetic */
|
||||
NULL, /* index_to_glyph_name */
|
||||
NULL, /* load_type1_data */
|
||||
_cairo_quartz_font_has_color_glyphs
|
||||
};
|
||||
|
||||
/*
|
||||
* private methods that the quartz surface uses
|
||||
*/
|
||||
|
|
@ -831,6 +754,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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@ CairoQuartzCreateCGImage (cairo_format_t format,
|
|||
|
||||
cairo_private CGFontRef
|
||||
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ endif
|
|||
|
||||
# Need to add quartz-surface-source
|
||||
if CAIRO_HAS_QUARTZ_SURFACE
|
||||
test_sources += $(quartz_surface_test_sources)
|
||||
test_sources += "$(quartz_surface_test_sources) $(quartz_color_font_test_sources)"
|
||||
endif
|
||||
|
||||
if CAIRO_HAS_PDF_SURFACE
|
||||
|
|
|
|||
|
|
@ -434,6 +434,8 @@ egl_surface_test_sources = \
|
|||
|
||||
quartz_surface_test_sources = quartz-surface-source.c
|
||||
|
||||
quartz_color_font_test_sources = quartz-color-font.c
|
||||
|
||||
pdf_surface_test_sources = \
|
||||
pdf-features.c \
|
||||
pdf-mime-data.c \
|
||||
|
|
|
|||
|
|
@ -438,6 +438,7 @@ test_egl_sources = [
|
|||
|
||||
test_quartz_sources = [
|
||||
'quartz-surface-source.c',
|
||||
'quartz-color-font.c',
|
||||
]
|
||||
|
||||
test_pdf_sources = [
|
||||
|
|
|
|||
54
test/quartz-color-font.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright © 2022 John Ralls <jralls@ceridwen.us>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cairo-test.h"
|
||||
#include <cairo-quartz.h>
|
||||
|
||||
#define WIDTH 100
|
||||
#define HEIGHT 50
|
||||
|
||||
#define FONT "Apple Color Emoji"
|
||||
|
||||
static const char smiley_face_utf8[] = { 0xf0, 0x9f, 0x99, 0x82, 0x00 }; /* U+1F642 */
|
||||
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height)
|
||||
{
|
||||
cairo_select_font_face(cr, FONT, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
cairo_set_font_size (cr, HEIGHT/2);
|
||||
cairo_move_to (cr, width/5, 2*height/3);
|
||||
|
||||
cairo_show_text(cr, smiley_face_utf8);
|
||||
cairo_show_text(cr, smiley_face_utf8);
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
CAIRO_TEST (quartz_color_font,
|
||||
"Test color font",
|
||||
"quartz, font", /* keywords */
|
||||
NULL, /* requirements */
|
||||
WIDTH, HEIGHT,
|
||||
NULL, draw)
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/pdf-operators-text.quartz.ref.png
Normal file
|
After Width: | Height: | Size: 8 KiB |
BIN
test/reference/quartz-color-font.quartz.rgb24.ref.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
test/reference/quartz-color-font.ref.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |