From ebd87cd7e8879fa1cd7cd649aaa129e31a421a2b Mon Sep 17 00:00:00 2001 From: "vladimir@pobox.com" Date: Sun, 6 Apr 2008 15:14:09 -0700 Subject: [PATCH] b=419715, upgrade cairo to 1.6 or as-close-as-possible -- imported patch cairo-upgrade.patch ; r=me --- configure.in | 4 +- gfx/cairo/README | 2 +- gfx/cairo/cairo/src/Makefile.in | 5 +- gfx/cairo/cairo/src/cairo-analysis-surface.c | 73 +- gfx/cairo/cairo/src/cairo-array.c | 12 +- gfx/cairo/cairo/src/cairo-atsui-font.c | 1035 ----------------- gfx/cairo/cairo/src/cairo-atsui.h | 58 - gfx/cairo/cairo/src/cairo-deprecated.h | 3 + gfx/cairo/cairo/src/cairo-features.h.in | 6 +- gfx/cairo/cairo/src/cairo-font-face.c | 1 + gfx/cairo/cairo/src/cairo-glitz-surface.c | 2 +- gfx/cairo/cairo/src/cairo-gstate.c | 23 +- gfx/cairo/cairo/src/cairo-hull.c | 2 +- gfx/cairo/cairo/src/cairo-image-surface.c | 239 ++-- gfx/cairo/cairo/src/cairo-meta-surface.c | 14 +- .../cairo/src/cairo-output-stream-private.h | 3 - gfx/cairo/cairo/src/cairo-output-stream.c | 89 +- gfx/cairo/cairo/src/cairo-path-fixed.c | 6 +- gfx/cairo/cairo/src/cairo-pattern.c | 10 +- gfx/cairo/cairo/src/cairo-pdf-operators.c | 268 +++-- gfx/cairo/cairo/src/cairo-pdf-surface.c | 76 +- gfx/cairo/cairo/src/cairo-png.c | 5 +- gfx/cairo/cairo/src/cairo-ps-surface.c | 81 +- gfx/cairo/cairo/src/cairo-quartz-font.c | 794 +++++++++++++ gfx/cairo/cairo/src/cairo-quartz-private.h | 15 +- gfx/cairo/cairo/src/cairo-quartz-surface.c | 125 +- gfx/cairo/cairo/src/cairo-quartz.h | 20 +- gfx/cairo/cairo/src/cairo-rectangle.c | 2 +- gfx/cairo/cairo/src/cairo-surface-fallback.c | 4 +- gfx/cairo/cairo/src/cairo-surface.c | 24 + gfx/cairo/cairo/src/cairo-svg-surface.c | 146 ++- gfx/cairo/cairo/src/cairo-truetype-subset.c | 63 +- gfx/cairo/cairo/src/cairo-win32-font.c | 2 +- .../cairo/src/cairo-win32-printing-surface.c | 21 +- gfx/cairo/cairo/src/cairo-win32-surface.c | 12 +- gfx/cairo/cairo/src/cairo-xlib-private.h | 22 + gfx/cairo/cairo/src/cairo-xlib-screen.c | 69 ++ .../cairo/src/cairo-xlib-surface-private.h | 5 + gfx/cairo/cairo/src/cairo-xlib-surface.c | 409 +++++-- gfx/cairo/cairo/src/cairo-xlib-visual.c | 148 +++ gfx/cairo/cairo/src/cairo.c | 16 +- gfx/cairo/cairo/src/cairo.h | 4 +- gfx/cairo/cairo/src/cairoint.h | 59 +- gfx/thebes/src/gfxAtsuiFonts.cpp | 4 +- 44 files changed, 2248 insertions(+), 1733 deletions(-) delete mode 100644 gfx/cairo/cairo/src/cairo-atsui-font.c delete mode 100644 gfx/cairo/cairo/src/cairo-atsui.h create mode 100644 gfx/cairo/cairo/src/cairo-quartz-font.c create mode 100644 gfx/cairo/cairo/src/cairo-xlib-visual.c diff --git a/configure.in b/configure.in index 17737395811..028791386ac 100644 --- a/configure.in +++ b/configure.in @@ -7181,7 +7181,7 @@ if test "$MOZ_TREE_CAIRO"; then if test "$MOZ_WIDGET_TOOLKIT" = "mac" -o "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1" QUARTZ_IMAGE_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_IMAGE_SURFACE 1" - ATSUI_FONT_FEATURE="#define CAIRO_HAS_ATSUI_FONT 1" + QUARTZ_FONT_FEATURE="#define CAIRO_HAS_QUARTZ_FONT 1" fi if test "$MOZ_WIDGET_TOOLKIT" = "windows"; then WIN32_SURFACE_FEATURE="#define CAIRO_HAS_WIN32_SURFACE 1" @@ -7231,7 +7231,7 @@ if test "$MOZ_TREE_CAIRO"; then AC_SUBST(DIRECTFB_SURFACE_FEATURE) AC_SUBST(FT_FONT_FEATURE) AC_SUBST(WIN32_FONT_FEATURE) - AC_SUBST(ATSUI_FONT_FEATURE) + AC_SUBST(QUARTZ_FONT_FEATURE) AC_SUBST(PNG_FUNCTIONS_FEATURE) if test "$_WIN32_MSVC"; then diff --git a/gfx/cairo/README b/gfx/cairo/README index 2f78cc8aba1..9649f763902 100644 --- a/gfx/cairo/README +++ b/gfx/cairo/README @@ -7,7 +7,7 @@ http://www.cairographics.org/. VERSIONS: - cairo (1.6.x - 1.5.12-56-ga33351f) + cairo (1.6.x - 1.5.16-23-gbb76eb5) pixman (0.10.x - pixman-0.10.0-5-g4cde088) glitz 0.5.2 (cvs - 2006-01-10) diff --git a/gfx/cairo/cairo/src/Makefile.in b/gfx/cairo/cairo/src/Makefile.in index 546766f5746..20c5d5ec2b9 100644 --- a/gfx/cairo/cairo/src/Makefile.in +++ b/gfx/cairo/cairo/src/Makefile.in @@ -164,8 +164,8 @@ EXPORTS += $(PDF_EXPORTS) endif ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) -CSRCS += cairo-quartz-surface.c cairo-quartz-image-surface.c cairo-atsui-font.c -EXPORTS += cairo-quartz.h cairo-atsui.h cairo-quartz-image.h +CSRCS += cairo-quartz-surface.c cairo-quartz-image-surface.c cairo-quartz-font.c +EXPORTS += cairo-quartz.h cairo-quartz-image.h endif ifeq ($(MOZ_WIDGET_TOOLKIT),beos) @@ -186,6 +186,7 @@ endif ifdef MOZ_X11 CSRCS += cairo-xlib-surface.c \ cairo-xlib-screen.c \ + cairo-xlib-visual.c \ cairo-xlib-display.c EXPORTS += cairo-xlib.h cairo-xlib-xrender.h endif diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface.c b/gfx/cairo/cairo/src/cairo-analysis-surface.c index 29919f012ad..749f3e3710a 100644 --- a/gfx/cairo/cairo/src/cairo-analysis-surface.c +++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c @@ -125,8 +125,20 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface, cairo_int_status_t status; cairo_box_t bbox; - if (rect->width == 0 || rect->height == 0) - return CAIRO_STATUS_SUCCESS; + if (rect->width == 0 || rect->height == 0) { + /* Even though the operation is not visible we must be careful + * to not allow unsupported operations to be replayed to the + * backend during CAIRO_PAGINATED_MODE_RENDER */ + if (backend_status == CAIRO_STATUS_SUCCESS || + backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) + { + return CAIRO_STATUS_SUCCESS; + } + else + { + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + } + } if (surface->has_ctm) { double x1, y1, x2, y2; @@ -143,8 +155,21 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface, x2 = ceil (x2) - rect->x; y2 = ceil (y2) - rect->y; - if (x2 <= 0 || y2 <= 0) - return CAIRO_STATUS_SUCCESS; + if (x2 <= 0 || y2 <= 0) { + /* Even though the operation is not visible we must be + * careful to not allow unsupported operations to be + * replayed to the backend during + * CAIRO_PAGINATED_MODE_RENDER */ + if (backend_status == CAIRO_STATUS_SUCCESS || + backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) + { + return CAIRO_STATUS_SUCCESS; + } + else + { + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + } + } rect->width = x2; rect->height = y2; @@ -434,17 +459,23 @@ _cairo_analysis_surface_stroke (void *abstract_surface, ctm, ctm_inverse, tolerance, &traps); - - if (status || traps.num_traps == 0) { + if (status) { _cairo_traps_fini (&traps); return status; } - _cairo_traps_extents (&traps, &box); - extents.x = _cairo_fixed_integer_floor (box.p1.x); - extents.y = _cairo_fixed_integer_floor (box.p1.y); - extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x; - extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y; + if (traps.num_traps == 0) { + extents.x = 0; + extents.y = 0; + extents.width = 0; + extents.height = 0; + } else { + _cairo_traps_extents (&traps, &box); + extents.x = _cairo_fixed_integer_floor (box.p1.x); + extents.y = _cairo_fixed_integer_floor (box.p1.y); + extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x; + extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y; + } _cairo_traps_fini (&traps); } @@ -506,17 +537,23 @@ _cairo_analysis_surface_fill (void *abstract_surface, fill_rule, tolerance, &traps); - - if (status || traps.num_traps == 0) { + if (status) { _cairo_traps_fini (&traps); return status; } - _cairo_traps_extents (&traps, &box); - extents.x = _cairo_fixed_integer_floor (box.p1.x); - extents.y = _cairo_fixed_integer_floor (box.p1.y); - extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x; - extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y; + if (traps.num_traps == 0) { + extents.x = 0; + extents.y = 0; + extents.width = 0; + extents.height = 0; + } else { + _cairo_traps_extents (&traps, &box); + extents.x = _cairo_fixed_integer_floor (box.p1.x); + extents.y = _cairo_fixed_integer_floor (box.p1.y); + extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x; + extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y; + } _cairo_traps_fini (&traps); } diff --git a/gfx/cairo/cairo/src/cairo-array.c b/gfx/cairo/cairo/src/cairo-array.c index b547b121d13..053e73ea2a3 100644 --- a/gfx/cairo/cairo/src/cairo-array.c +++ b/gfx/cairo/cairo/src/cairo-array.c @@ -110,15 +110,19 @@ _cairo_array_fini (cairo_array_t *array) * is always increased by doubling as many times as necessary. **/ cairo_status_t -_cairo_array_grow_by (cairo_array_t *array, int additional) +_cairo_array_grow_by (cairo_array_t *array, unsigned int additional) { char *new_elements; - int old_size = array->size; - int required_size = array->num_elements + additional; - int new_size; + unsigned int old_size = array->size; + unsigned int required_size = array->num_elements + additional; + unsigned int new_size; assert (! array->is_snapshot); + /* check for integer overflow */ + if (required_size > INT_MAX || required_size < array->num_elements) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (required_size <= old_size) return CAIRO_STATUS_SUCCESS; diff --git a/gfx/cairo/cairo/src/cairo-atsui-font.c b/gfx/cairo/cairo/src/cairo-atsui-font.c deleted file mode 100644 index 2d585ea46f9..00000000000 --- a/gfx/cairo/cairo/src/cairo-atsui-font.c +++ /dev/null @@ -1,1035 +0,0 @@ -/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2004 Calum Robinson - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Calum Robinson - * - * Contributor(s): - * Calum Robinson - */ - -#include "cairoint.h" - -#include "cairo.h" -#include "cairo-atsui.h" -#include "cairo-quartz-private.h" - -/* - * FixedToFloat/FloatToFixed are 10.3+ SDK items - include definitions - * here so we can use older SDKs. - */ -#ifndef FixedToFloat -#define fixed1 ((Fixed) 0x00010000L) -#define FixedToFloat(a) ((float)(a) / fixed1) -#define FloatToFixed(a) ((Fixed)((float)(a) * fixed1)) -#endif - -/* If this isn't defined, we must be building on non-intel, - * hence it will be 0. - */ -#ifdef __BIG_ENDIAN__ -#define CG_BITMAP_BYTE_ORDER_FLAG 0 -#else /* Little endian. */ -/* x86, and will be a 10.4u SDK; ByteOrder32Host will be defined */ -#define CG_BITMAP_BYTE_ORDER_FLAG kCGBitmapByteOrder32Host -#endif - -/* Public in 10.4, present in 10.3.9 */ -CG_EXTERN CGRect CGRectApplyAffineTransform (CGRect, CGAffineTransform); - -/* Error code for path callbacks */ -static OSStatus CAIRO_CG_PATH_ERROR = 1001; - -typedef struct _cairo_atsui_font_face cairo_atsui_font_face_t; -typedef struct _cairo_atsui_font cairo_atsui_font_t; -typedef struct _cairo_atsui_scaled_path cairo_atsui_scaled_path_t; - -static cairo_status_t _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face, - ATSUFontID font_id, - ATSUStyle style, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font_out); - -struct _cairo_atsui_font { - cairo_scaled_font_t base; - - ATSUStyle style; - ATSUStyle unscaled_style; - ATSUFontID fontID; - - Fixed size; - CGAffineTransform font_matrix; - CGFontRef cgfref; -}; - -struct _cairo_atsui_font_face { - cairo_font_face_t base; - ATSUFontID font_id; -}; - -struct _cairo_atsui_scaled_path { - cairo_path_fixed_t *path; - cairo_matrix_t *scale; -}; - -static void -_cairo_atsui_font_face_destroy (void *abstract_face) -{ -} - -static cairo_status_t -_cairo_atsui_font_face_scaled_font_create (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font) -{ - cairo_status_t status; - cairo_atsui_font_face_t *font_face = abstract_face; - OSStatus err; - ATSUAttributeTag styleTags[] = { kATSUFontTag }; - ATSUAttributeValuePtr styleValues[] = { &font_face->font_id }; - ByteCount styleSizes[] = { sizeof(ATSUFontID) }; - ATSUStyle style; - - err = ATSUCreateStyle (&style); - if (err != noErr) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags), - styleTags, styleSizes, styleValues); - if (err != noErr) { - ATSUDisposeStyle (style); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - status = _cairo_atsui_font_create_scaled (&font_face->base, font_face->font_id, style, - font_matrix, ctm, options, font); - if (status) - ATSUDisposeStyle (style); - - return status; -} - -static const cairo_font_face_backend_t _cairo_atsui_font_face_backend = { - CAIRO_FONT_TYPE_ATSUI, - _cairo_atsui_font_face_destroy, - _cairo_atsui_font_face_scaled_font_create -}; - -/** - * cairo_atsui_font_face_create_for_atsu_font_id - * @font_id: an ATSUFontID for the font. - * - * Creates a new font for the ATSUI font backend based on an - * #ATSUFontID. This font can then be used with - * cairo_set_font_face() or cairo_scaled_font_create(). - * - * Return value: a newly created #cairo_font_face_t. Free with - * cairo_font_face_destroy() when you are done using it. - * - * Since: 1.4 - **/ -cairo_font_face_t * -cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id) -{ - cairo_atsui_font_face_t *font_face; - - font_face = malloc (sizeof (cairo_atsui_font_face_t)); - if (!font_face) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_font_face_t *)&_cairo_font_face_nil; - } - - font_face->font_id = font_id; - - _cairo_font_face_init (&font_face->base, &_cairo_atsui_font_face_backend); - - return &font_face->base; -} - -static OSStatus -CreateSizedCopyOfStyle(ATSUStyle inStyle, - const Fixed *theSize, - const CGAffineTransform *theTransform, - ATSUStyle *style) -{ - OSStatus err; - const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, - kATSUFontMatrixTag }; - const ByteCount theFontStyleSizes[] = { sizeof(Fixed), - sizeof(CGAffineTransform) }; - ATSUAttributeValuePtr theFontStyleValues[] = { (Fixed *)theSize, - (CGAffineTransform *)theTransform }; - - err = ATSUCreateAndCopyStyle (inStyle, style); - if (err != noErr) - return err; - - err = ATSUSetAttributes(*style, - sizeof(theFontStyleTags) / - sizeof(ATSUAttributeTag), theFontStyleTags, - theFontStyleSizes, theFontStyleValues); - if (err != noErr) - ATSUDisposeStyle (*style); - - return err; -} - - -static cairo_status_t -_cairo_atsui_font_set_metrics (cairo_atsui_font_t *font) -{ - cairo_status_t status; - ATSFontRef atsFont; - ATSFontMetrics metrics; - OSStatus err; - - atsFont = FMGetATSFontRefFromFont(font->fontID); - - if (atsFont) { - err = ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, &metrics); - - if (err == noErr) { - cairo_font_extents_t extents; - - extents.ascent = metrics.ascent; - extents.descent = -metrics.descent; - extents.height = extents.ascent + extents.descent + metrics.leading; - extents.max_x_advance = metrics.maxAdvanceWidth; - - /* The FT backend doesn't handle max_y_advance either, so we'll ignore it for now. */ - extents.max_y_advance = 0.0; - - status = _cairo_scaled_font_set_metrics (&font->base, &extents); - - return status; - } - } - - return _cairo_error (CAIRO_STATUS_NULL_POINTER); -} - -static cairo_status_t -_cairo_atsui_font_create_scaled (cairo_font_face_t *font_face, - ATSUFontID font_id, - ATSUStyle style, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font_out) -{ - cairo_atsui_font_t *font = NULL; - OSStatus err; - cairo_status_t status; - double xscale = 1.0; - double yscale = 1.0; - - font = malloc(sizeof(cairo_atsui_font_t)); - if (font == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - memset (font, 0, sizeof(cairo_atsui_font_t)); - - status = _cairo_scaled_font_init (&font->base, - font_face, font_matrix, ctm, options, - &cairo_atsui_scaled_font_backend); - if (status) { - free (font); - return status; - } - - status = _cairo_matrix_compute_scale_factors (&font->base.scale, - &xscale, &yscale, 1); - if (status) - goto FAIL; - - /* ATS can't handle 0-sized bits; we end up in an odd infinite loop - * if we send down a size of 0. */ - if (xscale == 0.0) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto FAIL; - } - - font->font_matrix = CGAffineTransformMake (1., 0., - 0., yscale/xscale, - 0., 0.); - font->size = FloatToFixed (xscale); - font->style = NULL; - - err = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix, &font->style); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto FAIL; - } - - { - Fixed theSize = FloatToFixed(1.0); - const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag }; - const ByteCount theFontStyleSizes[] = { sizeof(Fixed) }; - ATSUAttributeValuePtr theFontStyleValues[] = { &theSize }; - - err = ATSUSetAttributes(style, - sizeof(theFontStyleTags) / - sizeof(ATSUAttributeTag), theFontStyleTags, - theFontStyleSizes, theFontStyleValues); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto FAIL; - } - } - - font->unscaled_style = style; - font->fontID = font_id; - - *font_out = &font->base; - - status = _cairo_atsui_font_set_metrics (font); - - font->cgfref = 0; - FAIL: - if (status) { - if (font) { - if (font->style) - ATSUDisposeStyle(font->style); - _cairo_scaled_font_fini(&font->base); - free (font); - } - - return status; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font_out) -{ - cairo_status_t status; - ATSUStyle style; - ATSUFontID fontID; - OSStatus err; - Boolean isItalic, isBold; - const char *family = toy_face->family; - const char *full_name; - - err = ATSUCreateStyle(&style); - if (err != noErr) { - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - switch (toy_face->weight) { - case CAIRO_FONT_WEIGHT_BOLD: - isBold = true; - break; - case CAIRO_FONT_WEIGHT_NORMAL: - default: - isBold = false; - break; - } - - switch (toy_face->slant) { - case CAIRO_FONT_SLANT_ITALIC: - isItalic = true; - break; - case CAIRO_FONT_SLANT_OBLIQUE: - isItalic = false; - break; - case CAIRO_FONT_SLANT_NORMAL: - default: - isItalic = false; - break; - } - - /* The APIs for resolving a font family to a regular - * font face are all broken or deprecated in 10.4, so - * just try our best to find a sensible font. - * - * First we try to map the CSS generic font families - * to fonts that should always be available. - * If the family isn't a CSS family, guess that the - * font family name is the same as the full name of the - * regular font instance, which works in many cases. - * 'Times' is one common exception to this rule, so it's - * handled specially. - */ - if (!strcmp(family, "serif") || !strcmp(family, "Times")) - full_name = "Times Roman"; - else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans")) - full_name = "Helvetica"; - else if (!strcmp(family, "cursive")) - full_name = "Apple Chancery"; - else if (!strcmp(family, "fantasy")) - full_name = "American Typewriter"; - else if (!strcmp(family, "monospace") || !strcmp(family, "mono")) - full_name = "Courier"; - else - full_name = family; - - err = ATSUFindFontFromName(family, strlen(family), - kFontFullName, - kFontNoPlatformCode, - kFontRomanScript, - kFontNoLanguageCode, &fontID); - - if (err != noErr) { - /* Look for any font instance in the family. This may - * succeed, but select the bold or italic face. It only - * selects the first loaded font instance in the family. - */ - err = ATSUFindFontFromName(family, strlen(family), - kFontFamilyName, - kFontNoPlatformCode, - kFontRomanScript, - kFontNoLanguageCode, &fontID); - if (err != noErr) { - /* Last chance - try Courier. */ - full_name = "Courier"; - err = ATSUFindFontFromName(full_name, strlen(full_name), - kFontFullName, - kFontNoPlatformCode, - kFontRomanScript, - kFontNoLanguageCode, &fontID); - if (err != noErr) { - ATSUDisposeStyle (style); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - } - } - - { - ATSUAttributeTag styleTags[] = - { kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag }; - ATSUAttributeValuePtr styleValues[] = { &isItalic, &isBold, &fontID }; - ByteCount styleSizes[] = - { sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID) }; - - err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags), - styleTags, styleSizes, styleValues); - if (err != noErr) { - ATSUDisposeStyle (style); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - } - - status = _cairo_atsui_font_create_scaled (&toy_face->base, fontID, style, - font_matrix, ctm, options, font_out); - if (status) - ATSUDisposeStyle (style); - - return status; -} - -static void -_cairo_atsui_font_fini(void *abstract_font) -{ - cairo_atsui_font_t *font = abstract_font; - - if (font == NULL) - return; - - if (font->style) - ATSUDisposeStyle(font->style); - if (font->unscaled_style) - ATSUDisposeStyle(font->unscaled_style); - if (font->cgfref) - CGFontRelease(font->cgfref); - -} - -static GlyphID -_cairo_atsui_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) { - unsigned long index = _cairo_scaled_glyph_index (scaled_glyph); - if (index > 0xffff) - return kATSDeletedGlyphcode; - return index; -} - -static cairo_status_t -_cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font, - cairo_scaled_glyph_t *scaled_glyph) -{ - cairo_status_t status; - cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; - OSStatus err; - ATSGlyphScreenMetrics metricsH; - GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); - double xscale, yscale; - - if (theGlyph == kATSDeletedGlyphcode) { - _cairo_scaled_glyph_set_metrics (scaled_glyph, - &scaled_font->base, - &extents); - return CAIRO_STATUS_SUCCESS; - } - - /* We calculate the advance from the screen metrics. We - * could probably take this from the glyph path. - */ - err = ATSUGlyphGetScreenMetrics (scaled_font->style, - 1, &theGlyph, 0, false, - false, &metricsH); - if (err != noErr) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - /* Scale down to font units.*/ - status = _cairo_matrix_compute_scale_factors (&scaled_font->base.scale, - &xscale, &yscale, 1); - if (status) - return status; - - xscale = 1.0/xscale; - yscale = 1.0/yscale; - - extents.x_advance = metricsH.deviceAdvance.x * xscale; - extents.y_advance = 0; - - extents.x_bearing = metricsH.topLeft.x * xscale; - extents.y_bearing = -metricsH.topLeft.y * yscale; - extents.width = metricsH.width * xscale; - extents.height = metricsH.height * yscale; - - _cairo_scaled_glyph_set_metrics (scaled_glyph, - &scaled_font->base, - &extents); - return CAIRO_STATUS_SUCCESS; -} - -static OSStatus -_move_to (const Float32Point *point, - void *callback_data) -{ - cairo_status_t status; - cairo_atsui_scaled_path_t *scaled_path = callback_data; - double x = point->x; - double y = point->y; - - cairo_matrix_transform_point (scaled_path->scale, &x, &y); - status = _cairo_path_fixed_close_path (scaled_path->path); - if (status) - return CAIRO_CG_PATH_ERROR; - - status = _cairo_path_fixed_move_to (scaled_path->path, - _cairo_fixed_from_double (x), - _cairo_fixed_from_double (y)); - if (status) - return CAIRO_CG_PATH_ERROR; - - return noErr; -} - -static OSStatus -_line_to (const Float32Point *point, - void *callback_data) -{ - cairo_status_t status; - cairo_atsui_scaled_path_t *scaled_path = callback_data; - double x = point->x; - double y = point->y; - - cairo_matrix_transform_point (scaled_path->scale, &x, &y); - - status = _cairo_path_fixed_line_to (scaled_path->path, - _cairo_fixed_from_double (x), - _cairo_fixed_from_double (y)); - if (status) - return CAIRO_CG_PATH_ERROR; - - return noErr; -} - -static OSStatus -_curve_to (const Float32Point *point1, - const Float32Point *point2, - const Float32Point *point3, - void *callback_data) -{ - cairo_status_t status; - cairo_atsui_scaled_path_t *scaled_path = callback_data; - double x1 = point1->x; - double y1 = point1->y; - double x2 = point2->x; - double y2 = point2->y; - double x3 = point3->x; - double y3 = point3->y; - - cairo_matrix_transform_point (scaled_path->scale, &x1, &y1); - cairo_matrix_transform_point (scaled_path->scale, &x2, &y2); - cairo_matrix_transform_point (scaled_path->scale, &x3, &y3); - - status = _cairo_path_fixed_curve_to (scaled_path->path, - _cairo_fixed_from_double (x1), - _cairo_fixed_from_double (y1), - _cairo_fixed_from_double (x2), - _cairo_fixed_from_double (y2), - _cairo_fixed_from_double (x3), - _cairo_fixed_from_double (y3)); - if (status) - return CAIRO_CG_PATH_ERROR; - - return noErr; -} - -static OSStatus -_close_path (void *callback_data) - -{ - cairo_status_t status; - cairo_atsui_scaled_path_t *scaled_path = callback_data; - - status = _cairo_path_fixed_close_path (scaled_path->path); - if (status) - return CAIRO_CG_PATH_ERROR; - - return noErr; -} - -static cairo_status_t -_cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font, - cairo_scaled_glyph_t *scaled_glyph) -{ - cairo_status_t status; - static ATSCubicMoveToUPP moveProc = NULL; - static ATSCubicLineToUPP lineProc = NULL; - static ATSCubicCurveToUPP curveProc = NULL; - static ATSCubicClosePathUPP closePathProc = NULL; - GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); - OSStatus err; - cairo_atsui_scaled_path_t scaled_path; - cairo_matrix_t *font_to_device = &scaled_font->base.scale; - cairo_matrix_t unscaled_font_to_device; - double xscale; - double yscale; - - scaled_path.path = _cairo_path_fixed_create (); - if (!scaled_path.path) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - if (theGlyph == kATSDeletedGlyphcode) { - _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, - scaled_path.path); - - return CAIRO_STATUS_SUCCESS; - } - - /* extract the rotation/shear component of the scale matrix. */ - status = _cairo_matrix_compute_scale_factors (font_to_device, &xscale, &yscale, 1); - if (status) - goto FAIL; - - cairo_matrix_init (&unscaled_font_to_device, - font_to_device->xx, - font_to_device->yx, - font_to_device->xy, - font_to_device->yy, 0., 0.); - cairo_matrix_scale (&unscaled_font_to_device, 1.0/xscale, 1.0/yscale); - - scaled_path.scale = &unscaled_font_to_device; - - if (moveProc == NULL) { - moveProc = NewATSCubicMoveToUPP(_move_to); - lineProc = NewATSCubicLineToUPP(_line_to); - curveProc = NewATSCubicCurveToUPP(_curve_to); - closePathProc = NewATSCubicClosePathUPP(_close_path); - } - - err = ATSUGlyphGetCubicPaths(scaled_font->style, - theGlyph, - moveProc, - lineProc, - curveProc, - closePathProc, (void *)&scaled_path, &err); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto FAIL; - } - - _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, - scaled_path.path); - - return CAIRO_STATUS_SUCCESS; - - FAIL: - _cairo_path_fixed_destroy (scaled_path.path); - return status; -} - -static cairo_status_t -_cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font, - cairo_scaled_glyph_t *scaled_glyph) -{ - OSStatus err; - CGContextRef drawingContext; - cairo_image_surface_t *surface; - cairo_format_t format; - cairo_status_t status; - - ATSFontRef atsFont; - CGFontRef cgFont; - cairo_scaled_font_t base = scaled_font->base; - cairo_font_extents_t extents = base.extents; - - GlyphID theGlyph = _cairo_atsui_scaled_glyph_index (scaled_glyph); - ATSGlyphScreenMetrics metricsH; - double left, bottom, width, height; - double xscale, yscale; - CGRect bbox; - CGAffineTransform transform; - - if (theGlyph == kATSDeletedGlyphcode) { - surface = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); - status = cairo_surface_status ((cairo_surface_t *)surface); - if (status) - return status; - - _cairo_scaled_glyph_set_surface (scaled_glyph, - &base, - surface); - return CAIRO_STATUS_SUCCESS; - } - - /* Compute a box to contain the glyph mask. The vertical - * sizes come from the font extents; extra pixels are - * added to account for fractional sizes. - */ - height = extents.ascent + extents.descent + 2.0; - bottom = -extents.descent - 1.0; - - status = _cairo_matrix_compute_scale_factors (&base.scale, - &xscale, &yscale, 1); - if (status) - return status; - - bbox = CGRectApplyAffineTransform (CGRectMake (1.0, bottom, 1.0, height), CGAffineTransformMakeScale(xscale, yscale)); - bottom = CGRectGetMinY (bbox); - height = bbox.size.height; - - /* Horizontal sizes come from the glyph typographic metrics. - * It is possible that this might result in clipped text - * in fonts where the typographic bounds don't cover the ink. - * The width is recalculated, since metricsH.width is rounded. - */ - err = ATSUGlyphGetScreenMetrics (scaled_font->style, - 1, &theGlyph, 0, false, - false, &metricsH); - if (err != noErr) { - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - left = metricsH.sideBearing.x - 1.0; - width = metricsH.deviceAdvance.x - - metricsH.sideBearing.x - + metricsH.otherSideBearing.x + 2.0; - - /* The xy and yx components are negated because the y-axis - * is flipped into the cairo system then flipped back, ie: - * [1 0][xx yx][1 0] - * [0 -1][xy yy][0 -1] - */ - transform = CGAffineTransformMake (base.scale.xx, - -base.scale.yx, - -base.scale.xy, - base.scale.yy, - 0., 0.); - status = _cairo_matrix_compute_scale_factors (&base.scale, - &xscale, &yscale, 1); - if (status) - return status; - - transform = CGAffineTransformScale (transform, 1.0/xscale, 1.0/yscale); - - /* Rotate the bounding box. This computes the smallest CGRect - * that would contain the bounding box after rotation. - */ - bbox = CGRectApplyAffineTransform (CGRectMake (left, bottom, - width, height), transform); - /* Compute the smallest CGRect with integer coordinates - * that contains the bounding box. - */ - bbox = CGRectIntegral (bbox); - - left = CGRectGetMinX (bbox); - bottom = CGRectGetMinY (bbox); - - /* XXX should we select format based on antialiasing flags, as ft does? */ - format = CAIRO_FORMAT_A8; - - /* create the glyph mask surface */ - surface = (cairo_image_surface_t *)cairo_image_surface_create (format, bbox.size.width, bbox.size.height); - status = cairo_surface_status ((cairo_surface_t *)surface); - if (status) - return status; - - /* Create a CGBitmapContext for the dest surface for drawing into */ - { - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray (); - - drawingContext = CGBitmapContextCreate (surface->data, - surface->width, - surface->height, - 8, - surface->stride, - colorSpace, - kCGImageAlphaNone); - CGColorSpaceRelease (colorSpace); - } - - if (!drawingContext) { - cairo_surface_destroy ((cairo_surface_t *)surface); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - atsFont = FMGetATSFontRefFromFont (scaled_font->fontID); - cgFont = CGFontCreateWithPlatformFont (&atsFont); - - CGContextSetFont (drawingContext, cgFont); - - if (base.options.antialias == CAIRO_ANTIALIAS_NONE) { - CGContextSetShouldAntialias (drawingContext, false); - } - - /* solid white */ - CGContextSetRGBFillColor (drawingContext, 1.0, 1.0, 1.0, 1.0); - - CGContextSetFontSize (drawingContext, 1.0); - CGContextTranslateCTM (drawingContext, -left, -bottom); - CGContextScaleCTM (drawingContext, xscale, yscale); - CGContextSetTextMatrix (drawingContext, transform); - CGContextShowGlyphsAtPoint (drawingContext, 0, 0, - &theGlyph, 1); - - CGContextRelease (drawingContext); - - /* correct for difference between cairo and quartz - * coordinate systems. - */ - cairo_surface_set_device_offset ((cairo_surface_t *)surface, - -left, (bbox.size.height + bottom)); - _cairo_scaled_glyph_set_surface (scaled_glyph, - &base, - surface); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_atsui_font_scaled_glyph_init (void *abstract_font, - cairo_scaled_glyph_t *scaled_glyph, - cairo_scaled_glyph_info_t info) -{ - cairo_atsui_font_t *scaled_font = abstract_font; - cairo_status_t status; - - if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) { - status = _cairo_atsui_font_init_glyph_metrics (scaled_font, scaled_glyph); - if (status) - return status; - } - - if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) { - status = _cairo_atsui_scaled_font_init_glyph_path (scaled_font, scaled_glyph); - if (status) - return status; - } - - if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { - status = _cairo_atsui_scaled_font_init_glyph_surface (scaled_font, scaled_glyph); - if (status) - return status; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_atsui_font_text_to_glyphs (void *abstract_font, - double x, - double y, - const char *utf8, - cairo_glyph_t **glyphs, - int *num_glyphs) -{ - cairo_status_t status = CAIRO_STATUS_SUCCESS; - uint16_t *utf16; - int n16; - OSStatus err; - ATSUTextLayout textLayout; - ATSLayoutRecord *layoutRecords; - cairo_atsui_font_t *font = abstract_font; - ItemCount glyphCount; - int i; - CGPoint point; - double xscale, yscale; - CGAffineTransform device_to_user_scale; - - status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16); - if (status) - goto BAIL3; - - err = ATSUCreateTextLayout(&textLayout); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL3; - } - - err = ATSUSetTextPointerLocation(textLayout, utf16, 0, n16, n16); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL2; - } - - /* Set the style for all of the text */ - err = ATSUSetRunStyle(textLayout, - font->style, kATSUFromTextBeginning, kATSUToTextEnd); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL2; - } - - err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, - 0, - kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, - (void *)&layoutRecords, - &glyphCount); - if (err != noErr) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL2; - } - - status = _cairo_matrix_compute_scale_factors (&font->base.ctm, - &xscale, &yscale, 1); - if (status) - goto BAIL2; - - *num_glyphs = glyphCount - 1; - *glyphs = - (cairo_glyph_t *) _cairo_malloc_ab(*num_glyphs, sizeof (cairo_glyph_t)); - if (*glyphs == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL1; - } - - device_to_user_scale = - CGAffineTransformInvert (CGAffineTransformMake (xscale, 0, - 0, yscale, - 0, 0)); - for (i = 0; i < *num_glyphs; i++) { - (*glyphs)[i].index = layoutRecords[i].glyphID; - /* ATSLayoutRecord.realPos is in device units, convert to user units */ - point = CGPointMake (FixedToFloat (layoutRecords[i].realPos), 0); - point = CGPointApplyAffineTransform (point, device_to_user_scale); - - (*glyphs)[i].x = x + point.x; - (*glyphs)[i].y = y; - } - - BAIL1: - /* TODO ignored return value. Is there anything we should do? */ - ATSUDirectReleaseLayoutDataArrayPtr(NULL, - kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, - (void *) &layoutRecords); - BAIL2: - ATSUDisposeTextLayout(textLayout); - BAIL3: - free (utf16); - - return status; -} - -ATSUStyle -_cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont) -{ - cairo_atsui_font_t *afont = (cairo_atsui_font_t *) sfont; - - return afont->style; -} - -ATSUFontID -_cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont) -{ - cairo_atsui_font_t *afont = (cairo_atsui_font_t *) sfont; - - return afont->fontID; -} - -CGFontRef -_cairo_atsui_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont) -{ - cairo_atsui_font_t *afont = (cairo_atsui_font_t *) sfont; - - if (!afont->cgfref) { - ATSFontRef atsfref = FMGetATSFontRefFromFont (afont->fontID); - afont->cgfref = CGFontCreateWithPlatformFont (&atsfref); - } - return afont->cgfref; -} - - -static cairo_int_status_t -_cairo_atsui_load_truetype_table (void *abstract_font, - unsigned long tag, - long offset, - unsigned char *buffer, - unsigned long *length) -{ - cairo_atsui_font_t *scaled_font = abstract_font; - ATSFontRef atsFont; - OSStatus err; - - atsFont = FMGetATSFontRefFromFont (scaled_font->fontID); - err = ATSFontGetTable ( atsFont, tag, - (ByteOffset) offset, - (ByteCount) *length, - buffer, - length); - if (err != noErr) { - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - return CAIRO_STATUS_SUCCESS; -} - -const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = { - CAIRO_FONT_TYPE_ATSUI, - _cairo_atsui_font_create_toy, - _cairo_atsui_font_fini, - _cairo_atsui_font_scaled_glyph_init, - _cairo_atsui_font_text_to_glyphs, - NULL, /* ucs4_to_index */ - NULL, /* show_glyphs */ - _cairo_atsui_load_truetype_table, - NULL, /* map_glyphs_to_unicode */ -}; - diff --git a/gfx/cairo/cairo/src/cairo-atsui.h b/gfx/cairo/cairo/src/cairo-atsui.h deleted file mode 100644 index 9f39176d7e0..00000000000 --- a/gfx/cairo/cairo/src/cairo-atsui.h +++ /dev/null @@ -1,58 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2004 Calum Robinson - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Calum Robinson - * - * Contributor(s): - * Calum Robinson - */ - -#ifndef CAIRO_ATSUI_H -#define CAIRO_ATSUI_H - -#include - -#if CAIRO_HAS_ATSUI_FONT - -/* ATSUI platform-specific font interface */ - -#include - -CAIRO_BEGIN_DECLS - -cairo_public cairo_font_face_t * -cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id); - -CAIRO_END_DECLS - -#else /* CAIRO_HAS_ATSUI_FONT */ -# error Cairo was not compiled with support for the atsui font backend -#endif /* CAIRO_HAS_ATSUI_FONT */ - -#endif /* CAIRO_ATSUI_H */ diff --git a/gfx/cairo/cairo/src/cairo-deprecated.h b/gfx/cairo/cairo/src/cairo-deprecated.h index 35a4eb995b1..c73d2b781d6 100644 --- a/gfx/cairo/cairo/src/cairo-deprecated.h +++ b/gfx/cairo/cairo/src/cairo-deprecated.h @@ -50,6 +50,8 @@ */ #define CAIRO_FORMAT_RGB16_565 4 +#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ + #ifndef _CAIROINT_H_ /* Obsolete functions. These definitions exist to coerce the compiler @@ -104,6 +106,7 @@ #define cairo_ps_surface_set_dpi cairo_ps_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution #define cairo_pdf_surface_set_dpi cairo_pdf_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution #define cairo_svg_surface_set_dpi cairo_svg_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution +#define cairo_atsui_font_face_create_for_atsu_font_id cairo_atsui_font_face_create_for_atsu_font_id_REPLACED_BY_cairo_quartz_font_face_create_for_atsu_font_id #define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path #define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat diff --git a/gfx/cairo/cairo/src/cairo-features.h.in b/gfx/cairo/cairo/src/cairo-features.h.in index e03e33ed3f0..e22d113fbc5 100644 --- a/gfx/cairo/cairo/src/cairo-features.h.in +++ b/gfx/cairo/cairo/src/cairo-features.h.in @@ -53,9 +53,9 @@ #define CAIRO_VERSION_MAJOR 1 #define CAIRO_VERSION_MINOR 5 -#define CAIRO_VERSION_MICRO 12 +#define CAIRO_VERSION_MICRO 16 -#define CAIRO_VERSION_STRING "1.5.12" +#define CAIRO_VERSION_STRING "1.5.16" @PS_SURFACE_FEATURE@ @@ -87,7 +87,7 @@ @WIN32_FONT_FEATURE@ -@ATSUI_FONT_FEATURE@ +@QUARTZ_FONT_FEATURE@ @PNG_FUNCTIONS_FEATURE@ diff --git a/gfx/cairo/cairo/src/cairo-font-face.c b/gfx/cairo/cairo/src/cairo-font-face.c index c7f0a44bff7..49c8cdf7361 100644 --- a/gfx/cairo/cairo/src/cairo-font-face.c +++ b/gfx/cairo/cairo/src/cairo-font-face.c @@ -433,6 +433,7 @@ _cairo_toy_font_face_create (const char *family, return &font_face->base; UNWIND_FONT_FACE_INIT: + _cairo_toy_font_face_fini (font_face); UNWIND_FONT_FACE_MALLOC: free (font_face); UNWIND_HASH_TABLE_LOCK: diff --git a/gfx/cairo/cairo/src/cairo-glitz-surface.c b/gfx/cairo/cairo/src/cairo-glitz-surface.c index 51448954a7f..592dd134ade 100644 --- a/gfx/cairo/cairo/src/cairo-glitz-surface.c +++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c @@ -817,7 +817,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, (((int) (gradient->stops[i].color.green_short >> 8)) << 8) | (((int) (gradient->stops[i].color.blue_short >> 8))); - params[n_base_params + 3 * i + 0] = gradient->stops[i].x; + params[n_base_params + 3 * i + 0] = _cairo_fixed_16_16_from_double (gradient->stops[i].offset); params[n_base_params + 3 * i + 1] = i << 16; params[n_base_params + 3 * i + 2] = 0; } diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c index 5049399f3d4..0f35b7f45b6 100644 --- a/gfx/cairo/cairo/src/cairo-gstate.c +++ b/gfx/cairo/cairo/src/cairo-gstate.c @@ -255,7 +255,7 @@ _cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out) cairo_status_t _cairo_gstate_save (cairo_gstate_t **gstate) { - cairo_gstate_t *top; + cairo_gstate_t *top = NULL; cairo_status_t status; status = _cairo_gstate_clone (*gstate, &top); @@ -290,27 +290,6 @@ _cairo_gstate_restore (cairo_gstate_t **gstate) return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_gstate_recursive_apply_clip_path (cairo_gstate_t *gstate, - cairo_clip_path_t *cpath) -{ - cairo_status_t status; - - if (cpath == NULL) - return CAIRO_STATUS_SUCCESS; - - status = _cairo_gstate_recursive_apply_clip_path (gstate, cpath->prev); - if (status) - return status; - - return _cairo_clip_clip (&gstate->clip, - &cpath->path, - cpath->fill_rule, - cpath->tolerance, - cpath->antialias, - gstate->target); -} - /** * _cairo_gstate_redirect_target: * @gstate: a #cairo_gstate_t diff --git a/gfx/cairo/cairo/src/cairo-hull.c b/gfx/cairo/cairo/src/cairo-hull.c index a9e55e6c5b2..73d95c554a1 100644 --- a/gfx/cairo/cairo/src/cairo-hull.c +++ b/gfx/cairo/cairo/src/cairo-hull.c @@ -192,7 +192,7 @@ cairo_status_t _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices) { cairo_status_t status; - cairo_hull_t *hull; + cairo_hull_t *hull = NULL; int num_hull = *num_vertices; status = _cairo_hull_create (vertices, num_hull, &hull); diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c index 57dbdb8be44..092b77e377b 100644 --- a/gfx/cairo/cairo/src/cairo-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-image-surface.c @@ -59,6 +59,7 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) case PIXMAN_a4: case PIXMAN_r1g2b1: case PIXMAN_b1g2r1: case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4: case PIXMAN_g4: case PIXMAN_g1: + case PIXMAN_yuy2: case PIXMAN_yv12: default: return CAIRO_FORMAT_INVALID; } @@ -100,6 +101,8 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) case PIXMAN_c4: case PIXMAN_g4: case PIXMAN_g1: + case PIXMAN_yuy2: + case PIXMAN_yv12: return CAIRO_CONTENT_COLOR; case PIXMAN_a8: case PIXMAN_a1: @@ -141,143 +144,104 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, return &surface->base; } -/* XXX: This function should really live inside pixman. */ -pixman_format_code_t -_pixman_format_from_masks (cairo_format_masks_t *masks) +cairo_int_status_t +_pixman_format_from_masks (cairo_format_masks_t *masks, + pixman_format_code_t *format_ret) { - switch (masks->bpp) { - case 32: - if (masks->alpha_mask == 0xff000000 && - masks->red_mask == 0x00ff0000 && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x000000ff) - { - return PIXMAN_a8r8g8b8; - } - if (masks->alpha_mask == 0x00000000 && - masks->red_mask == 0x00ff0000 && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x000000ff) - { - return PIXMAN_x8r8g8b8; - } - if (masks->alpha_mask == 0xff000000 && - masks->red_mask == 0x000000ff && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x00ff0000) - { - return PIXMAN_a8b8g8r8; - } - if (masks->alpha_mask == 0x00000000 && - masks->red_mask == 0x000000ff && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x00ff0000) - { - return PIXMAN_x8b8g8r8; - } - break; - case 16: - if (masks->alpha_mask == 0x0000 && - masks->red_mask == 0xf800 && - masks->green_mask == 0x07e0 && - masks->blue_mask == 0x001f) - { - return PIXMAN_r5g6b5; - } - if (masks->alpha_mask == 0x0000 && - masks->red_mask == 0x7c00 && - masks->green_mask == 0x03e0 && - masks->blue_mask == 0x001f) - { - return PIXMAN_x1r5g5b5; - } - break; - case 8: - if (masks->alpha_mask == 0xff) - { - return PIXMAN_a8; - } - break; - case 1: - if (masks->alpha_mask == 0x1) - { - return PIXMAN_a1; - } - break; + pixman_format_code_t format; + int format_type; + int a, r, g, b; + cairo_format_masks_t format_masks; + + a = _cairo_popcount (masks->alpha_mask); + r = _cairo_popcount (masks->red_mask); + g = _cairo_popcount (masks->green_mask); + b = _cairo_popcount (masks->blue_mask); + + if (masks->red_mask) { + if (masks->red_mask > masks->blue_mask) + format_type = PIXMAN_TYPE_ARGB; + else + format_type = PIXMAN_TYPE_ABGR; + } else if (masks->alpha_mask) { + format_type = PIXMAN_TYPE_A; + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; } - fprintf (stderr, - "Error: Cairo " PACKAGE_VERSION " does not yet support the requested image format:\n" - "\tDepth: %d\n" - "\tAlpha mask: 0x%08lx\n" - "\tRed mask: 0x%08lx\n" - "\tGreen mask: 0x%08lx\n" - "\tBlue mask: 0x%08lx\n" - "Please file an enhancement request (quoting the above) at:\n" - PACKAGE_BUGREPORT "\n", - masks->bpp, masks->alpha_mask, - masks->red_mask, masks->green_mask, masks->blue_mask); + format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b); - ASSERT_NOT_REACHED; - return 0; + if (! pixman_format_supported_destination (format)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Sanity check that we got out of PIXMAN_FORMAT exactly what we + * expected. This avoid any problems from something bizarre like + * alpha in the least-significant bits, or insane channel order, + * or whatever. */ + _pixman_format_to_masks (format, &format_masks); + + if (masks->bpp != format_masks.bpp || + masks->red_mask != format_masks.red_mask || + masks->green_mask != format_masks.green_mask || + masks->blue_mask != format_masks.blue_mask) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + *format_ret = format; + return CAIRO_STATUS_SUCCESS; } -/* XXX: This function should really live inside pixman. */ +/* A mask consisting of N bits set to 1. */ +#define MASK(N) ((1 << (N))-1) + void -_pixman_format_to_masks (pixman_format_code_t pixman_format, - uint32_t *bpp, - uint32_t *red, - uint32_t *green, - uint32_t *blue) +_pixman_format_to_masks (pixman_format_code_t format, + cairo_format_masks_t *masks) { - *red = 0x0; - *green = 0x0; - *blue = 0x0; + int a, r, g, b; - switch (pixman_format) - { - case PIXMAN_a8r8g8b8: - case PIXMAN_x8r8g8b8: + masks->bpp = PIXMAN_FORMAT_BPP (format); + + /* Number of bits in each channel */ + a = PIXMAN_FORMAT_A (format); + r = PIXMAN_FORMAT_R (format); + g = PIXMAN_FORMAT_G (format); + b = PIXMAN_FORMAT_B (format); + + switch (PIXMAN_FORMAT_TYPE (format)) { + case PIXMAN_TYPE_ARGB: + masks->alpha_mask = MASK (a) << (r + g + b); + masks->red_mask = MASK (r) << (g + b); + masks->green_mask = MASK (g) << (b); + masks->blue_mask = MASK (b); + return; + case PIXMAN_TYPE_ABGR: + masks->alpha_mask = MASK (a) << (b + g + r); + masks->blue_mask = MASK (b) << (g +r); + masks->green_mask = MASK (g) << (r); + masks->red_mask = MASK (r); + return; + case PIXMAN_TYPE_A: + masks->alpha_mask = MASK (a); + masks->red_mask = 0; + masks->green_mask = 0; + masks->blue_mask = 0; + return; + case PIXMAN_TYPE_OTHER: + case PIXMAN_TYPE_COLOR: + case PIXMAN_TYPE_GRAY: + case PIXMAN_TYPE_YUY2: + case PIXMAN_TYPE_YV12: default: - *bpp = 32; - *red = 0x00ff0000; - *green = 0x0000ff00; - *blue = 0x000000ff; - break; - - case PIXMAN_a8b8g8r8: - case PIXMAN_x8b8g8r8: - *bpp = 32; - *red = 0x000000ff; - *green = 0x0000ff00; - *blue = 0x00ff0000; - break; - - case PIXMAN_r5g6b5: - *bpp = 16; - *red = 0xf800; - *green = 0x07e0; - *blue = 0x001f; - break; - - case PIXMAN_x1r5g5b5: - *bpp = 16; - *red = 0x7c00; - *green = 0x03e0; - *blue = 0x001f; - break; - - case PIXMAN_a8: - *bpp = 8; - break; - - case PIXMAN_a1: - *bpp = 1; - break; + masks->alpha_mask = 0; + masks->red_mask = 0; + masks->green_mask = 0; + masks->blue_mask = 0; + return; } } - /* XXX: This function really should be eliminated. We don't really * want to advertise a cairo image surface that supports any possible * format. A minimal step would be to replace this function with one @@ -289,9 +253,25 @@ _cairo_image_surface_create_with_masks (unsigned char *data, int height, int stride) { + cairo_int_status_t status; pixman_format_code_t pixman_format; - pixman_format = _pixman_format_from_masks (masks); + status = _pixman_format_from_masks (masks, &pixman_format); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + fprintf (stderr, + "Error: Cairo " PACKAGE_VERSION " does not yet support the requested image format:\n" + "\tDepth: %d\n" + "\tAlpha mask: 0x%08lx\n" + "\tRed mask: 0x%08lx\n" + "\tGreen mask: 0x%08lx\n" + "\tBlue mask: 0x%08lx\n" + "Please file an enhancement request (quoting the above) at:\n" + PACKAGE_BUGREPORT "\n", + masks->bpp, masks->alpha_mask, + masks->red_mask, masks->green_mask, masks->blue_mask); + + ASSERT_NOT_REACHED; + } return _cairo_image_surface_create_with_pixman_format (data, pixman_format, @@ -395,9 +375,6 @@ _cairo_image_surface_create_with_content (cairo_content_t content, width, height); } -/* pixman required stride alignment in bytes. should be power of two. */ -#define STRIDE_ALIGNMENT (sizeof (uint32_t)) - /** * cairo_format_stride_for_width: * @format: A #cairo_format_t value @@ -439,7 +416,7 @@ cairo_format_stride_for_width (cairo_format_t format, if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp)) return -1; - return ((bpp*width+7)/8 + STRIDE_ALIGNMENT-1) & ~(STRIDE_ALIGNMENT-1); + return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); } slim_hidden_def (cairo_format_stride_for_width); @@ -498,7 +475,7 @@ cairo_image_surface_create_for_data (unsigned char *data, if (! CAIRO_FORMAT_VALID (format)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); - if ((stride & (STRIDE_ALIGNMENT-1)) != 0) + if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); pixman_format = _cairo_format_to_pixman_format_code (format); @@ -547,6 +524,7 @@ cairo_image_surface_get_data (cairo_surface_t *surface) return image_surface->data; } +slim_hidden_def (cairo_image_surface_get_data); /** * cairo_image_surface_get_format: @@ -643,6 +621,7 @@ cairo_image_surface_get_stride (cairo_surface_t *surface) return image_surface->stride; } +slim_hidden_def (cairo_image_surface_get_stride); cairo_format_t _cairo_format_from_content (cairo_content_t content) diff --git a/gfx/cairo/cairo/src/cairo-meta-surface.c b/gfx/cairo/cairo/src/cairo-meta-surface.c index 66849b484de..441a7d65b0d 100644 --- a/gfx/cairo/cairo/src/cairo-meta-surface.c +++ b/gfx/cairo/cairo/src/cairo-meta-surface.c @@ -743,7 +743,11 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, { cairo_command_t *stroke_command; - stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL; + if (type != CAIRO_META_CREATE_REGIONS) + stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL; + else + stroke_command = NULL; + if (stroke_command != NULL && type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) { @@ -783,14 +787,6 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, stroke_command->stroke.tolerance, stroke_command->stroke.antialias); i++; - if (type == CAIRO_META_CREATE_REGIONS) { - if (status == CAIRO_STATUS_SUCCESS) { - stroke_command->header.region = CAIRO_META_REGION_NATIVE; - } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { - stroke_command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK; - status = CAIRO_STATUS_SUCCESS; - } - } } else status = _cairo_surface_fill (target, command->fill.op, diff --git a/gfx/cairo/cairo/src/cairo-output-stream-private.h b/gfx/cairo/cairo/src/cairo-output-stream-private.h index 9e9e3ad50f6..1a257881948 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream-private.h +++ b/gfx/cairo/cairo/src/cairo-output-stream-private.h @@ -110,9 +110,6 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, const char *data, size_t length); -cairo_private void -_cairo_dtostr (char *buffer, size_t size, double d); - cairo_private void _cairo_output_stream_vprintf (cairo_output_stream_t *stream, const char *fmt, diff --git a/gfx/cairo/cairo/src/cairo-output-stream.c b/gfx/cairo/cairo/src/cairo-output-stream.c index b337994f146..351585e75bc 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream.c +++ b/gfx/cairo/cairo/src/cairo-output-stream.c @@ -44,6 +44,26 @@ #include #include +/* Numbers printed with %f are printed with this number of significant + * digits after the decimal. + */ +#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6 + +/* Numbers printed with %g are assumed to only have CAIRO_FIXED_FRAC_BITS + * bits of precision available after the decimal point. + * + * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal + * digits after the decimal point required to preserve the available + * precision. + * + * The conversion is: + * + * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) ) + * + * We can replace ceil(x) with (int)(x+1) since x will never be an + * integer for any likely value of CAIRO_FIXED_FRAC_BITS. + */ +#define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1)) void _cairo_output_stream_init (cairo_output_stream_t *stream, @@ -236,8 +256,6 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, } } -#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6 - /* Format a double in a locale independent way and trim trailing * zeros. Based on code from Alex Larson . * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html @@ -246,8 +264,8 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, * has been relicensed under the LGPL/MPL dual license for inclusion * into cairo (see COPYING). -- Kristian Høgsberg */ -void -_cairo_dtostr (char *buffer, size_t size, double d) +static void +_cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision) { struct lconv *locale_data; const char *decimal_point; @@ -266,40 +284,44 @@ _cairo_dtostr (char *buffer, size_t size, double d) assert (decimal_point_len != 0); - /* Using "%f" to print numbers less than 0.1 will result in - * reduced precision due to the default 6 digits after the - * decimal point. - * - * For numbers is < 0.1, we print with maximum precision and count - * the number of zeros between the decimal point and the first - * significant digit. We then print the number again with the - * number of decimal places that gives us the required number of - * significant digits. This ensures the number is correctly - * rounded. - */ - if (fabs (d) >= 0.1) { - snprintf (buffer, size, "%f", d); + if (limited_precision) { + snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d); } else { - snprintf (buffer, size, "%.18f", d); - p = buffer; + /* Using "%f" to print numbers less than 0.1 will result in + * reduced precision due to the default 6 digits after the + * decimal point. + * + * For numbers is < 0.1, we print with maximum precision and count + * the number of zeros between the decimal point and the first + * significant digit. We then print the number again with the + * number of decimal places that gives us the required number of + * significant digits. This ensures the number is correctly + * rounded. + */ + if (fabs (d) >= 0.1) { + snprintf (buffer, size, "%f", d); + } else { + snprintf (buffer, size, "%.18f", d); + p = buffer; - if (*p == '+' || *p == '-') - p++; + if (*p == '+' || *p == '-') + p++; - while (isdigit (*p)) - p++; + while (isdigit (*p)) + p++; - if (strncmp (p, decimal_point, decimal_point_len) == 0) - p += decimal_point_len; + if (strncmp (p, decimal_point, decimal_point_len) == 0) + p += decimal_point_len; - num_zeros = 0; - while (*p++ == '0') - num_zeros++; + num_zeros = 0; + while (*p++ == '0') + num_zeros++; - decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL; + decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL; - if (decimal_digits < 18) - snprintf (buffer, size, "%.*f", decimal_digits, d); + if (decimal_digits < 18) + snprintf (buffer, size, "%.*f", decimal_digits, d); + } } p = buffer; @@ -441,7 +463,10 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream, single_fmt, va_arg (ap, const char *)); break; case 'f': - _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double)); + _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE); + break; + case 'g': + _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE); break; case 'c': buffer[0] = va_arg (ap, int); diff --git a/gfx/cairo/cairo/src/cairo-path-fixed.c b/gfx/cairo/cairo/src/cairo-path-fixed.c index 55229da9fb8..75a76d088d2 100644 --- a/gfx/cairo/cairo/src/cairo-path-fixed.c +++ b/gfx/cairo/cairo/src/cairo-path-fixed.c @@ -613,8 +613,10 @@ _cairo_path_fixed_is_equal (cairo_path_fixed_t *path, if (other_buf == NULL || path_buf->num_ops != other_buf->num_ops || path_buf->num_points != other_buf->num_points || - memcmp (path_buf->op, other_buf->op, path_buf->num_ops) != 0 || - memcmp (path_buf->points, other_buf->points, path_buf->num_points != 0)) + memcmp (path_buf->op, other_buf->op, + sizeof (cairo_path_op_t) * path_buf->num_ops) != 0 || + memcmp (path_buf->points, other_buf->points, + sizeof (cairo_point_t) * path_buf->num_points) != 0) { return FALSE; } diff --git a/gfx/cairo/cairo/src/cairo-pattern.c b/gfx/cairo/cairo/src/cairo-pattern.c index 8ec39877093..bd67163de7d 100644 --- a/gfx/cairo/cairo/src/cairo-pattern.c +++ b/gfx/cairo/cairo/src/cairo-pattern.c @@ -821,7 +821,6 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, double alpha) { cairo_gradient_stop_t *stops; - cairo_fixed_t x; unsigned int i; if (pattern->n_stops >= pattern->stops_size) { @@ -834,10 +833,9 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, stops = pattern->stops; - x = _cairo_fixed_from_double (offset); for (i = 0; i < pattern->n_stops; i++) { - if (x < stops[i].x) + if (offset < stops[i].offset) { memmove (&stops[i + 1], &stops[i], sizeof (cairo_gradient_stop_t) * (pattern->n_stops - i)); @@ -846,7 +844,7 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, } } - stops[i].x = x; + stops[i].offset = offset; stops[i].color.red = red; stops[i].color.green = green; @@ -1208,7 +1206,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, } for (i = 0; i < pattern->n_stops; i++) { - pixman_stops[i].x = _cairo_fixed_to_16_16 (pattern->stops[i].x); + pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset); pixman_stops[i].color.red = pattern->stops[i].color.red_short; pixman_stops[i].color.green = pattern->stops[i].color.green_short; pixman_stops[i].color.blue = pattern->stops[i].color.blue_short; @@ -2155,7 +2153,7 @@ cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern, return _cairo_error (CAIRO_STATUS_INVALID_INDEX); if (offset) - *offset = _cairo_fixed_to_double(gradient->stops[index].x); + *offset = gradient->stops[index].offset; if (red) *red = gradient->stops[index].color.red; if (green) diff --git a/gfx/cairo/cairo/src/cairo-pdf-operators.c b/gfx/cairo/cairo/src/cairo-pdf-operators.c index 066a73f7e5e..1dbb08c6173 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-operators.c +++ b/gfx/cairo/cairo/src/cairo-pdf-operators.c @@ -108,6 +108,7 @@ typedef struct _word_wrap_stream { int column; cairo_bool_t last_write_was_space; cairo_bool_t in_hexstring; + cairo_bool_t empty_hexstring; } word_wrap_stream_t; static int @@ -136,11 +137,15 @@ _count_hexstring_up_to (const unsigned char *s, int length, int columns) { int word = 0; - while (length-- && columns--) { + while (length--) { if (*s++ != '>') word++; else return word; + + columns--; + if (columns < 0 && word > 1) + return word; } return word; @@ -158,14 +163,19 @@ _word_wrap_stream_write (cairo_output_stream_t *base, while (length) { if (*data == '<') { stream->in_hexstring = TRUE; + stream->empty_hexstring = TRUE; + stream->last_write_was_space = FALSE; data++; length--; _cairo_output_stream_printf (stream->output, "<"); + stream->column++; } else if (*data == '>') { stream->in_hexstring = FALSE; + stream->last_write_was_space = FALSE; data++; length--; _cairo_output_stream_printf (stream->output, ">"); + stream->column++; } else if (isspace (*data)) { newline = (*data == '\n' || *data == '\r'); if (! newline && stream->column >= stream->max_column) { @@ -175,8 +185,9 @@ _word_wrap_stream_write (cairo_output_stream_t *base, _cairo_output_stream_write (stream->output, data, 1); data++; length--; - if (newline) + if (newline) { stream->column = 0; + } else stream->column++; stream->last_write_was_space = TRUE; @@ -189,17 +200,21 @@ _word_wrap_stream_write (cairo_output_stream_t *base, } /* Don't wrap if this word is a continuation of a non hex * string word from a previous call to write. */ - if (stream->column + word >= stream->max_column && - (stream->last_write_was_space || stream->in_hexstring)) - { - _cairo_output_stream_printf (stream->output, "\n"); - stream->column = 0; + if (stream->column + word >= stream->max_column) { + if (stream->last_write_was_space || + (stream->in_hexstring && !stream->empty_hexstring)) + { + _cairo_output_stream_printf (stream->output, "\n"); + stream->column = 0; + } } _cairo_output_stream_write (stream->output, data, word); data += word; length -= word; stream->column += word; stream->last_write_was_space = FALSE; + if (stream->in_hexstring) + stream->empty_hexstring = FALSE; } } @@ -236,6 +251,7 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) stream->column = 0; stream->last_write_was_space = FALSE; stream->in_hexstring = FALSE; + stream->empty_hexstring = TRUE; return &stream->base; } @@ -259,7 +275,7 @@ _cairo_pdf_path_move_to (void *closure, cairo_point_t *point) info->has_sub_path = FALSE; cairo_matrix_transform_point (info->path_transform, &x, &y); _cairo_output_stream_printf (info->output, - "%f %f m ", x, y); + "%g %g m ", x, y); return _cairo_output_stream_get_status (info->output); } @@ -282,7 +298,7 @@ _cairo_pdf_path_line_to (void *closure, cairo_point_t *point) info->has_sub_path = TRUE; cairo_matrix_transform_point (info->path_transform, &x, &y); _cairo_output_stream_printf (info->output, - "%f %f l ", x, y); + "%g %g l ", x, y); return _cairo_output_stream_get_status (info->output); } @@ -306,7 +322,7 @@ _cairo_pdf_path_curve_to (void *closure, cairo_matrix_transform_point (info->path_transform, &cx, &cy); cairo_matrix_transform_point (info->path_transform, &dx, &dy); _cairo_output_stream_printf (info->output, - "%f %f %f %f %f %f c ", + "%g %g %g %g %g %g c ", bx, by, cx, cy, dx, dy); return _cairo_output_stream_get_status (info->output); } @@ -339,7 +355,7 @@ _cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box) cairo_matrix_transform_point (info->path_transform, &x1, &y1); cairo_matrix_transform_point (info->path_transform, &x2, &y2); _cairo_output_stream_printf (info->output, - "%f %f %f %f re ", + "%g %g %g %g re ", x1, y1, x2 - x1, y2 - y1); return _cairo_output_stream_get_status (info->output); @@ -355,7 +371,7 @@ _cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box) * the stroke workaround will not modify the path being emitted. */ static cairo_status_t -_cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, +_cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, cairo_path_fixed_t *path, cairo_matrix_t *path_transform, cairo_line_cap_t line_cap) @@ -365,10 +381,10 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, pdf_path_info_t info; cairo_box_t box; - word_wrap = _word_wrap_stream_create (pdf_operators->stream, 79); + word_wrap = _word_wrap_stream_create (pdf_operators->stream, 72); status = _cairo_output_stream_get_status (word_wrap); if (status) - return status; + return _cairo_output_stream_destroy (word_wrap); info.output = word_wrap; info.path_transform = path_transform; @@ -464,7 +480,8 @@ _cairo_pdf_line_join (cairo_line_join_t join) static cairo_int_status_t _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, - cairo_stroke_style_t *style) + cairo_stroke_style_t *style, + double scale) { double *dash = style->dash; int num_dashes = style->num_dashes; @@ -535,7 +552,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, _cairo_output_stream_printf (pdf_operators->stream, "%f w\n", - style->line_width); + style->line_width * scale); _cairo_output_stream_printf (pdf_operators->stream, "%d J\n", @@ -550,9 +567,9 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, _cairo_output_stream_printf (pdf_operators->stream, "["); for (d = 0; d < num_dashes; d++) - _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d]); + _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale); _cairo_output_stream_printf (pdf_operators->stream, "] %f d\n", - dash_offset); + dash_offset * scale); } else { _cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n"); } @@ -566,6 +583,116 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, return _cairo_output_stream_get_status (pdf_operators->stream); } +/* Scale the matrix so the largest absolute value of the non + * translation components is 1.0. Return the scale required to restore + * the matrix to the original values. + * + * eg the matrix [ 100 0 0 50 20 10 ] + * + * is rescaled to [ 1 0 0 0.5 0.2 0.1 ] + * and the scale returned is 100 + */ +static void +_cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale) +{ + double s; + + s = fabs (m->xx); + if (fabs (m->xy) > s) + s = fabs (m->xy); + if (fabs (m->yx) > s) + s = fabs (m->yx); + if (fabs (m->yy) > s) + s = fabs (m->yy); + *scale = s; + s = 1.0/s; + cairo_matrix_scale (m, s, s); +} + +static cairo_int_status_t +_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + const char *pdf_operator) +{ + cairo_status_t status; + cairo_matrix_t m, path_transform; + cairo_bool_t has_ctm = TRUE; + double scale = 1.0; + + /* Optimize away the stroke ctm when it does not affect the + * stroke. There are other ctm cases that could be optimized + * however this is the most common. + */ + if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 && + fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0) + { + has_ctm = FALSE; + } + + /* The PDF CTM is transformed to the user space CTM when stroking + * so the corect pen shape will be used. This also requires that + * the path be transformed to user space when emitted. The + * conversion of path coordinates to user space may cause rounding + * errors. For example the device space point (1.234, 3.142) when + * transformed to a user space CTM of [100 0 0 100 0 0] will be + * emitted as (0.012, 0.031). + * + * To avoid the rounding problem we scale the user space CTM + * matrix so that all the non translation components of the matrix + * are <= 1. The line width and and dashes are scaled by the + * inverse of the scale applied to the CTM. This maintains the + * shape of the stroke pen while keeping the user space CTM within + * the range that maximizes the precision of the emitted path. + */ + if (has_ctm) { + m = *ctm; + /* Zero out the translation since it does not affect the pen + * shape however it may cause unnecessary digits to be emitted. + */ + m.x0 = 0.0; + m.y0 = 0.0; + _cairo_matrix_factor_out_scale (&m, &scale); + path_transform = m; + status = cairo_matrix_invert (&path_transform); + if (status) + return status; + + cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf); + } + + status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + if (status) + return status; + + if (has_ctm) { + _cairo_output_stream_printf (pdf_operators->stream, + "q %f %f %f %f %f %f cm\n", + m.xx, m.yx, m.xy, m.yy, + m.x0, m.y0); + } else { + path_transform = pdf_operators->cairo_to_pdf; + } + + status = _cairo_pdf_operators_emit_path (pdf_operators, + path, + &path_transform, + style->line_cap); + if (status) + return status; + + _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator); + if (has_ctm) + _cairo_output_stream_printf (pdf_operators->stream, " Q"); + + _cairo_output_stream_printf (pdf_operators->stream, "\n"); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} cairo_int_status_t _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, @@ -574,31 +701,12 @@ _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse) { - cairo_status_t status; - cairo_matrix_t m; - - status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - if (status) - return status; - - cairo_matrix_multiply (&m, ctm, &pdf_operators->cairo_to_pdf); - _cairo_output_stream_printf (pdf_operators->stream, - "q %f %f %f %f %f %f cm\n", - m.xx, m.yx, m.xy, m.yy, - m.x0, m.y0); - - status = _cairo_pdf_operators_emit_path (pdf_operators, + return _cairo_pdf_operators_emit_stroke (pdf_operators, path, + style, + ctm, ctm_inverse, - style->line_cap); - if (status) - return status; - - _cairo_output_stream_printf (pdf_operators->stream, "S Q\n"); - - return _cairo_output_stream_get_status (pdf_operators->stream); + "S"); } cairo_int_status_t @@ -642,45 +750,25 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse) { - const char *pdf_operator; - cairo_status_t status; - cairo_matrix_t m; - - status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - if (status) - return status; - - cairo_matrix_multiply (&m, ctm, &pdf_operators->cairo_to_pdf); - _cairo_output_stream_printf (pdf_operators->stream, - "q %f %f %f %f %f %f cm\n", - m.xx, m.yx, m.xy, m.yy, - m.x0, m.y0); - - status = _cairo_pdf_operators_emit_path (pdf_operators, - path, - ctm_inverse, - style->line_cap); - if (status) - return status; + const char *operator; switch (fill_rule) { case CAIRO_FILL_RULE_WINDING: - pdf_operator = "B"; + operator = "B"; break; case CAIRO_FILL_RULE_EVEN_ODD: - pdf_operator = "B*"; + operator = "B*"; break; default: ASSERT_NOT_REACHED; } - _cairo_output_stream_printf (pdf_operators->stream, - "%s Q\n", - pdf_operator); - - return _cairo_output_stream_get_status (pdf_operators->stream); + return _cairo_pdf_operators_emit_stroke (pdf_operators, + path, + style, + ctm, + ctm_inverse, + operator); } #define GLYPH_POSITION_TOLERANCE 0.001 @@ -703,10 +791,10 @@ _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators, for (i = 0; i < num_glyphs; i++) cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y); - word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 79); + word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72); status = _cairo_output_stream_get_status (word_wrap_stream); if (status) - return status; + return _cairo_output_stream_destroy (word_wrap_stream); _cairo_output_stream_printf (word_wrap_stream, "BT\n"); @@ -799,10 +887,28 @@ _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators, } else { if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) { double delta = glyphs[i].x - Tm_x; + int rounded_delta; - _cairo_output_stream_printf (word_wrap_stream, - "> %f <", - -1000.0*delta/scaled_font->scale.xx); + delta = -1000.0*delta/scaled_font->scale.xx; + /* As the delta is in 1/1000 of a unit of text + * space, rounding to an integer should still + * provide sufficient precision. We round the + * delta before adding to Tm_x so that we keep + * track of the accumulated rounding error in + * the PDF interpreter and compensate for it + * when calculating subsequent deltas. + */ + rounded_delta = _cairo_lround (delta); + if (rounded_delta != 0) { + _cairo_output_stream_printf (word_wrap_stream, + "> %d <", + rounded_delta); + } + + /* Convert the rounded delta back to cairo + * space before adding to the current text + * position. */ + delta = rounded_delta*scaled_font->scale.xx/-1000.0; Tm_x += delta; } _cairo_output_stream_printf (word_wrap_stream, @@ -817,10 +923,16 @@ _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators, if (in_TJ) { if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) { double delta = glyphs[i].x - Tm_x; + int rounded_delta; - _cairo_output_stream_printf (word_wrap_stream, - "> %f <", - -1000.0*delta/scaled_font->scale.xx); + delta = -1000.0*delta/scaled_font->scale.xx; + rounded_delta = _cairo_lround (delta); + if (rounded_delta != 0) { + _cairo_output_stream_printf (word_wrap_stream, + "> %d <", + rounded_delta); + } + delta = rounded_delta*scaled_font->scale.xx/-1000.0; Tm_x += delta; } _cairo_output_stream_printf (word_wrap_stream, diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface.c b/gfx/cairo/cairo/src/cairo-pdf-surface.c index e6e962634c3..ce6d8c4a6a3 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-surface.c +++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c @@ -393,10 +393,15 @@ _extract_pdf_surface (cairo_surface_t *surface, { cairo_surface_t *target; + if (surface->status) + return surface->status; + if (! _cairo_surface_is_paginated (surface)) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); target = _cairo_paginated_surface_get_target (surface); + if (target->status) + return target->status; if (! _cairo_surface_is_pdf (target)) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); @@ -1245,7 +1250,6 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, int i, x, y; cairo_bool_t opaque; uint8_t a; - int src_bit, dst_bit; /* This is the only image format we support, which simplifies things. */ assert (image->format == CAIRO_FORMAT_ARGB32 || @@ -1255,11 +1259,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, stream_ret->id = 0; if (image->format == CAIRO_FORMAT_A1) { - /* We allocate using slightly different math so that we can get - * the overflow checking from _cairo_malloc_ab, but alpha_size - * needs to be the correct size for emitting the data in the PDF. - */ - alpha_size = (image->width*image->height + 7) / 8; + alpha_size = (image->width + 7) / 8 * image->height; alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height); } else { alpha_size = image->height * image->width; @@ -1273,8 +1273,6 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, opaque = TRUE; i = 0; - src_bit = 0; - dst_bit = 7; for (y = 0; y < image->height; y++) { if (image->format == CAIRO_FORMAT_ARGB32) { pixel32 = (uint32_t *) (image->data + y * image->stride); @@ -1297,21 +1295,12 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, } else { /* image->format == CAIRO_FORMAT_A1 */ pixel8 = (uint8_t *) (image->data + y * image->stride); - for (x = 0; x < image->width; x++, pixel8++) { - if (dst_bit == 7) - alpha[i] = 0; - if ((*pixel8 >> src_bit) & 1) { - opaque = FALSE; - alpha[i] |= (1 << dst_bit); - } - if (++src_bit > 7) { - src_bit = 0; - pixel8++; - } - if (--dst_bit < 0) { - dst_bit = 7; - i++; - } + for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) { + a = *pixel8; + a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a); + alpha[i++] = a; + if (a != 0xff) + opaque = FALSE; } } } @@ -1494,8 +1483,9 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, double old_width, old_height; cairo_matrix_t old_cairo_to_pdf; cairo_paginated_mode_t old_paginated_mode; + cairo_clip_t *old_clip; cairo_rectangle_int_t meta_extents; - cairo_status_t status; + cairo_status_t status, status2; int alpha = 0; status = _cairo_surface_get_extents (meta_surface, &meta_extents); @@ -1506,6 +1496,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, old_height = surface->height; old_cairo_to_pdf = surface->cairo_to_pdf; old_paginated_mode = surface->paginated_mode; + old_clip = _cairo_surface_get_clip (&surface->base); surface->width = meta_extents.width; surface->height = meta_extents.height; /* Patterns are emitted after fallback images. The paginated mode @@ -1548,6 +1539,10 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, surface->height = old_height; surface->paginated_mode = old_paginated_mode; surface->cairo_to_pdf = old_cairo_to_pdf; + status2 = _cairo_surface_set_clip (&surface->base, old_clip); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, &surface->cairo_to_pdf); @@ -1981,7 +1976,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, stops[i].color[3] = pattern->stops[i].color.alpha; if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3])) emit_alpha = TRUE; - stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x); + stops[i].offset = pattern->stops[i].offset; } if (pattern->base.extend == CAIRO_EXTEND_REPEAT || @@ -2220,8 +2215,8 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); - first_stop = _cairo_fixed_to_double (gradient->stops[0].x); - last_stop = _cairo_fixed_to_double (gradient->stops[gradient->n_stops - 1].x); + first_stop = gradient->stops[0].offset; + last_stop = gradient->stops[gradient->n_stops - 1].offset; if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT || pattern->base.base.extend == CAIRO_EXTEND_REFLECT) { @@ -4148,9 +4143,10 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, if (! _pattern_supported (pattern)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_SOURCE) { + if (op == CAIRO_OPERATOR_OVER) { if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + if ( _cairo_surface_is_meta (surface_pattern->surface)) return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; } @@ -4165,8 +4161,13 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface, - surface_pattern); + if (_cairo_surface_is_meta (surface_pattern->surface)) { + if (_cairo_pattern_is_opaque (pattern)) + return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN; + } else { + return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface, + surface_pattern); + } } if (_cairo_pattern_is_opaque (pattern)) @@ -4536,19 +4537,14 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return CAIRO_INT_STATUS_UNSUPPORTED; - /* Fill-stroke with patterns requiring an SMask are not currently - * implemented. Non opaque stroke patterns are not supported - * because the PDF fill-stroke operator does not blend a - * transparent stroke with the fill. + /* PDF rendering of fill-stroke is not the same as cairo when + * either the fill or stroke is not opaque. */ - if (fill_source->type == CAIRO_PATTERN_TYPE_LINEAR || - fill_source->type == CAIRO_PATTERN_TYPE_RADIAL) + if ( !_cairo_pattern_is_opaque (fill_source) || + !_cairo_pattern_is_opaque (stroke_source)) { - if (!_cairo_pattern_is_opaque (fill_source)) - return CAIRO_INT_STATUS_UNSUPPORTED; - } - if (!_cairo_pattern_is_opaque (stroke_source)) return CAIRO_INT_STATUS_UNSUPPORTED; + } fill_pattern_res.id = 0; gstate_res.id = 0; diff --git a/gfx/cairo/cairo/src/cairo-png.c b/gfx/cairo/cairo/src/cairo-png.c index 6b2ab858965..f87ba2ce245 100644 --- a/gfx/cairo/cairo/src/cairo-png.c +++ b/gfx/cairo/cairo/src/cairo-png.c @@ -211,9 +211,8 @@ write_png (cairo_surface_t *surface, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - white.red = 0xff; - white.blue = 0xff; - white.green = 0xff; + white.gray = (1 << depth) - 1; + white.red = white.blue = white.green = white.gray; png_set_bKGD (png, info, &white); png_convert_from_time_t (&pt, time (NULL)); diff --git a/gfx/cairo/cairo/src/cairo-ps-surface.c b/gfx/cairo/cairo/src/cairo-ps-surface.c index f5838ab62b9..e78e24738e1 100644 --- a/gfx/cairo/cairo/src/cairo-ps-surface.c +++ b/gfx/cairo/cairo/src/cairo-ps-surface.c @@ -180,11 +180,12 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface) " {\n" " dup\n" " type /stringtype eq\n" - " { show } { -0.0001 mul 0 rmoveto } ifelse\n" + " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n" " } forall\n" "} bind def\n" "/Td { moveto } bind def\n" - "/Tm { 6 array astore cairo_font exch selectfont 0 0 moveto } bind def\n" + "/Tm { 6 array astore dup /cairo_font_matrix exch def\n" + " cairo_font exch selectfont 0 0 moveto } bind def\n" "/g { setgray } bind def\n" "/rg { setrgbcolor } bind def\n"); @@ -858,10 +859,15 @@ _extract_ps_surface (cairo_surface_t *surface, { cairo_surface_t *target; + if (surface->status) + return surface->status; + if (! _cairo_surface_is_paginated (surface)) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); target = _cairo_paginated_surface_get_target (surface); + if (target->status) + return target->status; if (! _cairo_surface_is_ps (target)) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); @@ -2029,6 +2035,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, double old_width, old_height; cairo_matrix_t old_cairo_to_ps; cairo_content_t old_content; + cairo_clip_t *old_clip; cairo_rectangle_int_t meta_extents; cairo_status_t status; @@ -2040,6 +2047,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, old_width = surface->width; old_height = surface->height; old_cairo_to_ps = surface->cairo_to_ps; + old_clip = _cairo_surface_get_clip (&surface->base); surface->width = meta_extents.width; surface->height = meta_extents.height; cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height); @@ -2071,6 +2079,10 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, surface->width = old_width; surface->height = old_height; surface->cairo_to_ps = old_cairo_to_ps; + status = _cairo_surface_set_clip (&surface->base, old_clip); + if (status) + return status; + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, &surface->cairo_to_ps); @@ -2135,17 +2147,23 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, cairo_rectangle_int_t pattern_extents; status = _cairo_surface_get_extents (meta_surface, &pattern_extents); + if (status) + return status; + *width = pattern_extents.width; *height = pattern_extents.height; } else { status = _cairo_surface_acquire_source_image (pattern->surface, &surface->image, &surface->image_extra); + if (status) + return status; + *width = surface->image->width; *height = surface->image->height; } - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -2206,6 +2224,14 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, (int)(height/scale), scale*72, (long)width*height*3); + } else { + if (op == CAIRO_OPERATOR_SOURCE) { + _cairo_output_stream_printf (surface->stream, + "%d g 0 0 %f %f rectfill\n", + surface->content == CAIRO_CONTENT_COLOR ? 0 : 1, + surface->width, + surface->height); + } } status = cairo_matrix_invert (&cairo_p2d); @@ -2312,6 +2338,12 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, old_use_string_datasource = surface->use_string_datasource; surface->use_string_datasource = TRUE; + if (op == CAIRO_OPERATOR_SOURCE) { + _cairo_output_stream_printf (surface->stream, + "%d g 0 0 %f %f rectfill\n", + surface->content == CAIRO_CONTENT_COLOR ? 0 : 1, + xstep, ystep); + } status = _cairo_ps_surface_emit_surface (surface, pattern, op); if (status) return status; @@ -2343,10 +2375,17 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, pattern_height*2, pattern_width*2); } else { + if (op == CAIRO_OPERATOR_SOURCE) { + _cairo_output_stream_printf (surface->stream, + " /BBox [0 0 %f %f]\n", + xstep, ystep); + } else { + _cairo_output_stream_printf (surface->stream, + " /BBox [0 0 %d %d]\n", + pattern_width, pattern_height); + } _cairo_output_stream_printf (surface->stream, - " /BBox [0 0 %d %d]\n" - " /PaintProc { CairoPattern }\n", - pattern_width, pattern_height); + " /PaintProc { CairoPattern }\n"); } _cairo_output_stream_printf (surface->stream, @@ -2466,7 +2505,7 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface, stops[i].color[1] = stop->color.green; stops[i].color[2] = stop->color.blue; stops[i].color[3] = stop->color.alpha; - stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x); + stops[i].offset = pattern->stops[i].offset; } if (pattern->base.extend == CAIRO_EXTEND_REPEAT || @@ -2585,8 +2624,8 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface, assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps); - first_stop = _cairo_fixed_to_double (gradient->stops[0].x); - last_stop = _cairo_fixed_to_double (gradient->stops[gradient->n_stops - 1].x); + first_stop = gradient->stops[0].offset; + last_stop = gradient->stops[gradient->n_stops - 1].offset; if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT || pattern->base.base.extend == CAIRO_EXTEND_REFLECT) { @@ -2861,7 +2900,7 @@ _cairo_ps_surface_paint (void *abstract_surface, { cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; - cairo_rectangle_int_t extents, surface_extents; + cairo_rectangle_int_t extents; cairo_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -2874,22 +2913,15 @@ _cairo_ps_surface_paint (void *abstract_surface, "%% _cairo_ps_surface_paint\n"); #endif - status = _cairo_surface_get_extents (&surface->base, &surface_extents); + status = _cairo_surface_get_extents (&surface->base, &extents); if (status) return status; - status = _cairo_pattern_get_extents (source, &extents); - if (status) - return status; - - _cairo_rectangle_intersect (&extents, &surface_extents); - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - source->extend == CAIRO_EXTEND_NONE) + (source->extend == CAIRO_EXTEND_NONE || + source->extend == CAIRO_EXTEND_PAD)) { - _cairo_output_stream_printf (stream, "q %d %d %d %d rectclip\n", - extents.x, - surface_extents.height - extents.y - extents.height, + _cairo_output_stream_printf (stream, "q 0 0 %d %d rectclip\n", extents.width, extents.height); @@ -2908,9 +2940,7 @@ _cairo_ps_surface_paint (void *abstract_surface, if (status) return status; - _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n", - extents.x, - surface_extents.height - extents.y - extents.height, + _cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n", extents.width, extents.height); } @@ -2976,7 +3006,8 @@ _cairo_ps_surface_fill (void *abstract_surface, #endif if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - source->extend == CAIRO_EXTEND_NONE) + (source->extend == CAIRO_EXTEND_NONE || + source->extend == CAIRO_EXTEND_PAD)) { _cairo_output_stream_printf (surface->stream, "q\n"); diff --git a/gfx/cairo/cairo/src/cairo-quartz-font.c b/gfx/cairo/cairo/src/cairo-quartz-font.c new file mode 100644 index 00000000000..2918ea7b369 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-quartz-font.c @@ -0,0 +1,794 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright � 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include + +#include "cairo-quartz.h" +#include "cairo-quartz-private.h" + +/* 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; + +/* Not public in the least bit */ +static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = 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; + +static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE; +static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE; + +static void +quartz_font_ensure_symbols(void) +{ + if (_cairo_quartz_font_symbol_lookup_done) + return; + + /* 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"); + 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"); + + if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) && + CGFontGetGlyphBBoxesPtr && + CGFontGetGlyphsForUnicharsPtr && + CGFontGetUnitsPerEmPtr && + CGFontGetGlyphAdvancesPtr && + CGFontGetGlyphPathPtr && + (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr))) + _cairo_quartz_font_symbols_present = TRUE; + + _cairo_quartz_font_symbol_lookup_done = TRUE; +} + +typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t; +typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t; + +struct _cairo_quartz_scaled_font { + cairo_scaled_font_t base; +}; + +struct _cairo_quartz_font_face { + cairo_font_face_t base; + + CGFontRef cgFont; +}; + +/** + ** font face backend + **/ + +static void +_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); +} + +static cairo_status_t +_cairo_quartz_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) +{ + cairo_quartz_font_face_t *font_face = abstract_face; + cairo_quartz_scaled_font_t *font = NULL; + cairo_status_t status; + cairo_font_extents_t fs_metrics; + double ems; + CGRect bbox; + + quartz_font_ensure_symbols(); + if (!_cairo_quartz_font_symbols_present) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + font = malloc(sizeof(cairo_quartz_scaled_font_t)); + if (font == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memset (font, 0, sizeof(cairo_quartz_scaled_font_t)); + + status = _cairo_scaled_font_init (&font->base, + &font_face->base, font_matrix, ctm, options, + &cairo_quartz_scaled_font_backend); + if (status) + goto FINISH; + + ems = CGFontGetUnitsPerEmPtr (font_face->cgFont); + + /* 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); + + 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; + } + } + + status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics); + +FINISH: + if (status != CAIRO_STATUS_SUCCESS) { + free (font); + } else { + *font_out = (cairo_scaled_font_t*) font; + } + + return status; +} + +static const cairo_font_face_backend_t _cairo_quartz_font_face_backend = { + CAIRO_FONT_TYPE_QUARTZ, + _cairo_quartz_font_face_destroy, + _cairo_quartz_font_face_scaled_font_create +}; + +/** + * cairo_quartz_font_face_create_for_cgfont + * @font: a #CGFontRef obtained through a method external to cairo. + * + * Creates a new font for the Quartz font backend based on a + * #CGFontRef. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.6 + */ +cairo_font_face_t * +cairo_quartz_font_face_create_for_cgfont (CGFontRef font) +{ + cairo_quartz_font_face_t *font_face; + + quartz_font_ensure_symbols(); + + font_face = malloc (sizeof (cairo_quartz_font_face_t)); + if (!font_face) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + font_face->cgFont = CGFontRetain (font); + + _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend); + + return &font_face->base; +} + +/** + ** scaled font backend + **/ + +static cairo_quartz_font_face_t * +_cairo_quartz_scaled_to_face (void *abstract_font) +{ + cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font; + cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (&sfont->base); + if (!font_face || font_face->backend->type != CAIRO_FONT_TYPE_QUARTZ) + return NULL; + + return (cairo_quartz_font_face_t*) font_face; +} + +static cairo_status_t +_cairo_quartz_font_create_toy(cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) +{ + const char *family = toy_face->family; + char *full_name = malloc(strlen(family) + 64); // give us a bit of room to tack on Bold, Oblique, etc. + CFStringRef cgFontName = NULL; + CGFontRef cgFont = NULL; + int loop; + + cairo_status_t status; + cairo_font_face_t *face; + cairo_scaled_font_t *scaled_font; + + quartz_font_ensure_symbols(); + if (!_cairo_quartz_font_symbols_present) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* handle CSS-ish faces */ + if (!strcmp(family, "serif") || !strcmp(family, "Times Roman")) + family = "Times"; + else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans")) + family = "Helvetica"; + else if (!strcmp(family, "cursive")) + family = "Apple Chancery"; + else if (!strcmp(family, "fantasy")) + family = "Papyrus"; + else if (!strcmp(family, "monospace") || !strcmp(family, "mono")) + family = "Courier"; + + /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first, + * then drop the bold, then drop the slant, then drop both.. finally + * just use "Helvetica". And if Helvetica doesn't exist, give up. + */ + for (loop = 0; loop < 5; loop++) { + if (loop == 4) + family = "Helvetica"; + + strcpy (full_name, family); + + if (loop < 3 && (loop & 1) == 0) { + if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD) + strcat (full_name, " Bold"); + } + + if (loop < 3 && (loop & 2) == 0) { + if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC) + strcat (full_name, " Italic"); + else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE) + strcat (full_name, " Oblique"); + } + + if (CGFontCreateWithFontNamePtr) { + cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII); + cgFont = CGFontCreateWithFontNamePtr (cgFontName); + CFRelease (cgFontName); + } else { + cgFont = CGFontCreateWithNamePtr (full_name); + } + + if (cgFont) + break; + } + + if (!cgFont) { + /* Give up */ + return CAIRO_STATUS_NO_MEMORY; + } + + face = cairo_quartz_font_face_create_for_cgfont (cgFont); + if (face->status) + return face->status; + + status = _cairo_quartz_font_face_scaled_font_create (face, + font_matrix, ctm, + options, + &scaled_font); + cairo_font_face_destroy (face); + if (status) + return status; + + *font_out = scaled_font; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_quartz_font_fini(void *abstract_font) +{ +} + +#define INVALID_GLYPH 0x00 + +static inline CGGlyph +_cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) { + unsigned long index = _cairo_scaled_glyph_index (scaled_glyph); + if (index > 0xffff) + return INVALID_GLYPH; + return (CGGlyph) index; +} + +static inline cairo_status_t +_cairo_matrix_to_unit_quartz_matrix (const cairo_matrix_t *m, CGAffineTransform *txout, + double *xout, double *yout) +{ + CGAffineTransform transform; + double xscale, yscale; + cairo_status_t status; + + status = _cairo_matrix_compute_scale_factors (m, &xscale, &yscale, 1); + if (status) + return status; + + transform = CGAffineTransformMake (m->xx, - m->yx, + - m->xy, m->yy, + 0.0f, 0.0f); + if (xout) + *xout = xscale; + if (yout) + *yout = yscale; + + if (xscale) + xscale = 1.0 / xscale; + if (yscale) + yscale = 1.0 / yscale; + + *txout = CGAffineTransformScale (transform, xscale, yscale); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_quartz_init_glyph_metrics (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_text_extents_t extents = {0, 0, 0, 0, 0, 0}; + CGAffineTransform textMatrix; + CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); + int advance; + CGRect bbox; + double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); + double xscale, yscale; + double xmin, ymin, xmax, ymax; + + if (glyph == INVALID_GLYPH) + goto FAIL; + + if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || + !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) + goto FAIL; + + status = _cairo_matrix_compute_scale_factors (&font->base.scale, + &xscale, &yscale, 1); + if (status) + goto FAIL; + + 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); +#endif + + xmin = CGRectGetMinX(bbox); + ymin = CGRectGetMinY(bbox); + xmax = CGRectGetMaxX(bbox); + ymax = CGRectGetMaxY(bbox); + + extents.x_bearing = xmin; + extents.y_bearing = - ymax; + extents.width = xmax - xmin; + extents.height = ymax - ymin; + + 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); +#endif + + FAIL: + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &font->base, + &extents); + + return status; +} + +static void +_cairo_quartz_path_apply_func (void *info, const CGPathElement *el) +{ + cairo_path_fixed_t *path = (cairo_path_fixed_t *) info; + + switch (el->type) { + case kCGPathElementMoveToPoint: + _cairo_path_fixed_move_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y)); + break; + case kCGPathElementAddLineToPoint: + _cairo_path_fixed_line_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y)); + break; + case kCGPathElementAddQuadCurveToPoint: { + cairo_fixed_t fx, fy; + double x, y; + if (!_cairo_path_fixed_get_current_point (path, &fx, &fy)) + fx = fy = 0; + x = _cairo_fixed_to_double (fx); + y = _cairo_fixed_to_double (fy); + + _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0), + _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0), + _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0), + _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0), + _cairo_fixed_from_double(el->points[1].x), + _cairo_fixed_from_double(el->points[1].y)); + } + break; + case kCGPathElementAddCurveToPoint: + _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y), + _cairo_fixed_from_double(el->points[1].x), + _cairo_fixed_from_double(el->points[1].y), + _cairo_fixed_from_double(el->points[2].x), + _cairo_fixed_from_double(el->points[2].y)); + break; + case kCGPathElementCloseSubpath: + _cairo_path_fixed_close_path (path); + break; + } +} + +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; + cairo_path_fixed_t *path; + + if (glyph == INVALID_GLYPH) { + _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create()); + return CAIRO_STATUS_SUCCESS; + } + + textMatrix = CGAffineTransformMake (font->base.scale.xx, + -font->base.scale.yx, + -font->base.scale.xy, + font->base.scale.yy, + font->base.scale.x0, + font->base.scale.y0); + + textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0)); + + glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph); + if (!glyphPath) + return CAIRO_INT_STATUS_UNSUPPORTED; + + path = _cairo_path_fixed_create (); + if (!path) { + CGPathRelease (glyphPath); + return _cairo_error(CAIRO_STATUS_NO_MEMORY); + } + + CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func); + + CGPathRelease (glyphPath); + + _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_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; + double width, height; + double xscale, yscale; + double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); + + CGColorSpaceRef gray; + CGContextRef cgContext = NULL; + CGAffineTransform textMatrix; + CGRect glyphRect, glyphRectInt; + CGPoint glyphOrigin; + + //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface); + + /* 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. + */ + if (glyph == INVALID_GLYPH) { + surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); + status = cairo_surface_status ((cairo_surface_t *) surface); + if (status) + return status; + + _cairo_scaled_glyph_set_surface (scaled_glyph, + &font->base, + surface); + return CAIRO_STATUS_SUCCESS; + } + + if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || + !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_matrix_compute_scale_factors (&font->base.scale, + &xscale, &yscale, 1); + if (status) + return status; + + textMatrix = CGAffineTransformMake (font->base.scale.xx, + -font->base.scale.yx, + -font->base.scale.xy, + font->base.scale.yy, + 0.0f, 0.0f); + glyphRect = CGRectMake (bbox.origin.x / emscale, + bbox.origin.y / emscale, + bbox.size.width / emscale, + bbox.size.height / emscale); + + glyphRect = CGRectApplyAffineTransform (glyphRect, 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 + 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", + glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height); +#endif + + 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; + + gray = CGColorSpaceCreateDeviceGray (); + cgContext = CGBitmapContextCreate (surface->data, + surface->width, + surface->height, + 8, + surface->stride, + gray, + kCGImageAlphaNone); + CGColorSpaceRelease (gray); + + CGContextSetFont (cgContext, font_face->cgFont); + CGContextSetFontSize (cgContext, 1.0); + CGContextSetTextMatrix (cgContext, textMatrix); + + CGContextClearRect (cgContext, CGRectMake (0.0f, 0.0f, width, height)); + + if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE) + CGContextSetShouldAntialias (cgContext, false); + + CGContextSetRGBFillColor (cgContext, 1.0, 1.0, 1.0, 1.0); + CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); + + CGContextRelease (cgContext); + + cairo_surface_set_device_offset (&surface->base, + - glyphOrigin.x, + height + glyphOrigin.y); + + _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); + + return status; +} + +static cairo_int_status_t +_cairo_quartz_font_scaled_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info) +{ + cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS)) + status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph); + + 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); + + return status; +} + +static unsigned long +_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); + UniChar u = (UniChar) ucs4; + CGGlyph glyph; + + CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1); + + return glyph; +} + +const cairo_scaled_font_backend_t cairo_quartz_scaled_font_backend = { + CAIRO_FONT_TYPE_QUARTZ, + _cairo_quartz_font_create_toy, + _cairo_quartz_font_fini, + _cairo_quartz_font_scaled_glyph_init, + NULL, /* text_to_glyphs */ + _cairo_quartz_ucs4_to_index, + NULL, /* show_glyphs */ + NULL, /* load_truetype_table */ + NULL, /* map_glyphs_to_unicode */ +}; + +/* + * private methods that the quartz surface uses + */ + +CGFontRef +_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font) +{ + cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font); + + return ffont->cgFont; +} + + +/* + * compat with old ATSUI backend + */ + +/** + * cairo_quartz_font_face_create_for_atsu_font_id + * @font_id: an ATSUFontID for the font. + * + * Creates a new font for the Quartz font backend based on an + * #ATSUFontID. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.6 + **/ +cairo_font_face_t * +cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id) +{ + ATSFontRef atsFont = FMGetATSFontRefFromFont (font_id); + CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont); + + return cairo_quartz_font_face_create_for_cgfont (cgFont); +} + +/* This is the old name for the above function, exported for compat purposes */ +cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id); + +cairo_font_face_t * +cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id) +{ + return cairo_quartz_font_face_create_for_atsu_font_id (font_id); +} diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h index 41732fbb531..07d5a8e3a88 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h @@ -92,17 +92,14 @@ _cairo_quartz_create_cgimage (cairo_format_t format, CGDataProviderReleaseDataCallback releaseCallback, void *releaseInfo); +CGFontRef +_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont); + #endif /* CAIRO_HAS_QUARTZ_SURFACE */ -#if CAIRO_HAS_ATSUI_FONT -ATSUStyle -_cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont); - -ATSUFontID -_cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont); - +#if CAIRO_HAS_CGFONT_FONT CGFontRef -_cairo_atsui_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont); -#endif /* CAIRO_HAS_ATSUI_FONT */ +_cairo_cgfont_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont); +#endif /* CAIRO_HAS_CGFONT_FONT */ #endif /* CAIRO_QUARTZ_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c index bdbb5d3f09a..7d90fba443f 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -48,7 +48,6 @@ #define FloatToFixed(a) ((Fixed)((float)(a) * fixed1)) #endif -#include #include #undef QUARTZ_DEBUG @@ -102,13 +101,14 @@ CG_EXTERN void CGContextReplacePathWithStrokedPath (CGContextRef); CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef); #endif -/* Only present in 10.4+ */ +/* Some of these are present in earlier versions of the OS than where + * they are public; others are not public at all (CGContextCopyPath, + * CGContextReplacePathWithClipPath, many of the getters, etc.) + */ static void (*CGContextClipToMaskPtr) (CGContextRef, CGRect, CGImageRef) = NULL; -/* Only present in 10.5+ */ static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL; static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL; static void (*CGContextSetShouldAntialiasFontsPtr) (CGContextRef, bool) = NULL; -static void (*CGContextSetShouldSmoothFontsPtr) (CGContextRef, bool) = NULL; static bool (*CGContextGetShouldAntialiasFontsPtr) (CGContextRef) = NULL; static bool (*CGContextGetShouldSmoothFontsPtr) (CGContextRef) = NULL; static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL; @@ -116,6 +116,8 @@ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL; static void (*CGContextReplacePathWithClipPathPtr) (CGContextRef) = NULL; +static SInt32 _cairo_quartz_osx_version = 0x0; + static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE; /* @@ -143,7 +145,6 @@ static void quartz_ensure_symbols(void) CGContextDrawTiledImagePtr = dlsym(RTLD_DEFAULT, "CGContextDrawTiledImage"); CGContextGetTypePtr = dlsym(RTLD_DEFAULT, "CGContextGetType"); CGContextSetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldAntialiasFonts"); - CGContextSetShouldSmoothFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldSmoothFonts"); CGContextGetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextGetShouldAntialiasFonts"); CGContextGetShouldSmoothFontsPtr = dlsym(RTLD_DEFAULT, "CGContextGetShouldSmoothFonts"); CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath"); @@ -151,6 +152,11 @@ static void quartz_ensure_symbols(void) CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing"); CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing"); + if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) { + // assume 10.4 + _cairo_quartz_osx_version = 0x1040; + } + _cairo_quartz_symbol_lookup_done = TRUE; } @@ -479,6 +485,10 @@ _cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface, CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y); if (op->u.show_glyphs.isClipping) { + /* Note that the comment in show_glyphs about kCGTextClip + * and the text transform still applies here; however, the + * cg_advances we have were already transformed, so we + * don't have to do anything. */ CGContextSetTextDrawingMode (cgc, kCGTextClip); CGContextSaveGState (cgc); } @@ -540,7 +550,6 @@ static void ComputeGradientValue (void *info, const float *in, float *out) { double fdist = *in; - cairo_fixed_t fdist_fix; cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info; unsigned int i; @@ -556,10 +565,8 @@ ComputeGradientValue (void *info, const float *in, float *out) } } - fdist_fix = _cairo_fixed_from_double(fdist); - for (i = 0; i < grad->n_stops; i++) { - if (grad->stops[i].x > fdist_fix) + if (grad->stops[i].offset > fdist) break; } @@ -571,8 +578,8 @@ ComputeGradientValue (void *info, const float *in, float *out) out[2] = grad->stops[i].color.blue; out[3] = grad->stops[i].color.alpha; } else { - float ax = _cairo_fixed_to_double(grad->stops[i-1].x); - float bx = _cairo_fixed_to_double(grad->stops[i].x) - ax; + float ax = grad->stops[i-1].offset; + float bx = grad->stops[i].offset - ax; float bp = (fdist - ax)/bx; float ap = 1.0 - bp; @@ -1731,7 +1738,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface, cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_action_t action; quartz_stroke_t stroke; - CGAffineTransform strokeTransform; + CGAffineTransform origCTM, strokeTransform; CGPathRef path_for_unbounded = NULL; ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type)); @@ -1752,6 +1759,9 @@ _cairo_quartz_surface_stroke (void *abstract_surface, CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap)); CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join)); CGContextSetMiterLimit (surface->cgContext, style->miter_limit); + + origCTM = CGContextGetCTM (surface->cgContext); + _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform); CGContextConcatCTM (surface->cgContext, strokeTransform); @@ -1798,6 +1808,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface, CGContextReplacePathWithStrokedPath (surface->cgContext); CGContextClip (surface->cgContext); + CGContextSetCTM (surface->cgContext, origCTM); + CGContextConcatCTM (surface->cgContext, surface->sourceTransform); CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height); CGContextScaleCTM (surface->cgContext, 1, -1); @@ -1810,6 +1822,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface, CGContextReplacePathWithStrokedPath (surface->cgContext); CGContextClip (surface->cgContext); + CGContextSetCTM (surface->cgContext, origCTM); + CGContextConcatCTM (surface->cgContext, surface->sourceTransform); CGContextDrawShading (surface->cgContext, surface->sourceShading); } else if (action != DO_NOTHING) { @@ -1854,7 +1868,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface, return rv; } -#if CAIRO_HAS_ATSUI_FONT +#if CAIRO_HAS_QUARTZ_FONT static cairo_int_status_t _cairo_quartz_surface_show_glyphs (void *abstract_surface, cairo_operator_t op, @@ -1889,7 +1903,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, if (op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; - if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_ATSUI) + if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ) return CAIRO_INT_STATUS_UNSUPPORTED; CGContextSaveGState (surface->cgContext); @@ -1909,33 +1923,31 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op)); /* this doesn't addref */ - cgfref = _cairo_atsui_scaled_font_get_cg_font_ref (scaled_font); + cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font); CGContextSetFont (surface->cgContext, cgfref); CGContextSetFontSize (surface->cgContext, 1.0); - if (CGContextSetShouldAntialiasFontsPtr) { - switch (scaled_font->options.antialias) { - case CAIRO_ANTIALIAS_SUBPIXEL: - CGContextSetShouldAntialiasFontsPtr (surface->cgContext, TRUE); - CGContextSetShouldSmoothFontsPtr (surface->cgContext, TRUE); - if (CGContextSetAllowsFontSmoothingPtr && - !CGContextGetAllowsFontSmoothingPtr (surface->cgContext)) - { - didForceFontSmoothing = TRUE; - CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE); - } - break; - case CAIRO_ANTIALIAS_NONE: - CGContextSetShouldAntialiasFontsPtr (surface->cgContext, FALSE); - break; - case CAIRO_ANTIALIAS_GRAY: - CGContextSetShouldAntialiasFontsPtr (surface->cgContext, TRUE); - CGContextSetShouldSmoothFontsPtr (surface->cgContext, FALSE); - break; - case CAIRO_ANTIALIAS_DEFAULT: - /* Don't do anything */ - break; - } + switch (scaled_font->options.antialias) { + case CAIRO_ANTIALIAS_SUBPIXEL: + CGContextSetShouldAntialias (surface->cgContext, TRUE); + CGContextSetShouldSmoothFonts (surface->cgContext, TRUE); + if (CGContextSetAllowsFontSmoothingPtr && + !CGContextGetAllowsFontSmoothingPtr (surface->cgContext)) + { + didForceFontSmoothing = TRUE; + CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE); + } + break; + case CAIRO_ANTIALIAS_NONE: + CGContextSetShouldAntialias (surface->cgContext, FALSE); + break; + case CAIRO_ANTIALIAS_GRAY: + CGContextSetShouldAntialias (surface->cgContext, TRUE); + CGContextSetShouldSmoothFonts (surface->cgContext, FALSE); + break; + case CAIRO_ANTIALIAS_DEFAULT: + /* Don't do anything */ + break; } if (num_glyphs > STATIC_BUF_SIZE) { @@ -1984,10 +1996,13 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, yprev = yf; } - if (isClipping) { - /* If we're clipping, we get multiplied by the inverse of our text matrix; no, - * I don't understand why this is any different. So pre-apply our textTransform. - * Note that the new CGContextShowGlyphsAtPositions has a similar problem. */ + if (_cairo_quartz_osx_version >= 0x1050 && isClipping) { + /* If we're clipping, OSX 10.5 (at least as of 10.5.2) has a + * bug (apple bug ID #5834794) where the glyph + * advances/positions are not transformed by the text matrix + * if kCGTextClip is being used. So, we pre-transform here. + * 10.4 does not have this problem (as of 10.4.11). + */ for (i = 0; i < num_glyphs - 1; i++) cg_advances[i] = CGSizeApplyAffineTransform(cg_advances[i], textTransform); } @@ -2060,7 +2075,7 @@ BAIL: return rv; } -#endif /* CAIRO_HAS_ATSUI_FONT */ +#endif /* CAIRO_HAS_QUARTZ_FONT */ static cairo_int_status_t _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, @@ -2293,11 +2308,11 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { _cairo_quartz_surface_mask, _cairo_quartz_surface_stroke, _cairo_quartz_surface_fill, -#if CAIRO_HAS_ATSUI_FONT +#if CAIRO_HAS_QUARTZ_FONT _cairo_quartz_surface_show_glyphs, #else - NULL, /* surface_show_glyphs */ -#endif /* CAIRO_HAS_ATSUI_FONT */ + NULL, /* show_glyphs */ +#endif NULL, /* snapshot */ NULL, /* is_similar */ @@ -2358,22 +2373,20 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, * @height: height of the surface, in pixels * * Creates a Quartz surface that wraps the given CGContext. The - * CGContext is assumed to be in the QuickDraw coordinate space (that - * is, with the origin at the upper left and the Y axis increasing - * downward.) If the CGContext is in the Quartz coordinate space (with - * the origin at the bottom left), then it should be flipped before - * this function is called: + * CGContext is assumed to be in the standard Cairo coordinate space + * (that is, with the origin at the upper left and the Y axis + * increasing downward). If the CGContext is in the Quartz coordinate + * space (with the origin at the bottom left), then it should be + * flipped before this function is called. The flip can be accomplished + * using a translate and a scale; for example: * * * CGContextTranslateCTM (cgContext, 0.0, height); * CGContextScaleCTM (cgContext, 1.0, -1.0); * * - * A very small number of Cairo operations cannot be translated to - * Quartz operations; those operations will fail on this surface. - * If all Cairo operations are required to succeed, consider rendering - * to a surface created by cairo_quartz_surface_create() and then copying - * the result to the CGContext. + * All Cairo operations are implemented in terms of Quartz operations, + * as long as Quartz-compatible elements are used (such as Quartz fonts). * * Return value: the newly created Cairo surface. * diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h index 5d78d391393..7982fbb1c2a 100644 --- a/gfx/cairo/cairo/src/cairo-quartz.h +++ b/gfx/cairo/cairo/src/cairo-quartz.h @@ -40,7 +40,7 @@ #if CAIRO_HAS_QUARTZ_SURFACE -#include +#include CAIRO_BEGIN_DECLS @@ -57,10 +57,26 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, cairo_public CGContextRef cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); +/* + * Quartz font support + */ + +#ifdef CAIRO_HAS_QUARTZ_FONT + +cairo_public cairo_font_face_t * +cairo_quartz_font_face_create_for_cgfont (CGFontRef font); + +cairo_public cairo_font_face_t * +cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id); + +#endif /* CAIRO_HAS_QUARTZ_FONT */ + CAIRO_END_DECLS -#else /* CAIRO_HAS_QUARTZ_SURFACE */ +#else + # error Cairo was not compiled with support for the quartz backend + #endif /* CAIRO_HAS_QUARTZ_SURFACE */ #endif /* CAIRO_QUARTZ_H */ diff --git a/gfx/cairo/cairo/src/cairo-rectangle.c b/gfx/cairo/cairo/src/cairo-rectangle.c index d2ec52d486d..6fb0ef2ad58 100644 --- a/gfx/cairo/cairo/src/cairo-rectangle.c +++ b/gfx/cairo/cairo/src/cairo-rectangle.c @@ -108,7 +108,7 @@ _cairo_rectangle_intersect (cairo_rectangle_int_t *dest, cairo_rectangle_int_t * cairo_bool_t _cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line) { - cairo_fixed_t t1, t2, t3, t4; + cairo_fixed_t t1=0, t2=0, t3=0, t4=0; cairo_int64_t t1y, t2y, t3x, t4x; cairo_fixed_t xlen, ylen; diff --git a/gfx/cairo/cairo/src/cairo-surface-fallback.c b/gfx/cairo/cairo/src/cairo-surface-fallback.c index f9f5b04ee2c..f84be7ad8a8 100644 --- a/gfx/cairo/cairo/src/cairo-surface-fallback.c +++ b/gfx/cairo/cairo/src/cairo-surface-fallback.c @@ -1151,9 +1151,9 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, if (rects[i].y < y1) y1 = rects[i].y; - if (rects[i].x + rects[i].width > x2) + if ((int)(rects[i].x + rects[i].width) > x2) x2 = rects[i].x + rects[i].width; - if (rects[i].y + rects[i].height > y2) + if ((int)(rects[i].y + rects[i].height) > y2) y2 = rects[i].y + rects[i].height; } diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index 42ee3ec435c..a72428345d4 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -1985,6 +1985,12 @@ _cairo_surface_set_empty_clip_path (cairo_surface_t *surface, return _cairo_surface_set_error (surface, status); } +cairo_clip_t * +_cairo_surface_get_clip (cairo_surface_t *surface) +{ + return surface->clip; +} + cairo_status_t _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) { @@ -2487,6 +2493,24 @@ _cairo_surface_create_in_error (cairo_status_t status) return (cairo_surface_t *) &_cairo_surface_nil_temp_file_error; case CAIRO_STATUS_INVALID_STRIDE: return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride; + case CAIRO_STATUS_SUCCESS: + ASSERT_NOT_REACHED; + /* fall-through */ + case CAIRO_STATUS_INVALID_RESTORE: + case CAIRO_STATUS_INVALID_POP_GROUP: + case CAIRO_STATUS_NO_CURRENT_POINT: + case CAIRO_STATUS_INVALID_MATRIX: + case CAIRO_STATUS_INVALID_STATUS: + case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: + case CAIRO_STATUS_SURFACE_FINISHED: + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_DASH: + case CAIRO_STATUS_INVALID_DSC_COMMENT: + case CAIRO_STATUS_INVALID_INDEX: + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: default: _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t *) &_cairo_surface_nil; diff --git a/gfx/cairo/cairo/src/cairo-svg-surface.c b/gfx/cairo/cairo/src/cairo-svg-surface.c index 997cadb6104..a900c245d23 100644 --- a/gfx/cairo/cairo/src/cairo-svg-surface.c +++ b/gfx/cairo/cairo/src/cairo-svg-surface.c @@ -233,10 +233,15 @@ _extract_svg_surface (cairo_surface_t *surface, { cairo_surface_t *target; + if (surface->status) + return surface->status; + if (! _cairo_surface_is_paginated (surface)) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); target = _cairo_paginated_surface_get_target (surface); + if (target->status) + return target->status; if (! _cairo_surface_is_svg (target)) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); @@ -486,15 +491,21 @@ _cairo_svg_surface_show_page (void *abstract_surface) static void _cairo_svg_surface_emit_transform (cairo_output_stream_t *output, char const *attribute_str, - cairo_matrix_t *matrix) + const cairo_matrix_t *object_matrix, + const cairo_matrix_t *parent_matrix) { - if (!_cairo_matrix_is_identity (matrix)) + cairo_matrix_t matrix = *object_matrix; + + if (parent_matrix != NULL) + cairo_matrix_multiply (&matrix, &matrix, parent_matrix); + + if (!_cairo_matrix_is_identity (&matrix)) _cairo_output_stream_printf (output, "%s=\"matrix(%f,%f,%f,%f,%f,%f)\"", attribute_str, - matrix->xx, matrix->yx, - matrix->xy, matrix->yy, - matrix->x0, matrix->y0); + matrix.xx, matrix.yx, + matrix.xy, matrix.yy, + matrix.x0, matrix.y0); } typedef struct @@ -654,7 +665,8 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, } _cairo_output_stream_printf (document->xml_node_glyphs, "xml_node_glyphs, " transform", &image->base.device_transform_inverse); + _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform", + &image->base.device_transform_inverse, NULL); _cairo_output_stream_printf (document->xml_node_glyphs, ">/n"); for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) { @@ -949,7 +961,8 @@ static cairo_status_t _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *svg_surface, cairo_surface_pattern_t *pattern, - int pattern_id, + int pattern_id, + const cairo_matrix_t *parent_matrix, const char *extra_attributes) { cairo_surface_t *surface; @@ -967,7 +980,7 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output status = _cairo_surface_get_extents (surface, &extents); if (status) - return status; + goto FAIL; p2u = pattern->base.matrix; status = cairo_matrix_invert (&p2u); @@ -981,7 +994,7 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output "width=\"%d\" height=\"%d\"", pattern_id, extents.width, extents.height); - _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u); + _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix); _cairo_output_stream_printf (output, ">\n"); } @@ -990,7 +1003,7 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output extents.width, extents.height); if (pattern_id == invalid_pattern_id) - _cairo_svg_surface_emit_transform (output, " transform", &p2u); + _cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix); if (extra_attributes) _cairo_output_stream_printf (output, " %s", extra_attributes); @@ -1004,6 +1017,7 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output if (pattern_id != invalid_pattern_id) _cairo_output_stream_printf (output, "\n"); + FAIL: _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, surface, &surface_attr); @@ -1144,6 +1158,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, int pattern_id, + const cairo_matrix_t *parent_matrix, const char *extra_attributes) { cairo_svg_document_t *document = surface->document; @@ -1171,7 +1186,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, pattern_id, meta_surface->width_pixels, meta_surface->height_pixels); - _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u); + _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix); _cairo_output_stream_printf (output, ">\n"); } @@ -1180,7 +1195,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, id); if (pattern_id == invalid_pattern_id) - _cairo_svg_surface_emit_transform (output, " transform", &p2u); + _cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix); if (extra_attributes) _cairo_output_stream_printf (output, " %s", extra_attributes); @@ -1198,16 +1213,17 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, int pattern_id, + const cairo_matrix_t *parent_matrix, const char *extra_attributes) { if (_cairo_surface_is_meta (pattern->surface)) { return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, pattern, - pattern_id, extra_attributes); + pattern_id, parent_matrix, extra_attributes); } return _cairo_svg_surface_emit_composite_image_pattern (output, surface, pattern, - pattern_id, extra_attributes); + pattern_id, parent_matrix, extra_attributes); } static void @@ -1253,7 +1269,8 @@ static cairo_status_t _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, cairo_output_stream_t *style, - cairo_bool_t is_stroke) + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) { cairo_svg_document_t *document = surface->document; cairo_status_t status; @@ -1262,13 +1279,13 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, pattern_id = document->pattern_id++; status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs, surface, pattern, - pattern_id, NULL); + pattern_id, parent_matrix, NULL); if (status) return status; _cairo_output_stream_printf (style, "%s: url(#pattern%d);", - is_stroke ? "color" : "fill", + is_stroke ? "stroke" : "fill", pattern_id); return CAIRO_STATUS_SUCCESS; @@ -1294,7 +1311,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, "\n", - _cairo_fixed_to_double (pattern->stops[0].x), + pattern->stops[0].offset, pattern->stops[0].color.red * 100.0, pattern->stops[0].color.green * 100.0, pattern->stops[0].color.blue * 100.0, @@ -1311,22 +1328,20 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, for (i = 0; i < pattern->n_stops; i++) { if (reverse_stops) { stops[i] = pattern->stops[pattern->n_stops - i - 1]; - stops[i].x = _cairo_fixed_from_double (1.0 - _cairo_fixed_to_double (stops[i].x)); + stops[i].offset = 1.0 - stops[i].offset; } else stops[i] = pattern->stops[i]; if (emulate_reflect) { - stops[i].x /= 2; + stops[i].offset /= 2; if (i > 0 && i < (pattern->n_stops - 1)) { if (reverse_stops) { stops[i + pattern->n_stops - 1] = pattern->stops[i]; - stops[i + pattern->n_stops - 1].x = - _cairo_fixed_from_double (0.5 + 0.5 - * _cairo_fixed_to_double (stops[i + pattern->n_stops - 1].x)); + stops[i + pattern->n_stops - 1].offset = + 0.5 + 0.5 * stops[i + pattern->n_stops - 1].offset; } else { stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1]; - stops[i + pattern->n_stops - 1].x = - _cairo_fixed_from_double (1 - 0.5 - * _cairo_fixed_to_double (stops [i + pattern->n_stops - 1].x)); + stops[i + pattern->n_stops - 1].offset = + 1 - 0.5 * stops[i + pattern->n_stops - 1].offset; } } } @@ -1338,8 +1353,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, if (start_offset >= 0.0) for (i = 0; i < n_stops; i++) { - offset = start_offset + (1 - start_offset ) * - _cairo_fixed_to_double (stops[i].x); + offset = start_offset + (1 - start_offset ) * stops[i].offset; _cairo_output_stream_printf (output, "= -start_offset) { + if (stops[i].offset >= -start_offset) { if (i > 0) { - if (stops[i].x != stops[i-1].x) { + if (stops[i].offset != stops[i-1].offset) { double x0, x1; cairo_color_t *color0, *color1; - x0 = _cairo_fixed_to_double (stops[i-1].x); - x1 = _cairo_fixed_to_double (stops[i].x); + x0 = stops[i-1].offset; + x1 = stops[i].offset; color0 = &stops[i-1].color; color1 = &stops[i].color; offset_color_start.red = color0->red + (color1->red - color0->red) @@ -1405,7 +1419,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, "\n", - _cairo_fixed_to_double (stops[i].x) + start_offset, + stops[i].offset + start_offset, stops[i].color.red * 100.0, stops[i].color.green * 100.0, stops[i].color.blue * 100.0, @@ -1416,7 +1430,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, "\n", - 1.0 + _cairo_fixed_to_double (stops[i].x) + start_offset, + 1.0 + stops[i].offset + start_offset, stops[i].color.red * 100.0, stops[i].color.green * 100.0, stops[i].color.blue * 100.0, @@ -1461,7 +1475,8 @@ static cairo_status_t _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, cairo_linear_pattern_t *pattern, cairo_output_stream_t *style, - cairo_bool_t is_stroke) + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) { cairo_svg_document_t *document = surface->document; double x0, y0, x1, y1; @@ -1486,7 +1501,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, x0, y0, x1, y1); _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base), - _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u); + _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix); _cairo_output_stream_printf (document->xml_node_defs, ">\n"); status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs, @@ -1500,7 +1515,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, _cairo_output_stream_printf (style, "%s: url(#linear%d);", - is_stroke ? "color" : "fill", + is_stroke ? "stroke" : "fill", document->linear_pattern_id); document->linear_pattern_id++; @@ -1512,7 +1527,8 @@ static cairo_status_t _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, cairo_radial_pattern_t *pattern, cairo_output_stream_t *style, - cairo_bool_t is_stroke) + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) { cairo_svg_document_t *document = surface->document; cairo_matrix_t p2u; @@ -1563,7 +1579,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, document->radial_pattern_id, x1, y1, x1, y1, r1); - _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u); + _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix); _cairo_output_stream_printf (document->xml_node_defs, ">\n"); if (extend == CAIRO_EXTEND_NONE || n_stops < 1) @@ -1647,7 +1663,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, _cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" "); else _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base); - _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u); + _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix); _cairo_output_stream_printf (document->xml_node_defs, ">\n"); /* To support cairo's EXTEND_NONE, (for which SVG has no similar @@ -1684,7 +1700,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, _cairo_output_stream_printf (style, "%s: url(#radial%d);", - is_stroke ? "color" : "fill", + is_stroke ? "stroke" : "fill", document->radial_pattern_id); document->radial_pattern_id++; @@ -1696,20 +1712,25 @@ static cairo_status_t _cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern, cairo_output_stream_t *output, - cairo_bool_t is_stroke) + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) { switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: - return _cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke); + return _cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, + output, is_stroke); case CAIRO_PATTERN_TYPE_SURFACE: - return _cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke); + return _cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, + output, is_stroke, parent_matrix); case CAIRO_PATTERN_TYPE_LINEAR: - return _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke); + return _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, + output, is_stroke, parent_matrix); case CAIRO_PATTERN_TYPE_RADIAL: - return _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke); + return _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, + output, is_stroke, parent_matrix); } return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); } @@ -1719,14 +1740,15 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, - cairo_fill_rule_t fill_rule) + cairo_fill_rule_t fill_rule, + cairo_matrix_t *parent_matrix) { _cairo_output_stream_printf (output, "fill-rule: %s; ", fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero"); _cairo_svg_surface_emit_operator (output, surface, op); - return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE); + return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix); } static cairo_status_t @@ -1734,7 +1756,8 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, - cairo_stroke_style_t *stroke_style) + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *parent_matrix) { cairo_status_t status; const char *line_cap, *line_join; @@ -1776,7 +1799,7 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output, line_cap, line_join); - status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE); + status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix); if (status) return status; @@ -1826,11 +1849,13 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, cairo_status_t status; _cairo_output_stream_printf (surface->xml_node, "xml_node, surface, fill_op, fill_source, fill_rule); + status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op, + fill_source, fill_rule, stroke_ctm_inverse); if (status) return status; - status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op, stroke_source, stroke_style); + status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op, + stroke_source, stroke_style, stroke_ctm_inverse); if (status) return status; @@ -1840,7 +1865,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, if (status) return status; - _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm); + _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); return CAIRO_STATUS_SUCCESS; @@ -1864,7 +1889,7 @@ _cairo_svg_surface_fill (void *abstract_surface, assert (_cairo_svg_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "xml_node, surface, op, source, fill_rule); + status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL); if (status) return status; @@ -1913,6 +1938,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output, surface, (cairo_surface_pattern_t *) source, invalid_pattern_id, + NULL, extra_attributes); _cairo_output_stream_printf (output, @@ -1921,7 +1947,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output, "style=\"", surface->width, surface->height); _cairo_svg_surface_emit_operator (output, surface, op); - status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE); + status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL); if (status) return status; @@ -2086,14 +2112,18 @@ _cairo_svg_surface_stroke (void *abstract_dst, assert (_cairo_svg_surface_operation_supported (surface, op, source)); _cairo_output_stream_printf (surface->xml_node, "xml_node, surface, op, source, stroke_style); + status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op, + source, stroke_style, ctm_inverse); + if (status) + return status; + _cairo_output_stream_printf (surface->xml_node, "\" "); status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse); if (status) return status; - _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm); + _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); return CAIRO_STATUS_SUCCESS; @@ -2130,7 +2160,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "xml_node, FALSE); + surface->xml_node, FALSE, NULL); if (status) return status; diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset.c b/gfx/cairo/cairo/src/cairo-truetype-subset.c index f143882e20f..3fa174c8287 100644 --- a/gfx/cairo/cairo/src/cairo-truetype-subset.c +++ b/gfx/cairo/cairo/src/cairo-truetype-subset.c @@ -85,8 +85,10 @@ struct _cairo_truetype_font { }; -static int -cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph); +static cairo_status_t +cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, + unsigned short glyph, + unsigned short *out); #define SFNT_VERSION 0x00010000 #define SFNT_STRING_MAX_LENGTH 65535 @@ -491,29 +493,38 @@ cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font, return CAIRO_STATUS_SUCCESS; } -static void -cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font, - unsigned char *buffer) +static cairo_status_t +cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font, + unsigned char *buffer, + unsigned long size) { tt_glyph_data_t *glyph_data; - tt_composite_glyph_t *composite_glyph; + tt_composite_glyph_t *composite_glyph, *last_glyph; int num_args; int has_more_components; unsigned short flags; unsigned short index; + cairo_status_t status; if (font->status) - return; + return font->status; + + if (size < sizeof (tt_glyph_data_t)) + return CAIRO_INT_STATUS_UNSUPPORTED; glyph_data = (tt_glyph_data_t *) buffer; if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0) - return; + return CAIRO_STATUS_SUCCESS; composite_glyph = &glyph_data->glyph; + last_glyph = (tt_composite_glyph_t *) (buffer + size); do { flags = be16_to_cpu (composite_glyph->flags); has_more_components = flags & TT_MORE_COMPONENTS; - index = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index)); + status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index); + if (status) + return status; + composite_glyph->index = cpu_to_be16 (index); num_args = 1; if (flags & TT_ARG_1_AND_2_ARE_WORDS) @@ -525,7 +536,12 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font, else if (flags & TT_WE_HAVE_A_TWO_BY_TWO) num_args += 3; composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]); + + if (has_more_components && composite_glyph >= last_glyph) + return CAIRO_INT_STATUS_UNSUPPORTED; } while (has_more_components); + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -580,6 +596,12 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, end = be32_to_cpu (u.long_offsets[index + 1]); } + /* quick sanity check... */ + if (end < begin) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + size = end - begin; status = cairo_truetype_font_align_output (font, &next); if (status) @@ -601,7 +623,9 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, if (status) goto FAIL; - cairo_truetype_font_remap_composite_glyph (font, buffer); + status = cairo_truetype_font_remap_composite_glyph (font, buffer, size); + if (status) + goto FAIL; } } @@ -932,16 +956,22 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font, return _cairo_truetype_font_set_error (font, status); } -static int -cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph) +static cairo_status_t +cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, + unsigned short glyph, + unsigned short *out) { + if (glyph >= font->num_glyphs_in_face) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (font->parent_to_subset[glyph] == 0) { font->parent_to_subset[glyph] = font->base.num_glyphs; font->glyphs[font->base.num_glyphs].parent_index = glyph; font->base.num_glyphs++; } - return font->parent_to_subset[glyph]; + *out = font->parent_to_subset[glyph]; + return CAIRO_STATUS_SUCCESS; } static void @@ -1037,7 +1067,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, cairo_status_t status; const char *data = NULL; /* squelch bogus compiler warning */ unsigned long length = 0; /* squelch bogus compiler warning */ - unsigned long parent_glyph, offsets_length; + unsigned long offsets_length; unsigned int i; const unsigned long *string_offsets = NULL; unsigned long num_strings = 0; @@ -1047,8 +1077,9 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, return status; for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { - parent_glyph = font->scaled_font_subset->glyphs[i]; - cairo_truetype_font_use_glyph (font, parent_glyph); + unsigned short parent_glyph = font->scaled_font_subset->glyphs[i]; + status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph); + assert (status == CAIRO_STATUS_SUCCESS); } cairo_truetype_font_create_truetype_table_list (font); diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c index b560b48e660..27b58191427 100644 --- a/gfx/cairo/cairo/src/cairo-win32-font.c +++ b/gfx/cairo/cairo/src/cairo-win32-font.c @@ -1907,7 +1907,7 @@ cairo_font_face_t * cairo_win32_font_face_create_for_hfont (HFONT font) { LOGFONTW logfont; - GetObject (font, sizeof(logfont), &logfont); + GetObjectW (font, sizeof(logfont), &logfont); if (logfont.lfEscapement != 0 || logfont.lfOrientation != 0 || logfont.lfWidth != 0) { diff --git a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c index 0713ef72778..cc3a17b5bee 100644 --- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c @@ -757,7 +757,7 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa } stop = i%num_rects + 1; - vert[i*2+1].x = (LONG)(d*(range_start + i/num_rects + _cairo_fixed_to_double (pattern->base.stops[stop].x))); + vert[i*2+1].x = (LONG)(d*(range_start + i/num_rects + pattern->base.stops[stop].offset)); vert[i*2+1].y = (LONG) clip.bottom; if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2) stop = num_rects - stop; @@ -1419,6 +1419,9 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface) { cairo_win32_surface_t *surface = abstract_surface; XFORM xform; + double x_res, y_res; + cairo_matrix_t inverse_ctm; + cairo_status_t status; SaveDC (surface->dc); /* Save application context first, before doing MWT */ @@ -1431,6 +1434,17 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface) surface->ctm.x0 = xform.eDx; surface->ctm.y0 = xform.eDy; surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm); + + inverse_ctm = surface->ctm; + status = cairo_matrix_invert (&inverse_ctm); + if (status) + return status; + + x_res = (double) GetDeviceCaps(surface->dc, LOGPIXELSX); + y_res = (double) GetDeviceCaps(surface->dc, LOGPIXELSY); + cairo_matrix_transform_distance (&inverse_ctm, &x_res, &y_res); + _cairo_surface_set_resolution (&surface->base, x_res, y_res); + if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY)) return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform"); @@ -1468,7 +1482,6 @@ cairo_surface_t * cairo_win32_printing_surface_create (HDC hdc) { cairo_win32_surface_t *surface; - int xr, yr; RECT rect; surface = malloc (sizeof (cairo_win32_surface_t)); @@ -1504,10 +1517,6 @@ cairo_win32_printing_surface_create (HDC hdc) _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); - xr = GetDeviceCaps(hdc, LOGPIXELSX); - yr = GetDeviceCaps(hdc, LOGPIXELSY); - _cairo_surface_set_resolution (&surface->base, (double) xr, (double) yr); - return _cairo_paginated_surface_create (&surface->base, CAIRO_CONTENT_COLOR_ALPHA, surface->extents.width, diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c index 5719c6de499..bfe71b4f391 100644 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c @@ -410,9 +410,15 @@ _cairo_win32_surface_create_similar_internal (void *abstract_src, saved_dc_bitmap = SelectObject (ddb_dc, ddb); new_surf = (cairo_win32_surface_t*) cairo_win32_surface_create (ddb_dc); - new_surf->bitmap = ddb; - new_surf->saved_dc_bitmap = saved_dc_bitmap; - new_surf->is_dib = FALSE; + if (new_surf->base.status == CAIRO_STATUS_SUCCESS) { + new_surf->bitmap = ddb; + new_surf->saved_dc_bitmap = saved_dc_bitmap; + new_surf->is_dib = FALSE; + } else { + SelectObject (ddb_dc, saved_dc_bitmap); + DeleteDC (ddb_dc); + DeleteObject (ddb); + } } return (cairo_surface_t*) new_surf; diff --git a/gfx/cairo/cairo/src/cairo-xlib-private.h b/gfx/cairo/cairo/src/cairo-xlib-private.h index 3e04ecd80e1..5bfc2ec564e 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-private.h @@ -70,6 +70,12 @@ struct _cairo_xlib_display { unsigned int closed :1; }; +typedef struct _cairo_xlib_visual_info { + VisualID visualid; + XColor colors[256]; + unsigned long rgb333_to_pseudocolor[512]; +} cairo_xlib_visual_info_t; + struct _cairo_xlib_screen_info { cairo_xlib_screen_info_t *next; cairo_reference_count_t ref_count; @@ -82,6 +88,8 @@ struct _cairo_xlib_screen_info { GC gc[9]; unsigned int gc_needs_clip_reset; + + cairo_array_t visuals; }; cairo_private cairo_xlib_display_t * @@ -125,4 +133,18 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth); cairo_private cairo_status_t _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip); +cairo_private cairo_status_t +_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info, + Visual *visual, + cairo_xlib_visual_info_t **out); + +cairo_private cairo_status_t +_cairo_xlib_visual_info_create (Display *dpy, + int screen, + VisualID visualid, + cairo_xlib_visual_info_t **out); + +cairo_private void +_cairo_xlib_visual_info_destroy (Display *dpy, cairo_xlib_visual_info_t *info); + #endif /* CAIRO_XLIB_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-screen.c b/gfx/cairo/cairo/src/cairo-xlib-screen.c index b759a85e31f..8a3da6675fc 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-screen.c +++ b/gfx/cairo/cairo/src/cairo-xlib-screen.c @@ -269,6 +269,8 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) { cairo_xlib_screen_info_t **prev; cairo_xlib_screen_info_t *list; + cairo_xlib_visual_info_t **visuals; + int i; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count)); @@ -282,12 +284,17 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) break; } } + visuals = _cairo_array_index (&info->visuals, 0); + for (i = 0; i < _cairo_array_num_elements (&info->visuals); i++) + _cairo_xlib_visual_info_destroy (info->display->display, visuals[i]); CAIRO_MUTEX_UNLOCK (info->display->mutex); _cairo_xlib_screen_info_close_display (info); _cairo_xlib_display_destroy (info->display); + _cairo_array_fini (&info->visuals); + free (info); } @@ -335,6 +342,9 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) memset (info->gc, 0, sizeof (info->gc)); info->gc_needs_clip_reset = 0; + _cairo_array_init (&info->visuals, + sizeof (cairo_xlib_visual_info_t*)); + if (screen) { int event_base, error_base; info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && @@ -411,3 +421,62 @@ _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cai return status; } + +cairo_status_t +_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info, + Visual *visual, + cairo_xlib_visual_info_t **out) +{ + cairo_xlib_visual_info_t **visuals, *ret = NULL; + cairo_status_t status; + int i, n_visuals; + + CAIRO_MUTEX_LOCK (info->display->mutex); + visuals = _cairo_array_index (&info->visuals, 0); + n_visuals = _cairo_array_num_elements (&info->visuals); + for (i = 0; i < n_visuals; i++) { + if (visuals[i]->visualid == visual->visualid) { + ret = visuals[i]; + break; + } + } + CAIRO_MUTEX_UNLOCK (info->display->mutex); + + if (ret != NULL) { + *out = ret; + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_xlib_visual_info_create (info->display->display, + XScreenNumberOfScreen (info->screen), + visual->visualid, + &ret); + if (status) + return status; + + CAIRO_MUTEX_LOCK (info->display->mutex); + if (n_visuals != _cairo_array_num_elements (&info->visuals)) { + /* check that another thread has not added our visual */ + int new_visuals = _cairo_array_num_elements (&info->visuals); + visuals = _cairo_array_index (&info->visuals, 0); + for (i = n_visuals; i < new_visuals; i++) { + if (visuals[i]->visualid == visual->visualid) { + _cairo_xlib_visual_info_destroy (info->display->display, ret); + ret = visuals[i]; + break; + } + } + if (i == new_visuals) + status = _cairo_array_append (&info->visuals, &ret); + } else + status = _cairo_array_append (&info->visuals, &ret); + CAIRO_MUTEX_UNLOCK (info->display->mutex); + + if (status) { + _cairo_xlib_visual_info_destroy (info->display->display, ret); + return status; + } + + *out = ret; + return CAIRO_STATUS_SUCCESS; +} diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface-private.h b/gfx/cairo/cairo/src/cairo-xlib-surface-private.h index e5ccf905a17..d5df19ca2fb 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-surface-private.h @@ -91,6 +91,11 @@ struct _cairo_xlib_surface { cairo_filter_t filter; int repeat; XTransform xtransform; + + uint32_t a_mask; + uint32_t r_mask; + uint32_t g_mask; + uint32_t b_mask; }; enum { diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface.c b/gfx/cairo/cairo/src/cairo-xlib-surface.c index 59dd45bea2e..df80ca69883 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface.c +++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c @@ -48,6 +48,16 @@ typedef int (*cairo_xlib_error_func_t) (Display *display, XErrorEvent *event); +static cairo_surface_t * +_cairo_xlib_surface_create_internal (Display *dpy, + Drawable drawable, + Screen *screen, + Visual *visual, + XRenderPictFormat *xrender_format, + int width, + int height, + int depth); + static cairo_status_t _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface); @@ -71,10 +81,6 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, int num_glyphs, cairo_scaled_font_t *scaled_font); -#if CAIRO_HAS_XLIB_XRENDER_SURFACE -slim_hidden_proto (cairo_xlib_surface_create_with_xrender_format); -#endif - /* * Instead of taking two round trips for each blending request, * assume that if a particular drawable fails GetImage that it will @@ -173,9 +179,11 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src, depth); surface = (cairo_xlib_surface_t *) - cairo_xlib_surface_create_with_xrender_format (dpy, pix, src->screen, - xrender_format, - width, height); + _cairo_xlib_surface_create_internal (dpy, pix, + src->screen, src->visual, + xrender_format, + width, height, + depth); if (surface->base.status) { XFreePixmap (dpy, pix); return &surface->base; @@ -251,10 +259,11 @@ _cairo_xlib_surface_create_similar (void *abstract_src, xrender_format->depth); surface = (cairo_xlib_surface_t *) - cairo_xlib_surface_create_with_xrender_format (src->dpy, pix, - src->screen, - xrender_format, - width, height); + _cairo_xlib_surface_create_internal (src->dpy, pix, + src->screen, src->visual, + xrender_format, + width, height, + xrender_format->depth); if (surface->base.status != CAIRO_STATUS_SUCCESS) { XFreePixmap (src->dpy, pix); return &surface->base; @@ -455,18 +464,70 @@ _swap_ximage_to_native (XImage *ximage) } } +/* Given a mask, (with a single sequence of contiguous 1 bits), return + * the number of 1 bits in 'width' and the number of 0 bits to its + * right in 'shift'. */ +static inline void +_characterize_field (uint32_t mask, int *width, int *shift) +{ + *width = _cairo_popcount (mask); + /* The final '& 31' is to force a 0 mask to result in 0 shift. */ + *shift = _cairo_popcount ((mask - 1) & ~mask) & 31; +} + +/* Convert a field of 'width' bits to 'new_width' bits with correct + * rounding. */ +static inline uint32_t +_resize_field (uint32_t field, int width, int new_width) +{ + if (width == 0) + return 0; + + if (width >= new_width) { + return field >> (width - new_width); + } else { + uint32_t result = field << (new_width - width); + + while (width < new_width) { + result |= result >> width; + width <<= 1; + } + return result; + } +} + +/* Given a shifted field value, (described by 'width' and 'shift), + * resize it 8-bits and return that value. + * + * Note that the original field value must not have any non-field bits + * set. + */ +static inline uint32_t +_field_to_8 (uint32_t field, int width, int shift) +{ + return _resize_field (field >> shift, width, 8); +} + +/* Given an 8-bit value, convert it to a field of 'width', shift it up + * to 'shift, and return it. */ +static inline uint32_t +_field_from_8 (uint32_t field, int width, int shift) +{ + return _resize_field (field, 8, width) << shift; +} + static cairo_status_t _get_image_surface (cairo_xlib_surface_t *surface, cairo_rectangle_int_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_int_t *image_rect) { + cairo_int_status_t status; cairo_image_surface_t *image; XImage *ximage; - short x1, y1, x2, y2; - cairo_format_masks_t masks; + unsigned short x1, y1, x2, y2; pixman_format_code_t pixman_format; - cairo_status_t status; + cairo_format_masks_t xlib_masks; x1 = 0; y1 = 0; @@ -567,55 +628,127 @@ _get_image_surface (cairo_xlib_surface_t *surface, _swap_ximage_to_native (ximage); - /* - * Compute the pixel format masks from either a XrenderFormat or - * else from a visual; failing that we assume the drawable is an - * alpha-only pixmap as it could only have been created that way - * through the cairo_xlib_surface_create_for_bitmap function. - */ - if (surface->xrender_format) { - masks.bpp = ximage->bits_per_pixel; - masks.red_mask = (unsigned long) surface->xrender_format->direct.redMask - << surface->xrender_format->direct.red; - masks.green_mask = (unsigned long) surface->xrender_format->direct.greenMask - << surface->xrender_format->direct.green; - masks.blue_mask = (unsigned long) surface->xrender_format->direct.blueMask - << surface->xrender_format->direct.blue; - masks.alpha_mask = (unsigned long) surface->xrender_format->direct.alphaMask - << surface->xrender_format->direct.alpha; - } else if (surface->visual) { - masks.bpp = ximage->bits_per_pixel; - masks.alpha_mask = 0; - masks.red_mask = surface->visual->red_mask; - masks.green_mask = surface->visual->green_mask; - masks.blue_mask = surface->visual->blue_mask; + xlib_masks.bpp = ximage->bits_per_pixel; + xlib_masks.alpha_mask = surface->a_mask; + xlib_masks.red_mask = surface->r_mask; + xlib_masks.green_mask = surface->g_mask; + xlib_masks.blue_mask = surface->b_mask; + + status = _pixman_format_from_masks (&xlib_masks, &pixman_format); + if (status == CAIRO_STATUS_SUCCESS) { + image = (cairo_image_surface_t*) + _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data, + pixman_format, + ximage->width, + ximage->height, + ximage->bytes_per_line); + status = image->base.status; + if (status) { + XDestroyImage (ximage); + return status; + } + + /* Let the surface take ownership of the data */ + _cairo_image_surface_assume_ownership_of_data (image); + ximage->data = NULL; } else { - masks.bpp = ximage->bits_per_pixel; - masks.red_mask = 0; - masks.green_mask = 0; - masks.blue_mask = 0; - if (surface->depth < 32) - masks.alpha_mask = (1 << surface->depth) - 1; - else - masks.alpha_mask = 0xffffffff; + cairo_format_t format; + unsigned char *data; + uint32_t *row; + uint32_t in_pixel, out_pixel; + unsigned int rowstride; + uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0; + int a_width=0, r_width=0, g_width=0, b_width=0; + int a_shift=0, r_shift=0, g_shift=0, b_shift=0; + int x, y; + XColor *colors = NULL; + + /* The visual we are dealing with is not supported by the + * standard pixman formats. So we must first convert the data + * to a supported format. */ + if (surface->visual->class == TrueColor) { + cairo_bool_t has_color; + cairo_bool_t has_alpha; + + has_color = (surface->r_mask || + surface->g_mask || + surface->b_mask); + has_alpha = surface->a_mask; + + if (has_color) { + if (has_alpha) { + format = CAIRO_FORMAT_ARGB32; + } else { + format = CAIRO_FORMAT_RGB24; + } + } else { + /* XXX: Using CAIRO_FORMAT_A8 here would be more + * efficient, but would require slightly different code in + * the image conversion to put the alpha channel values + * into the right place. */ + format = CAIRO_FORMAT_ARGB32; + } + + a_mask = surface->a_mask; + r_mask = surface->r_mask; + g_mask = surface->g_mask; + b_mask = surface->b_mask; + + _characterize_field (a_mask, &a_width, &a_shift); + _characterize_field (r_mask, &r_width, &r_shift); + _characterize_field (g_mask, &g_width, &g_shift); + _characterize_field (b_mask, &b_width, &b_shift); + + } else { + cairo_xlib_visual_info_t *visual_info; + + format = CAIRO_FORMAT_RGB24; + + status = _cairo_xlib_screen_get_visual_info (surface->screen_info, + surface->visual, + &visual_info); + if (status) { + XDestroyImage (ximage); + return status; + } + + colors = visual_info->colors; + } + + image = (cairo_image_surface_t *) cairo_image_surface_create + (format, ximage->width, ximage->height); + status = image->base.status; + if (status) { + XDestroyImage (ximage); + return status; + } + + data = cairo_image_surface_get_data (&image->base); + rowstride = cairo_image_surface_get_stride (&image->base) >> 2; + row = (uint32_t *) data; + for (y = 0; y < ximage->height; y++) { + for (x = 0; x < ximage->width; x++) { + in_pixel = XGetPixel (ximage, x, y); + if (surface->visual->class == TrueColor) { + out_pixel = ( + _field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 | + _field_to_8 (in_pixel & r_mask, r_width, r_shift) << 16 | + _field_to_8 (in_pixel & g_mask, g_width, g_shift) << 8 | + _field_to_8 (in_pixel & b_mask, b_width, b_shift)); + } else { + XColor *color; + color = &colors[in_pixel & 0xff]; + out_pixel = ( + _field_to_8 (color->red, 16, 0) << 16 | + _field_to_8 (color->green, 16, 0) << 8 | + _field_to_8 (color->blue, 16, 0)); + } + row[x] = out_pixel; + } + row += rowstride; + } } - pixman_format = _pixman_format_from_masks (&masks); - image = (cairo_image_surface_t*) - _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data, - pixman_format, - ximage->width, - ximage->height, - ximage->bytes_per_line); - status = image->base.status; - if (status) { - XDestroyImage (ximage); - return status; - } - - /* Let the surface take ownership of the data */ - _cairo_image_surface_assume_ownership_of_data (image); - ximage->data = NULL; XDestroyImage (ximage); *image_out = image; @@ -719,39 +852,118 @@ _draw_image_surface (cairo_xlib_surface_t *surface, int dst_y) { XImage ximage; - uint32_t bpp, red, green, blue; + cairo_format_masks_t image_masks; int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; cairo_status_t status; + cairo_bool_t own_data; + unsigned long *rgb333_to_pseudocolor = NULL; + + _pixman_format_to_masks (image->pixman_format, &image_masks); - _pixman_format_to_masks (image->pixman_format, &bpp, &red, &green, &blue); - ximage.width = image->width; ximage.height = image->height; ximage.format = ZPixmap; - ximage.data = (char *)image->data; ximage.byte_order = native_byte_order; ximage.bitmap_unit = 32; /* always for libpixman */ ximage.bitmap_bit_order = native_byte_order; ximage.bitmap_pad = 32; /* always for libpixman */ - ximage.depth = image->depth; - ximage.bytes_per_line = image->stride; - ximage.bits_per_pixel = bpp; - ximage.red_mask = red; - ximage.green_mask = green; - ximage.blue_mask = blue; + ximage.depth = surface->depth; + ximage.red_mask = surface->r_mask; + ximage.green_mask = surface->g_mask; + ximage.blue_mask = surface->b_mask; ximage.xoffset = 0; - XInitImage (&ximage); + if (image_masks.red_mask == surface->r_mask && + image_masks.green_mask == surface->g_mask && + image_masks.blue_mask == surface->b_mask) + { + ximage.bits_per_pixel = image_masks.bpp; + ximage.bytes_per_line = image->stride; + ximage.data = (char *)image->data; + own_data = FALSE; + XInitImage (&ximage); + } else { + unsigned int stride, rowstride; + int x, y; + uint32_t in_pixel, out_pixel, *row; + int a_width=0, r_width=0, g_width=0, b_width=0; + int a_shift=0, r_shift=0, g_shift=0, b_shift=0; + + if (surface->depth > 16) { + ximage.bits_per_pixel = 32; + } else if (surface->depth > 8) { + ximage.bits_per_pixel = 16; + } else if (surface->depth > 1) { + ximage.bits_per_pixel = 8; + } else { + ximage.bits_per_pixel = 1; + } + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width, + ximage.bits_per_pixel); + ximage.bytes_per_line = stride; + ximage.data = _cairo_malloc_ab (stride, ximage.height); + if (ximage.data == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + own_data = TRUE; + + XInitImage (&ximage); + + if (surface->visual->class == TrueColor) { + _characterize_field (surface->a_mask, &a_width, &a_shift); + _characterize_field (surface->r_mask, &r_width, &r_shift); + _characterize_field (surface->g_mask, &g_width, &g_shift); + _characterize_field (surface->b_mask, &b_width, &b_shift); + } else { + cairo_xlib_visual_info_t *visual_info; + + status = _cairo_xlib_screen_get_visual_info (surface->screen_info, + surface->visual, + &visual_info); + if (status) + goto BAIL; + + rgb333_to_pseudocolor = visual_info->rgb333_to_pseudocolor; + } + + rowstride = cairo_image_surface_get_stride (&image->base) >> 2; + row = (uint32_t *) cairo_image_surface_get_data (&image->base); + for (y = 0; y < ximage.height; y++) { + for (x = 0; x < ximage.width; x++) { + int a, r, g, b; + in_pixel = row[x]; + a = (in_pixel >> 24) & 0xff; + r = (in_pixel >> 16) & 0xff; + g = (in_pixel >> 8) & 0xff; + b = (in_pixel ) & 0xff; + if (surface->visual->class == TrueColor) + out_pixel = (_field_from_8 (a, a_width, a_shift) | + _field_from_8 (r, r_width, r_shift) | + _field_from_8 (g, g_width, g_shift) | + _field_from_8 (b, b_width, b_shift)); + else + out_pixel = rgb333_to_pseudocolor[_field_from_8 (r, 3, 6) | + _field_from_8 (g, 3, 3) | + _field_from_8 (b, 3, 0)]; + XPutPixel (&ximage, x, y, out_pixel); + } + row += rowstride; + } + } status = _cairo_xlib_surface_ensure_gc (surface); if (status) - return status; + goto BAIL; + XPutImage(surface->dpy, surface->drawable, surface->gc, &ximage, src_x, src_y, dst_x, dst_y, width, height); - return CAIRO_STATUS_SUCCESS; + BAIL: + if (own_data) + free (ximage.data); + return status; } static cairo_status_t @@ -2032,6 +2244,40 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->clip_rects = surface->embedded_clip_rects; surface->num_clip_rects = 0; + /* + * Compute the pixel format masks from either a XrenderFormat or + * else from a visual; failing that we assume the drawable is an + * alpha-only pixmap as it could only have been created that way + * through the cairo_xlib_surface_create_for_bitmap function. + */ + if (xrender_format) { + surface->a_mask = (unsigned long) + surface->xrender_format->direct.alphaMask + << surface->xrender_format->direct.alpha; + surface->r_mask = (unsigned long) + surface->xrender_format->direct.redMask + << surface->xrender_format->direct.red; + surface->g_mask = (unsigned long) + surface->xrender_format->direct.greenMask + << surface->xrender_format->direct.green; + surface->b_mask = (unsigned long) + surface->xrender_format->direct.blueMask + << surface->xrender_format->direct.blue; + } else if (visual) { + surface->a_mask = 0; + surface->r_mask = visual->red_mask; + surface->g_mask = visual->green_mask; + surface->b_mask = visual->blue_mask; + } else { + if (depth < 32) + surface->a_mask = (1 << depth) - 1; + else + surface->a_mask = 0xffffffff; + surface->r_mask = 0; + surface->g_mask = 0; + surface->b_mask = 0; + } + return (cairo_surface_t *) surface; } @@ -2155,7 +2401,6 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, return _cairo_xlib_surface_create_internal (dpy, drawable, screen, NULL, format, width, height, 0); } -slim_hidden_def (cairo_xlib_surface_create_with_xrender_format); /** * cairo_xlib_surface_get_xrender_format: @@ -2665,7 +2910,6 @@ _cairo_xlib_surface_add_glyph (Display *dpy, cairo_xlib_font_glyphset_info_t *glyphset_info; if (!glyph_surface) { - status = _cairo_scaled_glyph_lookup (scaled_font, _cairo_scaled_glyph_index (scaled_glyph), CAIRO_SCALED_GLYPH_INFO_METRICS | @@ -2694,17 +2938,18 @@ _cairo_xlib_surface_add_glyph (Display *dpy, /* If the glyph surface has zero height or width, we create * a clear 1x1 surface, to avoid various X server bugs. */ - if ((glyph_surface->width == 0) || (glyph_surface->height == 0)) { + if (glyph_surface->width == 0 || glyph_surface->height == 0) { cairo_t *cr; cairo_surface_t *tmp_surface; tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1); + if (tmp_surface->status) + goto BAIL; + cr = cairo_create (tmp_surface); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); - status = cairo_status (cr); - cairo_destroy (cr); tmp_surface->device_transform = glyph_surface->base.device_transform; @@ -2727,17 +2972,17 @@ _cairo_xlib_surface_add_glyph (Display *dpy, tmp_surface = cairo_image_surface_create (glyphset_info->format, glyph_surface->width, glyph_surface->height); + if (tmp_surface->status) + goto BAIL; + tmp_surface->device_transform = glyph_surface->base.device_transform; tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse; cr = cairo_create (tmp_surface); - cairo_set_source_surface (cr, &glyph_surface->base, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); - status = cairo_status (cr); - cairo_destroy (cr); glyph_surface = (cairo_image_surface_t *) tmp_surface; @@ -2821,7 +3066,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, glyph_index = _cairo_scaled_glyph_index (scaled_glyph); XRenderAddGlyphs (dpy, glyphset_info->glyphset, - &glyph_index, &(glyph_info), 1, + &glyph_index, &glyph_info, 1, (char *) data, glyph_surface->stride * glyph_surface->height); diff --git a/gfx/cairo/cairo/src/cairo-xlib-visual.c b/gfx/cairo/cairo/src/cairo-xlib-visual.c new file mode 100644 index 00000000000..a45be53f3f5 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-xlib-visual.c @@ -0,0 +1,148 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-xlib-private.h" + +/* A perceptual distance metric between two colors. No sqrt needed + * since the square of the distance is still a valid metric. */ + +/* XXX: This is currently using linear distance in RGB space which is + * decidedly not perceptually linear. If someone cared a lot about the + * quality, they might choose something else here. Then again, they + * might also choose not to use a PseudoColor visual... */ +static inline int +_color_distance (unsigned short r1, unsigned short g1, unsigned short b1, + unsigned short r2, unsigned short g2, unsigned short b2) +{ + r1 >>= 8; g1 >>= 8; b1 >>= 8; + r2 >>= 8; g2 >>= 8; b2 >>= 8; + + return ((r2 - r1) * (r2 - r1) + + (g2 - g1) * (g2 - g1) + + (b2 - b1) * (b2 - b1)); +} + +cairo_status_t +_cairo_xlib_visual_info_create (Display *dpy, + int screen, + VisualID visualid, + cairo_xlib_visual_info_t **out) +{ + cairo_xlib_visual_info_t *info; + Colormap colormap = DefaultColormap (dpy, screen); + XColor color; + int gray, red, green, blue; + int i, index, distance, min_distance = 0; + + const unsigned short index5_to_short[5] = { + 0x0000, 0x4000, 0x8000, 0xc000, 0xffff + }; + const unsigned short index8_to_short[8] = { + 0x0000, 0x2492, 0x4924, 0x6db6, + 0x9249, 0xb6db, 0xdb6d, 0xffff + }; + + info = malloc (sizeof (cairo_xlib_visual_info_t)); + if (info == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + info->visualid = visualid; + + /* Allocate a 16-entry gray ramp and a 5x5x5 color cube. Give up + * as soon as failures start. */ + for (gray = 0; gray < 16; gray++) { + color.red = (gray << 12) | (gray << 8) | (gray << 4) | gray; + color.green = (gray << 12) | (gray << 8) | (gray << 4) | gray; + color.blue = (gray << 12) | (gray << 8) | (gray << 4) | gray; + if (! XAllocColor (dpy, colormap, &color)) + goto DONE_ALLOCATE; + } + + /* XXX: Could do this in a more clever order to have the best + * possible results from early failure. Could also choose a cube + * uniformly distributed in a better space than RGB. */ + for (red = 0; red < 5; red++) { + for (green = 0; green < 5; green++) { + for (blue = 0; blue < 5; blue++) { + color.red = index5_to_short[red]; + color.green = index5_to_short[green]; + color.blue = index5_to_short[blue]; + color.pixel = 0; + color.flags = 0; + color.pad = 0; + if (! XAllocColor (dpy, colormap, &color)) + goto DONE_ALLOCATE; + } + } + } + DONE_ALLOCATE: + + for (i = 0; i < ARRAY_LENGTH (info->colors); i++) + info->colors[i].pixel = i; + XQueryColors (dpy, colormap, info->colors, ARRAY_LENGTH (info->colors)); + + /* Search for nearest colors within allocated colormap. */ + for (red = 0; red < 8; red++) { + for (green = 0; green < 8; green++) { + for (blue = 0; blue < 8; blue++) { + index = (red << 6) | (green << 3) | (blue); + for (i = 0; i < 256; i++) { + distance = _color_distance (index8_to_short[red], + index8_to_short[green], + index8_to_short[blue], + info->colors[i].red, + info->colors[i].green, + info->colors[i].blue); + if (i == 0 || distance < min_distance) { + info->rgb333_to_pseudocolor[index] = info->colors[i].pixel; + min_distance = distance; + } + } + } + } + } + + *out = info; + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_xlib_visual_info_destroy (Display *dpy, cairo_xlib_visual_info_t *info) +{ + /* No need for XFreeColors() whilst using DefaultColormap */ + free (info); +} diff --git a/gfx/cairo/cairo/src/cairo.c b/gfx/cairo/cairo/src/cairo.c index a0fbb4930a9..b540af3c2a0 100644 --- a/gfx/cairo/cairo/src/cairo.c +++ b/gfx/cairo/cairo/src/cairo.c @@ -2295,10 +2295,15 @@ cairo_in_fill (cairo_t *cr, double x, double y) * taken into account. * * Note that if the line width is set to exactly zero, then - * cairo_stroke_extents will return an empty rectangle. Contrast with + * cairo_stroke_extents() will return an empty rectangle. Contrast with * cairo_path_extents() which can be used to compute the non-empty * bounds as the line width approaches zero. * + * Note that cairo_stroke_extents() must necessarily do more work to + * compute the precise inked areas in light of the stroke parameters, + * so cairo_path_extents() may be more desirable for sake of + * performance if non-inked path extents are desired. + * * See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(), * cairo_set_line_cap(), cairo_set_dash(), and * cairo_stroke_preserve(). @@ -2344,8 +2349,13 @@ cairo_stroke_extents (cairo_t *cr, * dimensions and clipping are not taken into account. * * Contrast with cairo_path_extents(), which is similar, but returns - * non-zero extents for some paths no inked area, (such as a simple - * line segment). + * non-zero extents for some paths with no inked area, (such as a + * simple line segment). + * + * Note that cairo_fill_extents() must necessarily do more work to + * compute the precise inked areas in light of the fill rule, so + * cairo_path_extents() may be more desirable for sake of performance + * if the non-inked path extents are desired. * * See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve(). **/ diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index cf14e6f4a60..ab730e7ad9b 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -1148,7 +1148,7 @@ cairo_font_face_status (cairo_font_face_t *font_face); * @CAIRO_FONT_TYPE_TOY: The font was created using cairo's toy font api * @CAIRO_FONT_TYPE_FT: The font is of type FreeType * @CAIRO_FONT_TYPE_WIN32: The font is of type Win32 - * @CAIRO_FONT_TYPE_ATSUI: The font is of type ATSUI + * @CAIRO_FONT_TYPE_QUARTZ: The font is of type Quartz (Since: 1.6) * * #cairo_font_type_t is used to describe the type of a given font * face or scaled font. The font types are also known as "font @@ -1183,7 +1183,7 @@ typedef enum _cairo_font_type { CAIRO_FONT_TYPE_TOY, CAIRO_FONT_TYPE_FT, CAIRO_FONT_TYPE_WIN32, - CAIRO_FONT_TYPE_ATSUI + CAIRO_FONT_TYPE_QUARTZ } cairo_font_type_t; cairo_public cairo_font_type_t diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index 7e0b5bd4aed..8ea3e4934e6 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -147,6 +147,27 @@ do { \ */ #define CAIRO_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) +/* Return the number of 1 bits in mask. + * + * GCC 3.4 supports a "population count" builtin, which on many targets is + * implemented with a single instruction. There is a fallback definition + * in libgcc in case a target does not have one, which should be just as + * good as the open-coded solution below, (which is "HACKMEM 169"). + */ +static inline int +_cairo_popcount (uint32_t mask) +{ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return __builtin_popcount (mask); +#else + register int y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); +#endif +} + #ifdef WORDS_BIGENDIAN #define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) (c) #else @@ -217,7 +238,7 @@ cairo_private void _cairo_array_fini (cairo_array_t *array); cairo_private cairo_status_t -_cairo_array_grow_by (cairo_array_t *array, int additional); +_cairo_array_grow_by (cairo_array_t *array, unsigned int additional); cairo_private void _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements); @@ -439,9 +460,9 @@ extern const cairo_private struct _cairo_scaled_font_backend cairo_win32_scaled_ #endif -#if CAIRO_HAS_ATSUI_FONT +#if CAIRO_HAS_QUARTZ_FONT -extern const cairo_private struct _cairo_scaled_font_backend cairo_atsui_scaled_font_backend; +extern const cairo_private struct _cairo_scaled_font_backend cairo_quartz_scaled_font_backend; #endif @@ -776,7 +797,7 @@ typedef struct _cairo_surface_pattern { } cairo_surface_pattern_t; typedef struct _cairo_gradient_stop { - cairo_fixed_t x; + double offset; cairo_color_t color; } cairo_gradient_stop_t; @@ -848,7 +869,7 @@ typedef struct _cairo_traps { #define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL #define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial" -#define CAIRO_ATSUI_FONT_FAMILY_DEFAULT "Helvetica" +#define CAIRO_QUARTZ_FONT_FAMILY_DEFAULT "Helvetica" #define CAIRO_FT_FONT_FAMILY_DEFAULT "" #if CAIRO_HAS_WIN32_FONT @@ -856,10 +877,10 @@ typedef struct _cairo_traps { #define CAIRO_FONT_FAMILY_DEFAULT CAIRO_WIN32_FONT_FAMILY_DEFAULT #define CAIRO_SCALED_FONT_BACKEND_DEFAULT &cairo_win32_scaled_font_backend -#elif CAIRO_HAS_ATSUI_FONT +#elif CAIRO_HAS_QUARTZ_FONT -#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_ATSUI_FONT_FAMILY_DEFAULT -#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &cairo_atsui_scaled_font_backend +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_QUARTZ_FONT_FAMILY_DEFAULT +#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &cairo_quartz_scaled_font_backend #elif CAIRO_HAS_FT_FONT @@ -1736,6 +1757,9 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface, double tolerance, cairo_antialias_t antialias); +cairo_private cairo_clip_t * +_cairo_surface_get_clip (cairo_surface_t *surface); + cairo_private cairo_status_t _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip); @@ -1836,6 +1860,11 @@ _cairo_surface_has_device_transform (cairo_surface_t *surface); #define CAIRO_FORMAT_INVALID ((unsigned int) -1) #define CAIRO_FORMAT_VALID(format) ((format) <= CAIRO_FORMAT_A1) +/* pixman-required stride alignment in bytes. */ +#define CAIRO_STRIDE_ALIGNMENT (sizeof (uint32_t)) +#define CAIRO_STRIDE_FOR_WIDTH_BPP(w,bpp) \ + (((bpp)*(w)+7)/8 + CAIRO_STRIDE_ALIGNMENT-1) & ~(CAIRO_STRIDE_ALIGNMENT-1) + #define CAIRO_CONTENT_VALID(content) ((content) && \ (((content) & ~(CAIRO_CONTENT_COLOR | \ CAIRO_CONTENT_ALPHA | \ @@ -1855,15 +1884,13 @@ cairo_private cairo_surface_t * _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, pixman_format_code_t pixman_format); -cairo_private pixman_format_code_t -_pixman_format_from_masks (cairo_format_masks_t *masks); +cairo_private cairo_int_status_t +_pixman_format_from_masks (cairo_format_masks_t *masks, + pixman_format_code_t *format_ret); cairo_private void _pixman_format_to_masks (pixman_format_code_t pixman_format, - uint32_t *bpp, - uint32_t *red, - uint32_t *green, - uint32_t *blue); + cairo_format_masks_t *masks); cairo_private cairo_surface_t * _cairo_image_surface_create_with_pixman_format (unsigned char *data, @@ -2209,7 +2236,7 @@ _cairo_utf8_to_ucs4 (const unsigned char *str, uint32_t **result, int *items_written); -#if CAIRO_HAS_WIN32_FONT+0 || CAIRO_HAS_ATSUI_FONT+0 +#if CAIRO_HAS_WIN32_FONT+0 || CAIRO_HAS_QUARTZ_FONT+0 # define CAIRO_HAS_UTF8_TO_UTF16 1 #endif #if CAIRO_HAS_UTF8_TO_UTF16 @@ -2253,7 +2280,9 @@ slim_hidden_proto (cairo_get_matrix); slim_hidden_proto (cairo_get_tolerance); slim_hidden_proto (cairo_image_surface_create); slim_hidden_proto (cairo_image_surface_create_for_data); +slim_hidden_proto (cairo_image_surface_get_data); slim_hidden_proto (cairo_image_surface_get_height); +slim_hidden_proto (cairo_image_surface_get_stride); slim_hidden_proto (cairo_image_surface_get_width); slim_hidden_proto (cairo_format_stride_for_width); slim_hidden_proto (cairo_line_to); diff --git a/gfx/thebes/src/gfxAtsuiFonts.cpp b/gfx/thebes/src/gfxAtsuiFonts.cpp index f4f5d8d274c..eba26f5082a 100644 --- a/gfx/thebes/src/gfxAtsuiFonts.cpp +++ b/gfx/thebes/src/gfxAtsuiFonts.cpp @@ -54,7 +54,7 @@ #include "gfxFontTest.h" #include "gfxFontUtils.h" -#include "cairo-atsui.h" +#include "cairo-quartz.h" #include "gfxQuartzSurface.h" #include "gfxQuartzFontCache.h" @@ -116,7 +116,7 @@ gfxAtsuiFont::gfxAtsuiFont(MacOSFontEntry *aFontEntry, InitMetrics(fontID, fontRef); - mFontFace = cairo_atsui_font_face_create_for_atsu_font_id(fontID); + mFontFace = cairo_quartz_font_face_create_for_atsu_font_id(fontID); cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm);