summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cairo-array.c14
-rw-r--r--src/cairo-cache.c3
-rw-r--r--src/cairo-dwrite.h2
-rw-r--r--src/cairo-font-options.c37
-rw-r--r--src/cairo-ft-font.c53
-rw-r--r--src/cairo-gstate.c2
-rw-r--r--src/cairo-matrix.c9
-rw-r--r--src/cairo-pattern.c3
-rw-r--r--src/cairo-pdf-surface.c2
-rw-r--r--src/cairo-ps-surface.c2
-rw-r--r--src/cairo-quartz-image-surface.c169
-rw-r--r--src/cairo-quartz-private.h25
-rw-r--r--src/cairo-quartz-surface.c432
-rw-r--r--src/cairo-recording-surface.c5
-rwxr-xr-xsrc/cairo-scaled-font.c4
-rw-r--r--src/cairo-shape-mask-compositor.c6
-rw-r--r--src/cairo-surface-observer.c9
-rw-r--r--src/cairo-surface.c1
-rw-r--r--src/cairo-svg.h6
-rw-r--r--src/cairo-tee-surface-private.h47
-rw-r--r--src/cairo-tee-surface.c41
-rw-r--r--src/cairo-truetype-subset.c6
-rw-r--r--src/cairo.c28
-rw-r--r--src/cairo.h30
-rw-r--r--src/cairoint.h4
-rw-r--r--src/win32/cairo-dwrite-font.cpp415
-rw-r--r--src/win32/cairo-dwrite-private.hpp51
-rw-r--r--src/win32/cairo-win32-font.c8
-rw-r--r--src/win32/cairo-win32-private.h4
-rw-r--r--src/win32/dw-extra.h159
30 files changed, 697 insertions, 880 deletions
diff --git a/src/cairo-array.c b/src/cairo-array.c
index db7b6de7a..1c91b7c73 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -143,7 +143,6 @@ _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
/**
* _cairo_array_index:
* @array: a #cairo_array_t
- * Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
@@ -161,6 +160,8 @@ _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... use values[i] here ...
* </programlisting></informalexample>
+ *
+ * Returns: A pointer to the object stored at @index.
**/
void *
_cairo_array_index (cairo_array_t *array, unsigned int index)
@@ -187,7 +188,6 @@ _cairo_array_index (cairo_array_t *array, unsigned int index)
/**
* _cairo_array_index_const:
* @array: a #cairo_array_t
- * Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
@@ -205,6 +205,8 @@ _cairo_array_index (cairo_array_t *array, unsigned int index)
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... read values[i] here ...
* </programlisting></informalexample>
+ *
+ * Returns: A pointer to the object stored at @index.
**/
const void *
_cairo_array_index_const (const cairo_array_t *array, unsigned int index)
@@ -330,9 +332,10 @@ _cairo_array_allocate (cairo_array_t *array,
/**
* _cairo_array_num_elements:
* @array: a #cairo_array_t
- * Returns: The number of elements stored in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
+ *
+ * Returns: The number of elements stored in @array.
**/
unsigned int
_cairo_array_num_elements (const cairo_array_t *array)
@@ -343,10 +346,11 @@ _cairo_array_num_elements (const cairo_array_t *array)
/**
* _cairo_array_size:
* @array: a #cairo_array_t
- * Returns: The number of elements for which there is currently space
- * allocated in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
+ *
+ * Returns: The number of elements for which there is currently space
+ * allocated in @array.
**/
unsigned int
_cairo_array_size (const cairo_array_t *array)
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index be1285a20..afdca984e 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -56,7 +56,6 @@ _cairo_cache_entry_is_non_zero (const void *entry)
* @keys_equal: a function to return %TRUE if two keys are equal
* @entry_destroy: destroy notifier for cache entries
* @max_size: the maximum size for this cache
- * Returns: the newly created #cairo_cache_t
*
* Creates a new cache using the keys_equal() function to determine
* the equality of entries.
@@ -84,6 +83,8 @@ _cairo_cache_entry_is_non_zero (const void *entry)
* _cairo_cache_freeze() and _cairo_cache_thaw() calls can be
* used to establish a window during which no automatic removal of
* entries will occur.
+ *
+ * Returns: the newly created #cairo_cache_t
**/
cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
diff --git a/src/cairo-dwrite.h b/src/cairo-dwrite.h
index 630fcf280..b1ff718a0 100644
--- a/src/cairo-dwrite.h
+++ b/src/cairo-dwrite.h
@@ -51,7 +51,7 @@ cairo_public IDWriteRenderingParams *
cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face);
cairo_public void
-cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *param);
+cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *params);
cairo_public DWRITE_MEASURING_MODE
cairo_dwrite_font_face_get_measuring_mode (cairo_font_face_t *font_face);
diff --git a/src/cairo-font-options.c b/src/cairo-font-options.c
index 361882ae5..33ee617b8 100644
--- a/src/cairo-font-options.c
+++ b/src/cairo-font-options.c
@@ -105,6 +105,41 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
}
}
+cairo_bool_t
+_cairo_font_options_compare (const cairo_font_options_t *a,
+ const cairo_font_options_t *b)
+{
+ if (a->antialias != b->antialias ||
+ a->subpixel_order != b->subpixel_order ||
+ a->lcd_filter != b->lcd_filter ||
+ a->hint_style != b->hint_style ||
+ a->hint_metrics != b->hint_metrics ||
+ a->round_glyph_positions != b->round_glyph_positions ||
+ a->color_mode != b->color_mode ||
+ a->palette_index != b->palette_index ||
+ a->custom_palette_size != b->custom_palette_size)
+ {
+ return FALSE;
+ }
+
+ if (a->variations && b->variations && strcmp (a->variations, b->variations) != 0)
+ return FALSE;
+ else if (a->variations != b->variations)
+ return FALSE;
+
+ if (a->custom_palette && b->custom_palette &&
+ memcmp (a->custom_palette, b->custom_palette, sizeof (cairo_palette_color_t) * a->custom_palette_size) != 0)
+ {
+ return FALSE;
+ }
+ else if (a->custom_palette != b->custom_palette)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/**
* cairo_font_options_create:
*
@@ -662,7 +697,7 @@ cairo_font_options_get_variations (cairo_font_options_t *options)
/**
* cairo_font_options_set_color_mode:
* @options: a #cairo_font_options_t
- * @font_color: the new color mode
+ * @color_mode: the new color mode
*
* Sets the color mode for the font options object. This controls
* whether color fonts are to be rendered in color or as outlines.
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 75d6f8c16..22a6a622b 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -3408,7 +3408,6 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
int load_flags = scaled_font->ft_options.load_flags;
cairo_bool_t vertical_layout = FALSE;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_bool_t scaled_glyph_loaded = FALSE;
cairo_ft_glyph_private_t *glyph_priv;
int color_flag = 0;
@@ -3528,46 +3527,20 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
cairo_path_fixed_t *path = NULL; /* hide compiler warning */
- if (scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) {
- path = _cairo_path_fixed_create ();
- if (!path) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto FAIL;
- }
-
- status = _cairo_recording_surface_get_path (scaled_glyph->recording_surface, path);
- if (unlikely (status)) {
- _cairo_path_fixed_destroy (path);
- goto FAIL;
- }
-
- } else {
- /*
- * A kludge -- the above code will trash the outline,
- * so reload it. This will probably never occur though
- */
- if ((info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) != 0) {
- scaled_glyph_loaded = FALSE;
- load_flags |= FT_LOAD_NO_BITMAP;
- }
-
- if (!scaled_glyph_loaded) {
- status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
- scaled_glyph,
- face,
- load_flags,
- FALSE,
- vertical_layout);
- if (unlikely (status))
- goto FAIL;
- }
+ /* Load non-color glyph */
+ status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ load_flags,
+ FALSE,
+ vertical_layout);
+ if (unlikely (status))
+ goto FAIL;
- if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
- status = _cairo_ft_face_decompose_glyph_outline (face, &path);
- } else {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- }
- }
+ if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
+ status = _cairo_ft_face_decompose_glyph_outline (face, &path);
+ else
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (status))
goto FAIL;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 0f4fd541a..8a253468d 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1748,7 +1748,7 @@ void
_cairo_gstate_set_font_options (cairo_gstate_t *gstate,
const cairo_font_options_t *options)
{
- if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0)
+ if (_cairo_font_options_compare (options, &gstate->font_options))
return;
_cairo_gstate_unset_scaled_font (gstate);
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index cb49adcbe..e8fd097ae 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -373,15 +373,10 @@ _cairo_matrix_multiply (cairo_matrix_t *r,
* the returned vector is as follows:
*
* <programlisting>
- * dx2 = dx1 * a + dy1 * c;
- * dy2 = dx1 * b + dy1 * d;
+ * dx_new = xx * dx + xy * dy;
+ * dy_new = yx * dx + yy * dy;
* </programlisting>
*
- * Affine transformations are position invariant, so the same vector
- * always transforms to the same vector. If (@x1,@y1) transforms
- * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
- * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
- *
* Since: 1.0
**/
void
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index d16ed2836..2c0ba31f8 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -3439,9 +3439,10 @@ use_bilinear(double x, double y, double t)
/**
* _cairo_pattern_analyze_filter:
* @pattern: surface pattern
- * Returns: the optimized #cairo_filter_t to use with @pattern.
*
* Possibly optimize the filter to a simpler value depending on transformation
+ *
+ * Returns: the optimized #cairo_filter_t to use with @pattern.
**/
cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern)
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 772828eb8..2b1bf72e4 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2556,7 +2556,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
cairo_pdf_surface_t *surface = abstract_surface;
long long offset;
cairo_pdf_resource_t catalog;
- cairo_status_t status, status2;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
int size, i;
cairo_pdf_jbig2_global_t *global;
char *label;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index abc9407ee..381b4cf75 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -148,7 +148,7 @@ static char *ctime_r(const time_t *timep, char *buf)
* ury]" that specifies the bounding box (in PS coordinates) of the
* EPS graphics. The parameters are: lower left x, lower left y, upper
* right x, upper right y. Normally the bbox data is identical to the
- * %%%BoundingBox data in the EPS file.
+ * \%\%\%BoundingBox data in the EPS file.
*
**/
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 30d92d6be..d09f5b5bc 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -49,12 +49,6 @@
#define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE)))
#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
-static void
-DataProviderReleaseCallback (void *image_info, const void *data, size_t size)
-{
- free (image_info);
-}
-
static cairo_surface_t *
_cairo_quartz_image_surface_create_similar (void *asurface,
cairo_content_t content,
@@ -87,8 +81,9 @@ _cairo_quartz_image_surface_finish (void *asurface)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
- CGImageRelease (surface->image);
- cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface);
+ CGContextRelease (surface->cgContext);
+ if (surface->imageSurface)
+ cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface);
return CAIRO_STATUS_SUCCESS;
}
@@ -134,47 +129,6 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
return TRUE;
}
-/* we assume some drawing happened to the image buffer; make sure it's
- * represented in the CGImage on flush()
- */
-
-static cairo_status_t
-_cairo_quartz_image_surface_flush (void *asurface,
- unsigned flags)
-{
- cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
- CGImageRef oldImage = surface->image;
- CGImageRef newImage = NULL;
- void *image_data;
- const unsigned int size = surface->imageSurface->height * surface->imageSurface->stride;
- if (flags)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX only flush if the image has been modified. */
-
- image_data = _cairo_malloc_ab ( surface->imageSurface->height,
- surface->imageSurface->stride);
- if (unlikely (!image_data))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memcpy (image_data, surface->imageSurface->data,
- surface->imageSurface->height * surface->imageSurface->stride);
- newImage = CairoQuartzCreateCGImage (surface->imageSurface->format,
- surface->imageSurface->width,
- surface->imageSurface->height,
- surface->imageSurface->stride,
- image_data,
- TRUE,
- NULL,
- DataProviderReleaseCallback,
- image_data);
-
- surface->image = newImage;
- CGImageRelease (oldImage);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_quartz_image_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -275,7 +229,7 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
_cairo_quartz_image_surface_get_extents,
NULL, /* get_font_options */
- _cairo_quartz_image_surface_flush,
+ NULL, /*surface_flush */
NULL, /* mark_dirty_rectangle */
_cairo_quartz_image_surface_paint,
@@ -290,12 +244,9 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
* cairo_quartz_image_surface_create:
* @image_surface: a cairo image surface to wrap with a quartz image surface
*
- * Creates a Quartz surface backed by a CGImageRef that references the
+ * Creates a Quartz surface backed by a CGBitmapContext that references the
* given image surface. The resulting surface can be rendered quickly
- * when used as a source when rendering to a #cairo_quartz_surface. If
- * the data in the image surface is ever updated, cairo_surface_flush()
- * must be called on the #cairo_quartz_image_surface to ensure that the
- * CGImageRef refers to the updated data.
+ * when used as a source when rendering to a #cairo_quartz_surface.
*
* Return value: the newly created surface.
*
@@ -305,13 +256,11 @@ cairo_surface_t *
cairo_quartz_image_surface_create (cairo_surface_t *surface)
{
cairo_quartz_image_surface_t *qisurf;
-
- CGImageRef image;
-
cairo_image_surface_t *image_surface;
int width, height, stride;
cairo_format_t format;
- void *image_data;
+ CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
+ CGColorSpaceRef colorspace;
if (surface->status)
return surface;
@@ -338,54 +287,100 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
if (qisurf == NULL)
return SURFACE_ERROR_NO_MEMORY;
- memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
-
- image_data = _cairo_malloc_ab (height, stride);
- if (unlikely (!image_data)) {
- free(qisurf);
- return SURFACE_ERROR_NO_MEMORY;
- }
-
- memcpy (image_data, image_surface->data, height * stride);
- image = CairoQuartzCreateCGImage (format,
- width, height,
- stride,
- image_data,
- TRUE,
- NULL,
- DataProviderReleaseCallback,
- image_data);
-
- if (!image) {
- free (qisurf);
- return SURFACE_ERROR_NO_MEMORY;
- }
-
_cairo_surface_init (&qisurf->base,
&cairo_quartz_image_surface_backend,
NULL, /* device */
_cairo_content_from_format (format),
FALSE); /* is_vector */
+ if (_cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface)) {
+ CGContextRef context = cairo_quartz_surface_get_cg_context(surface);
+ colorspace = _cairo_quartz_create_color_space (context);
+ }
+ else {
+ colorspace = CGDisplayCopyColorSpace (CGMainDisplayID ());
+ }
+
+ bitinfo |= format == CAIRO_FORMAT_ARGB32 ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
+
qisurf->width = width;
qisurf->height = height;
- qisurf->image = image;
+ qisurf->cgContext = CGBitmapContextCreate (image_surface->data, width, height, 8, image_surface->stride,
+ colorspace, bitinfo);
qisurf->imageSurface = (cairo_image_surface_t*) cairo_surface_reference(surface);
+ CGColorSpaceRelease (colorspace);
return &qisurf->base;
}
+/**
+ * cairo_quartz_image_surface_get_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Returns a #cairo_surface_t image surface that refers to the same bits
+ * as the image of the quartz surface.
+ *
+ * Return value: a #cairo_surface_t (owned by the quartz #cairo_surface_t),
+ * or %NULL if the quartz surface is not an image surface.
+ *
+ * Since: 1.6
+ */
cairo_surface_t *
-cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
+cairo_quartz_image_surface_get_image (cairo_surface_t *surface)
{
- cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
+ cairo_quartz_image_surface_t *qsurface = (cairo_quartz_image_surface_t*) surface;
/* Throw an error for a non-quartz surface */
- if (! _cairo_surface_is_quartz (asurface)) {
+ if (! _cairo_surface_is_quartz (surface)) {
return SURFACE_ERROR_TYPE_MISMATCH;
}
- return (cairo_surface_t*) surface->imageSurface;
+ return (cairo_surface_t*) qsurface->imageSurface;
+}
+
+/*
+ * _cairo_quartz_image_surface_get_cg_context:
+ * @surface: the Cairo Quartz surface
+ *
+ * Returns the CGContextRef that the given Quartz surface is backed
+ * by.
+ *
+ * A call to cairo_surface_flush() is required before using the
+ * CGContextRef to ensure that all pending drawing operations are
+ * finished and to restore any temporary modification cairo has made
+ * to its state. A call to cairo_surface_mark_dirty() is required
+ * after the state or the content of the CGContextRef has been
+ * modified.
+ *
+ * Return value: the CGContextRef for the given surface.
+ *
+ **/
+CGContextRef
+_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface)
+{
+ if (surface && _cairo_surface_is_quartz_image (surface)) {
+ cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
+ return quartz->cgContext;
+ } else
+ return NULL;
+}
+
+/*
+ * _cairo_surface_is_quartz_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_quartz_surface_t
+ *
+ * Return value: True if the surface is an quartz surface
+ **/
+cairo_bool_t
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface) {
+ return surface->backend == &cairo_quartz_image_surface_backend;
+}
+
+cairo_bool_t
+_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface) {
+ return surface->width == 0 || surface->height == 0;
}
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index f142f8471..bdfdf8c2b 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -81,8 +81,7 @@ typedef struct cairo_quartz_image_surface {
cairo_surface_t base;
int width, height;
-
- CGImageRef image;
+ CGContextRef cgContext;
cairo_image_surface_t *imageSurface;
} cairo_quartz_image_surface_t;
@@ -92,16 +91,15 @@ _cairo_quartz_verify_surface_size(int width, int height);
cairo_private cairo_bool_t
_cairo_surface_is_quartz (const cairo_surface_t *surface);
-cairo_private CGImageRef
-CairoQuartzCreateCGImage (cairo_format_t format,
- unsigned int width,
- unsigned int height,
- unsigned int stride,
- void *data,
- cairo_bool_t interpolate,
- CGColorSpaceRef colorSpaceOverride,
- CGDataProviderReleaseDataCallback releaseCallback,
- void *releaseInfo);
+cairo_private cairo_bool_t
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface);
+cairo_private cairo_bool_t
+_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface);
+
+cairo_private CGColorSpaceRef
+_cairo_quartz_create_color_space (CGContextRef context);
+cairo_private CGContextRef
+_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface);
cairo_private CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
@@ -112,6 +110,9 @@ _cairo_quartz_font_face_create_for_ctfont (CTFontRef ctFont);
cairo_private void
_cairo_quartz_set_antialiasing (CGContextRef context, cairo_antialias_t antialias);
+cairo_status_t _cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest);
+cairo_private void _cairo_quartz_image_to_png (CGImageRef, const char *dest);
+
#else
# error Cairo was not compiled with support for the quartz backend
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index dbb6aa46f..d8a8065d0 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
#include "cairo-quartz-private.h"
+#include "cairo-quartz-image.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
@@ -55,6 +56,7 @@
#endif
#include <limits.h>
+#include <assert.h>
#undef QUARTZ_DEBUG
@@ -64,13 +66,30 @@
#define ND(_x) do {} while(0)
#endif
-#define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation
#else
#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
#endif
+static inline cairo_bool_t
+_is_quartz_surface (cairo_surface_t *surface) {
+ return _cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface);
+}
+
+static inline cairo_bool_t
+_cairo_quartz_surface_is_zero (cairo_quartz_surface_t* surface) {
+ return surface->extents.width == 0 || surface->extents.height == 0;
+}
+
+static inline cairo_bool_t
+_cairo_quartz_is_zero_surface (cairo_surface_t* surface) {
+ assert (_is_quartz_surface (surface));
+ if (_cairo_surface_is_quartz (surface))
+ return (_cairo_quartz_surface_is_zero ((cairo_quartz_surface_t*) surface));
+ else
+ return (_cairo_quartz_image_surface_is_zero ((cairo_quartz_image_surface_t*) surface));
+}
/**
* SECTION:cairo-quartz
@@ -94,6 +113,20 @@
/*
* macOS Private functions
*/
+typedef enum {
+ kCGContextTypeUnknown,
+ kCGContextTypePDF,
+ kCGContextTypePostScript,
+ kCGContextTypeWindow,
+ kCGContextTypeBitmap,
+ kCGContextTypeGL,
+ kCGContextTypeDisplayList,
+ kCGContextTypeKSeparation,
+ kCGContextTypeIOSurface,
+ kCGContextTypeCount
+} CGContextType;
+
+
static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
static void
@@ -108,20 +141,15 @@ quartz_ensure_symbols()
}
}
-#ifdef QUARTZ_DEBUG
-static void quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest);
-static void quartz_image_to_png (CGImageRef, const char *dest);
-#endif
-
typedef struct
{
cairo_surface_t base;
CGImageRef image;
} cairo_quartz_snapshot_t;
-static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface);
-static cairo_status_t _cairo_quartz_snapshot_finish (void* surface);
-static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface);
+static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_surface_t *surface);
+static cairo_status_t _cairo_quartz_snapshot_finish (void *surface);
+static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface);
static const cairo_surface_backend_t cairo_quartz_snapshot_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_QUARTZ_SNAPSHOT,
@@ -134,102 +162,72 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
unsigned int width,
unsigned int height);
-CGImageRef
-CairoQuartzCreateCGImage (cairo_format_t format,
- unsigned int width,
- unsigned int height,
- unsigned int stride,
- void *data,
- cairo_bool_t interpolate,
- CGColorSpaceRef colorSpaceOverride,
- CGDataProviderReleaseDataCallback releaseCallback,
- void *releaseInfo)
+CGColorSpaceRef
+_cairo_quartz_create_color_space (CGContextRef context)
{
- CGImageRef image = NULL;
- CGDataProviderRef dataProvider = NULL;
- CGColorSpaceRef colorSpace = colorSpaceOverride;
- CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
- int bitsPerComponent, bitsPerPixel;
-
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- if (colorSpace == NULL)
- colorSpace = CGColorSpaceCreateDeviceRGB ();
- bitinfo |= kCGImageAlphaPremultipliedFirst;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- break;
-
- case CAIRO_FORMAT_RGB24:
- if (colorSpace == NULL)
- colorSpace = CGColorSpaceCreateDeviceRGB ();
- bitinfo |= kCGImageAlphaNoneSkipFirst;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- break;
-
- case CAIRO_FORMAT_A8:
- bitsPerComponent = 8;
- bitsPerPixel = 8;
- break;
+ CGColorSpaceRef color_space = NULL;
+ CGContextType cgtype = kCGContextTypeUnknown;
- case CAIRO_FORMAT_A1:
-#ifdef WORDS_BIGENDIAN
- bitsPerComponent = 1;
- bitsPerPixel = 1;
- break;
-#endif
-
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_RGB16_565:
- case CAIRO_FORMAT_RGB96F:
- case CAIRO_FORMAT_RGBA128F:
- case CAIRO_FORMAT_INVALID:
- default:
- return NULL;
- }
-
- dataProvider = CGDataProviderCreateWithData (releaseInfo,
- data,
- height * stride,
- releaseCallback);
-
- if (unlikely (!dataProvider)) {
- // manually release
- if (releaseCallback)
- releaseCallback (releaseInfo, data, height * stride);
- goto FINISH;
+ if (context)
+ {
+ if (CGBitmapContextGetBitsPerPixel (context) < 24)
+ return 0;
+
+ quartz_ensure_symbols();
+ cgtype = CGContextGetTypePtr (context);
+ switch (cgtype)
+ {
+ case kCGContextTypeUnknown:
+ break;
+ case kCGContextTypePDF:
+ color_space = CGColorSpaceCreateDeviceRGB ();
+ break;
+ case kCGContextTypePostScript:
+ case kCGContextTypeWindow:
+ break;
+ case kCGContextTypeBitmap:
+ color_space = CGBitmapContextGetColorSpace (context);
+ color_space = CGColorSpaceRetain (color_space);
+ break;
+ case kCGContextTypeGL:
+ case kCGContextTypeDisplayList:
+ case kCGContextTypeKSeparation:
+ case kCGContextTypeIOSurface:
+ case kCGContextTypeCount:
+ default:
+ break;
+ }
+ if (color_space)
+ return color_space;
}
+ if (!color_space)
+ color_space = CGDisplayCopyColorSpace (CGMainDisplayID ());
- if (format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) {
- cairo_quartz_float_t decode[] = {1.0, 0.0};
- image = CGImageMaskCreate (width, height,
- bitsPerComponent,
- bitsPerPixel,
- stride,
- dataProvider,
- decode,
- interpolate);
- } else
- image = CGImageCreate (width, height,
- bitsPerComponent,
- bitsPerPixel,
- stride,
- colorSpace,
- bitinfo,
- dataProvider,
- NULL,
- interpolate,
- kCGRenderingIntentDefault);
-
-FINISH:
+ if (!color_space)
+ color_space = CGColorSpaceCreateDeviceRGB ();
- CGDataProviderRelease (dataProvider);
+ return color_space;
+}
- if (colorSpace != colorSpaceOverride)
- CGColorSpaceRelease (colorSpace);
+static CGColorRef
+_cairo_quartz_create_cgcolor (CGColorSpaceRef cs, CGFloat red, CGFloat green,
+ CGFloat blue, CGFloat alpha)
+{
+ CGFloat colors[4] = { red, green, blue, alpha };
+ CGColorRef cgc;
+ if (!CGColorSpaceRetain(cs))
+ {
+ cs = _cairo_quartz_create_color_space (NULL);
+ }
+ cgc = CGColorCreate (cs, colors);
+ CGColorSpaceRelease (cs);
+ return cgc;
+}
- return image;
+static CGColorRef
+_cairo_quartz_black (CGColorSpaceRef cs)
+{
+ return _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 1.0);
}
static inline cairo_bool_t
@@ -241,7 +239,7 @@ _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc)
quartz_ensure_symbols ();
if (likely (CGContextGetTypePtr)) {
/* 4 is the type value of a bitmap context */
- return CGContextGetTypePtr (cgc) == 4;
+ return CGContextGetTypePtr (cgc) == kCGContextTypeBitmap;
}
/* This will cause a (harmless) warning to be printed if called on a non-bitmap context */
@@ -682,12 +680,6 @@ CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient,
&gradient_callbacks);
}
-static void
-DataProviderReleaseCallback (void *info, const void *data, size_t size)
-{
- free (info);
-}
-
static cairo_status_t
_cairo_surface_to_cgimage (cairo_surface_t *source,
cairo_rectangle_int_t *extents,
@@ -697,25 +689,19 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
CGImageRef *image_out)
{
cairo_status_t status;
- cairo_image_surface_t *image_surface;
- void *image_data, *image_extra;
+ cairo_quartz_image_surface_t *image_surface;
+ void *image_extra;
cairo_bool_t acquired = FALSE;
- if (source->backend && source->backend->type == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
- cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
- *image_out = CGImageRetain (surface->image);
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (_cairo_surface_is_quartz (source)) {
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
- if (IS_EMPTY (surface)) {
+ if (_is_quartz_surface (source)) {
+ CGContextRef cgContext = cairo_quartz_surface_get_cg_context(source);
+ if (_cairo_quartz_is_zero_surface (source)) {
*image_out = NULL;
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
- if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
- *image_out = _cairo_quartz_surface_snapshot_get_image (surface);
+ if (_cairo_quartz_is_cgcontext_bitmap_context (cgContext)) {
+ *image_out = _cairo_quartz_surface_snapshot_get_image (source);
return CAIRO_STATUS_SUCCESS;
}
@@ -724,80 +710,60 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
}
if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
- image_surface = (cairo_image_surface_t *)
- cairo_image_surface_create (format, extents->width, extents->height);
- if (unlikely (image_surface->base.status)) {
- status = image_surface->base.status;
- cairo_surface_destroy (&image_surface->base);
+ cairo_image_surface_t *surface =
+ (cairo_image_surface_t*)cairo_image_surface_create (format, extents->width,
+ extents->height);
+ if (unlikely (surface->base.status)) {
+ status = surface->base.status;
+ cairo_surface_destroy (&surface->base);
return status;
}
status = _cairo_recording_surface_replay_with_clip (source,
matrix,
- &image_surface->base,
+ &surface->base,
NULL,
FALSE);
if (unlikely (status)) {
- cairo_surface_destroy (&image_surface->base);
+ cairo_surface_destroy (&surface->base);
return status;
}
+ image_surface =
+ (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
cairo_matrix_init_identity (matrix);
}
else {
- status = _cairo_surface_acquire_source_image (source, &image_surface,
+ cairo_image_surface_t *surface;
+ status = _cairo_surface_acquire_source_image (source, &surface,
&image_extra);
if (unlikely (status))
return status;
- acquired = TRUE;
- }
-
- if (image_surface->width == 0 || image_surface->height == 0) {
- *image_out = NULL;
- if (acquired)
- _cairo_surface_release_source_image (source, image_surface, image_extra);
+ image_surface =
+ (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
+ status = image_surface->base.status;
+ if (status)
+ _cairo_surface_release_source_image (source, surface, image_extra);
else
- cairo_surface_destroy (&image_surface->base);
-
- return status;
+ acquired = TRUE;
}
- image_data = _cairo_malloc_ab (image_surface->height, image_surface->stride);
- if (unlikely (!image_data))
- {
- if (acquired)
- _cairo_surface_release_source_image (source, image_surface, image_extra);
- else
- cairo_surface_destroy (&image_surface->base);
-
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ *image_out = NULL;
+ if (image_surface->width > 0 && image_surface->height > 0) {
+ *image_out = _cairo_quartz_surface_snapshot_get_image (&image_surface->base);
+ status = CAIRO_STATUS_SUCCESS;
}
- // The last row of data may have less than stride bytes so make sure we
- // only copy the minimum amount required from that row.
- memcpy (image_data, image_surface->data,
- (image_surface->height - 1) * image_surface->stride +
- cairo_format_stride_for_width (image_surface->format,
- image_surface->width));
- *image_out = CairoQuartzCreateCGImage (image_surface->format,
- image_surface->width,
- image_surface->height,
- image_surface->stride,
- image_data,
- TRUE,
- NULL,
- DataProviderReleaseCallback,
- image_data);
+ if (acquired) {
+ _cairo_surface_release_source_image (source, image_surface->imageSurface, image_extra);
+ image_surface->imageSurface = NULL;
+ }
+ cairo_surface_destroy (&image_surface->base);
/* TODO: differentiate memory error and unsupported surface type */
if (unlikely (*image_out == NULL))
status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (acquired)
- _cairo_surface_release_source_image (source, image_surface, image_extra);
- else
- cairo_surface_destroy (&image_surface->base);
-
return status;
}
@@ -993,6 +959,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state,
CGColorSpaceRef patternSpace;
CGPatternRef cgpat = NULL;
cairo_int_status_t status;
+ CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (state->cgDrawContext));
_cairo_surface_get_extents (&surface->base, &extents);
@@ -1048,7 +1015,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state,
-state->clipRect.origin.y);
}
- CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+ CGContextSetFillColorWithColor (state->cgDrawContext, black);
state->rect = CGRectMake (0, 0, pattern_extents.width, pattern_extents.height);
state->action = DO_IMAGE;
@@ -1087,6 +1054,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state,
CGContextSetPatternPhase (state->cgDrawContext, CGSizeMake (0, 0));
CGPatternRelease (cgpat);
+ CGColorRelease (black);
state->action = DO_DIRECT;
return CAIRO_STATUS_SUCCESS;
@@ -1126,7 +1094,7 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
if (unlikely (gradFunc == NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
- rgb = CGColorSpaceCreateDeviceRGB ();
+ rgb = _cairo_quartz_create_color_space (NULL);
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
state->shading = CGShadingCreateAxial (rgb,
@@ -1197,9 +1165,11 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
state->filter = _cairo_quartz_filter_to_quartz (source->filter);
if (op == CAIRO_OPERATOR_CLEAR) {
- CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+ CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (surface->cgContext));
+ CGContextSetFillColorWithColor (state->cgDrawContext, black);
state->action = DO_DIRECT;
+ CGColorRelease (black);
return CAIRO_STATUS_SUCCESS;
}
@@ -1236,18 +1206,17 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
+ CGColorRef color = _cairo_quartz_create_cgcolor (_cairo_quartz_create_color_space (state->cgDrawContext),
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue,
+ solid->color.alpha);
+
- CGContextSetRGBStrokeColor (state->cgDrawContext,
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
- CGContextSetRGBFillColor (state->cgDrawContext,
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
+ CGContextSetStrokeColorWithColor (state->cgDrawContext, color);
+ CGContextSetFillColorWithColor (state->cgDrawContext, color);
+ CGColorRelease (color);
state->action = DO_DIRECT;
return CAIRO_STATUS_SUCCESS;
}
@@ -1301,6 +1270,9 @@ static inline void
_cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state,
cairo_operator_t op)
{
+ CGColorSpaceRef cs = _cairo_quartz_create_color_space (state->cgDrawContext);
+ CGColorRef transparent = _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 0.0); //releases cs
+
if (! (op == CAIRO_OPERATOR_SOURCE &&
state->cgDrawContext == state->cgMaskContext))
return;
@@ -1315,8 +1287,9 @@ _cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state,
CGContextAddRect (state->cgDrawContext, state->clipRect);
- CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 0);
+ CGContextSetFillColorWithColor (state->cgDrawContext, transparent);
CGContextEOFillPath (state->cgDrawContext);
+ CGColorRelease (transparent);
}
@@ -1367,7 +1340,7 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface,
unsigned char *imageData;
cairo_format_t format;
- if (IS_EMPTY (surface))
+ if (_cairo_quartz_is_zero_surface (&surface->base))
return (cairo_image_surface_t *) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
if (! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext))
@@ -1377,8 +1350,9 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface,
bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext);
// let's hope they don't add YUV under us
- colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
+ colorspace = _cairo_quartz_create_color_space (surface->cgContext);
color_comps = CGColorSpaceGetNumberOfComponents (colorspace);
+ CGColorSpaceRelease (colorspace);
/* XXX TODO: We can handle many more data formats by
* converting to pixman_format_t */
@@ -1439,7 +1413,7 @@ _cairo_quartz_surface_finish (void *abstract_surface)
ND ((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext));
- if (IS_EMPTY (surface))
+ if (_cairo_quartz_is_zero_surface (&surface->base))
return CAIRO_STATUS_SUCCESS;
/* Restore our saved gstate that we use to reset clipping */
@@ -2086,7 +2060,7 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip
ND ((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
- if (IS_EMPTY (surface))
+ if (_cairo_quartz_is_zero_surface (&surface->base))
return CAIRO_STATUS_SUCCESS;
if (path == NULL) {
@@ -2184,7 +2158,7 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
surface->extents.height = height;
surface->virtual_extents = surface->extents;
- if (IS_EMPTY (surface)) {
+ if (_cairo_quartz_is_zero_surface (&surface->base)) {
surface->cgContext = NULL;
surface->cgContextBaseCTM = CGAffineTransformIdentity;
surface->base.is_clear = TRUE;
@@ -2234,10 +2208,9 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height)
{
- cairo_quartz_surface_t *surf;
-
- surf = _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA,
- width, height);
+ cairo_quartz_surface_t *surf =
+ _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA,
+ width, height);
if (likely (!surf->base.status))
CGContextRetain (cgContext);
@@ -2250,8 +2223,14 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
*
- * Creates a Quartz surface backed by a CGBitmap. The surface is
- * created using the Device RGB (or Device Gray, for A8) color space.
+ * Creates a Quartz surface backed by a CGBitmapContext using the main
+ * display's colorspace to avoid an expensive colorspace transform
+ * done serially on the CPU. This may produce slightly different
+ * colors from what's intended. Programs for which color management is
+ * important should create their own CGBitmapContext with a
+ * device-independent color space; most will expect Cairo to draw in
+ * sRGB and would use CGColorSpaceCreateWithName(kCGColorSpaceSRGB).
+ *
* All Cairo operations, including those that require software
* rendering, will succeed on this surface.
*
@@ -2283,7 +2262,7 @@ cairo_quartz_surface_create (cairo_format_t format,
if (format == CAIRO_FORMAT_ARGB32 ||
format == CAIRO_FORMAT_RGB24)
{
- cgColorspace = CGColorSpaceCreateDeviceRGB ();
+ cgColorspace = _cairo_quartz_create_color_space (NULL);
bitinfo = kCGBitmapByteOrder32Host;
if (format == CAIRO_FORMAT_ARGB32)
bitinfo |= kCGImageAlphaPremultipliedFirst;
@@ -2372,8 +2351,14 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
if (surface && _cairo_surface_is_quartz (surface)) {
cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
return quartz->cgContext;
- } else
- return NULL;
+ }
+
+ if (surface && _cairo_surface_is_quartz_image (surface)) {
+ cairo_quartz_image_surface_t *quartz = (cairo_quartz_image_surface_t *) surface;
+ return quartz->cgContext;
+ }
+
+ return NULL;
}
/**
@@ -2391,12 +2376,15 @@ _cairo_surface_is_quartz (const cairo_surface_t *surface)
}
cairo_surface_t*
-_cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface)
+_cairo_quartz_snapshot_create (cairo_surface_t *surface)
{
cairo_quartz_snapshot_t *snapshot = NULL;
+ CGContextRef cgContext;
+ if (!surface || ! _is_quartz_surface (surface) || _cairo_quartz_is_zero_surface (surface))
+ return NULL;
- if (!surface || !_cairo_surface_is_quartz (&surface->base) || IS_EMPTY (surface) ||
- ! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext))
+ if (_cairo_surface_is_quartz (surface) &&
+ ! _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)surface)->cgContext))
return NULL;
snapshot = _cairo_malloc (sizeof (cairo_quartz_snapshot_t));
@@ -2405,10 +2393,13 @@ _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
memset (snapshot, 0, sizeof (cairo_quartz_snapshot_t));
+ cgContext = cairo_quartz_surface_get_cg_context (surface);
_cairo_surface_init (&snapshot->base,
&cairo_quartz_snapshot_backend,
NULL, CAIRO_CONTENT_COLOR_ALPHA, FALSE);
- snapshot->image = CGBitmapContextCreateImage (surface->cgContext);
+ snapshot->image = CGBitmapContextCreateImage (cgContext);
+ _cairo_surface_attach_snapshot (surface, &snapshot->base, NULL);
+ cairo_surface_destroy (&snapshot->base); // The surface has reffed the snapshot so we must unref it here.
return &snapshot->base;
}
@@ -2423,43 +2414,34 @@ _cairo_quartz_snapshot_finish (void *surface)
}
CGImageRef
-_cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface)
+_cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface)
{
- cairo_surface_t *snapshot =
- _cairo_surface_has_snapshot (&surface->base, &cairo_quartz_snapshot_backend);
+ cairo_surface_t *snapshot;
+ assert (_is_quartz_surface (surface));
+ snapshot =
+ _cairo_surface_has_snapshot (surface, &cairo_quartz_snapshot_backend);
if (unlikely (!snapshot))
{
snapshot = _cairo_quartz_snapshot_create (surface);
if (unlikely (!snapshot || cairo_surface_status (snapshot)))
return NULL;
- _cairo_surface_attach_snapshot (&surface->base, snapshot, NULL);
- cairo_surface_destroy (snapshot);
}
return CGImageRetain (((cairo_quartz_snapshot_t*)snapshot)->image);
}
-/* Debug stuff */
-
-#ifdef QUARTZ_DEBUG
-
void
-quartz_image_to_png (CGImageRef image, const char *dest)
+_cairo_quartz_image_to_png (CGImageRef image, const char *dest)
{
- static int sctr = 0;
- const char* image_name = "quartz-image";
- char pathbuf[100];
-
CFStringRef png_utti = CFSTR("public.png");
CFStringRef path;
CFURLRef url;
CGImageDestinationRef image_dest;
- memset (pathbuf, 0, sizeof (pathbuf));
- dest = dest ? dest : image_name;
- snprintf (pathbuf, sizeof (pathbuf), "%s/Desktop/%s%d.png",getenv ("HOME"), dest, sctr++);
- path = CFStringCreateWithCString (NULL, pathbuf, kCFStringEncodingUTF8);
+ if (!dest)
+ return;
+ path = CFStringCreateWithCString (NULL, dest, kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE);
image_dest = CGImageDestinationCreateWithURL (url, png_utti, 1, NULL);
@@ -2470,20 +2452,20 @@ quartz_image_to_png (CGImageRef image, const char *dest)
CFRelease (path);
}
-void
-quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest)
+cairo_status_t
+_cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest)
{
CGImageRef image;
-
- if (nq->base.type != CAIRO_SURFACE_TYPE_QUARTZ) {
- fprintf (stderr, "** quartz_surface_to_png: surface %p isn't quartz!\n", nq);
- return;
+ cairo_quartz_surface_t *surface;
+ if (!(_cairo_surface_is_quartz (abstract_surface) &&
+ _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)abstract_surface)->cgContext))) {
+ return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
}
- image = CGBitmapContextCreateImage (nq->cgContext);
- quartz_image_to_png (image, dest);
+ surface = (cairo_quartz_surface_t*)abstract_surface;
+ image = CGBitmapContextCreateImage (surface->cgContext);
+ _cairo_quartz_image_to_png (image, dest);
CGImageRelease (image);
+ return CAIRO_STATUS_SUCCESS;
}
-
-#endif /* QUARTZ_DEBUG */
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 158ea16ba..2912f5ede 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -364,7 +364,10 @@ _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
cleanup:
- bbtree_del (&surface->bbtree);
+ if (surface->bbtree.left)
+ bbtree_del (surface->bbtree.left);
+ if (surface->bbtree.right)
+ bbtree_del (surface->bbtree.right);
return status;
}
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 415b45f78..75640f723 100755
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2660,6 +2660,8 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
* @recording_surface: The recording surface
* @foreground_color: The foreground color that was used to record the
* glyph, or NULL if foreground color not required.
+ *
+ * Sets the surface that was used to record the glyph.
*/
void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
@@ -2691,6 +2693,8 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
* @foreground_marker_color: The foreground color that was used to
* substitute the foreground_marker, or NULL if foreground_marker not
* used when rendering the surface color.
+ *
+ * Sets the color surface of the glyph.
*/
void
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
diff --git a/src/cairo-shape-mask-compositor.c b/src/cairo-shape-mask-compositor.c
index 3117267cc..0f4918603 100644
--- a/src/cairo-shape-mask-compositor.c
+++ b/src/cairo-shape-mask-compositor.c
@@ -116,7 +116,7 @@ _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
&_cairo_pattern_white.base,
&pattern.base,
clip);
- if ((status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_surface_mask (extents->surface,
CAIRO_OPERATOR_ADD,
&extents->source_pattern.base,
@@ -210,7 +210,7 @@ _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor,
&_cairo_pattern_white.base,
&pattern.base,
clip);
- if ((status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_surface_mask (extents->surface,
CAIRO_OPERATOR_ADD,
&extents->source_pattern.base,
@@ -303,7 +303,7 @@ _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
&_cairo_pattern_white.base,
&pattern.base,
clip);
- if ((status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_surface_mask (extents->surface,
CAIRO_OPERATOR_ADD,
&extents->source_pattern.base,
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 9c4432e24..bf29d4219 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -54,6 +54,15 @@
#include "cairo-script-private.h"
#endif
+/**
+ * SECTION:cairo-surface-observer
+ * @Title: Surface Observer
+ * @Short_Description: Observing other surfaces
+ * @See_Also: #cairo_surface_t
+ *
+ * A surface that exists solely to watch another is doing.
+ */
+
static const cairo_surface_backend_t _cairo_surface_observer_backend;
/* observation/stats */
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 609eb9ccf..f1292e0bb 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -49,7 +49,6 @@
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
#include "cairo-surface-inline.h"
-#include "cairo-tee-surface-private.h"
/**
* SECTION:cairo-surface
diff --git a/src/cairo-svg.h b/src/cairo-svg.h
index 5328cb583..7745eec90 100644
--- a/src/cairo-svg.h
+++ b/src/cairo-svg.h
@@ -73,9 +73,9 @@ typedef enum _cairo_svg_version {
* lengths in the SVG specification.
*
* See also:
- * https://www.w3.org/TR/SVG/coords.html#Units
- * https://www.w3.org/TR/SVG/types.html#DataTypeLength
- * https://www.w3.org/TR/css-values-3/#lengths
+ * - [SVG Units](https://www.w3.org/TR/SVG/coords.html#Units)
+ * - [SVG Types](https://www.w3.org/TR/SVG/types.html#DataTypeLength)
+ * - [CSS Length](https://www.w3.org/TR/css-values-3/#lengths)
*
* Since: 1.16
**/
diff --git a/src/cairo-tee-surface-private.h b/src/cairo-tee-surface-private.h
deleted file mode 100644
index a83cfc959..000000000
--- a/src/cairo-tee-surface-private.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Chris Wilson
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 University of Southern
- * California.
- *
- * Contributor(s):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#ifndef CAIRO_TEE_SURFACE_PRIVATE_H
-#define CAIRO_TEE_SURFACE_PRIVATE_H
-
-#include "cairoint.h"
-
-cairo_private cairo_surface_t *
-_cairo_tee_surface_find_match (void *abstract_surface,
- const cairo_surface_backend_t *backend,
- cairo_content_t content);
-
-#endif /* CAIRO_TEE_SURFACE_PRIVATE_H */
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 4994a5a60..1d075a29c 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -44,7 +44,6 @@
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
-#include "cairo-tee-surface-private.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-surface-wrapper-private.h"
#include "cairo-array-private.h"
@@ -565,43 +564,3 @@ cairo_tee_surface_index (cairo_surface_t *abstract_surface,
return slave->target;
}
}
-
-cairo_surface_t *
-_cairo_tee_surface_find_match (void *abstract_surface,
- const cairo_surface_backend_t *backend,
- cairo_content_t content)
-{
- cairo_tee_surface_t *surface = abstract_surface;
- cairo_surface_wrapper_t *slaves;
- int num_slaves, n;
-
- /* exact match first */
- if (surface->master.target->backend == backend &&
- surface->master.target->content == content)
- {
- return surface->master.target;
- }
-
- num_slaves = _cairo_array_num_elements (&surface->slaves);
- slaves = _cairo_array_index (&surface->slaves, 0);
- for (n = 0; n < num_slaves; n++) {
- if (slaves[n].target->backend == backend &&
- slaves[n].target->content == content)
- {
- return slaves[n].target;
- }
- }
-
- /* matching backend? */
- if (surface->master.target->backend == backend)
- return surface->master.target;
-
- num_slaves = _cairo_array_num_elements (&surface->slaves);
- slaves = _cairo_array_index (&surface->slaves, 0);
- for (n = 0; n < num_slaves; n++) {
- if (slaves[n].target->backend == backend)
- return slaves[n].target;
- }
-
- return NULL;
-}
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index 91ee0e90b..78c7dd5ec 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -1471,10 +1471,14 @@ find_name (tt_name_t *name, unsigned long size, int name_id, int platform, int e
if (offset + len > size)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- str = _cairo_strndup (((char*)name) + offset, len);
+ str = _cairo_malloc (len + 1);
if (str == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ memcpy (str,
+ ((char*)name) + offset,
+ len);
+ str[len] = 0;
break;
}
}
diff --git a/src/cairo.c b/src/cairo.c
index 55e7103ea..3d4fea601 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1166,9 +1166,8 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
* cairo_set_line_width() and ignore this note.
*
* As with the other stroke parameters, the current line width is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default line width value is 2.0.
*
@@ -1242,9 +1241,8 @@ slim_hidden_def (cairo_set_hairline);
* styles are drawn.
*
* As with the other stroke parameters, the current line cap style is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default line cap style is %CAIRO_LINE_CAP_BUTT.
*
@@ -1274,9 +1272,8 @@ slim_hidden_def (cairo_set_line_cap);
* styles are drawn.
*
* As with the other stroke parameters, the current line join style is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default line join style is %CAIRO_LINE_JOIN_MITER.
*
@@ -1411,9 +1408,8 @@ cairo_get_dash (cairo_t *cr,
* converted to a bevel.
*
* As with the other stroke parameters, the current line miter limit is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default miter limit value is 10.0, which will convert joins
* with interior angles less than 11 degrees to bevels instead of
@@ -2941,7 +2937,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr)
* CAIRO_TAG_DEST:
*
* Create a destination for a hyperlink. Destination tag attributes
- * are detailed at [Destinations][dests].
+ * are detailed at [Destinations][dest].
*
* Since: 1.16
**/
@@ -2950,7 +2946,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr)
* CAIRO_TAG_LINK:
*
* Create hyperlink. Link tag attributes are detailed at
- * [Links][links].
+ * [Links][link].
*
* Since: 1.16
**/
@@ -3360,7 +3356,7 @@ cairo_set_scaled_font (cairo_t *cr,
if (unlikely (cr->status))
return;
- if ((scaled_font == NULL)) {
+ if (scaled_font == NULL) {
_cairo_set_error (cr, _cairo_error (CAIRO_STATUS_NULL_POINTER));
return;
}
@@ -4044,7 +4040,7 @@ slim_hidden_def (cairo_has_current_point);
* cairo_move_to(), cairo_line_to(), cairo_curve_to(),
* cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(),
* cairo_arc(), cairo_arc_negative(), cairo_rectangle(),
- * cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path().
+ * cairo_text_path(), cairo_glyph_path().
*
* Some functions use and alter the current point but do not
* otherwise change current path:
diff --git a/src/cairo.h b/src/cairo.h
index 78a958476..eef4c442b 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -295,6 +295,7 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_WIN32_GDI_ERROR: error occurred in the Windows Graphics Device Interface (Since 1.16)
* @CAIRO_STATUS_TAG_ERROR: invalid tag name, attributes, or nesting (Since 1.16)
* @CAIRO_STATUS_DWRITE_ERROR: error occurred in the Windows Direct Write API (Since 1.18)
+ * @CAIRO_STATUS_SVG_FONT_ERROR: error occurred in OpenType-SVG font rendering (Since 1.18)
* @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of
* status values defined in this enumeration. When using this value, note
* that the version of cairo at run-time may have additional status values
@@ -2448,26 +2449,37 @@ cairo_surface_status (cairo_surface_t *surface);
* @CAIRO_SURFACE_TYPE_PS: The surface is of type ps, since 1.2
* @CAIRO_SURFACE_TYPE_XLIB: The surface is of type xlib, since 1.2
* @CAIRO_SURFACE_TYPE_XCB: The surface is of type xcb, since 1.2
- * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2
+ * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2, deprecated 1.18
+ * (glitz support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_QUARTZ: The surface is of type quartz, since 1.2
* @CAIRO_SURFACE_TYPE_WIN32: The surface is of type win32, since 1.2
- * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2
- * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2
+ * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2, deprecated 1.18
+ * (beos support have been removed, this surface type will never be set by cairo)
+ * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2, deprecated 1.18
+ * (directfb support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg, since 1.2
- * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4
+ * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4, deprecated 1.18
+ * (os2 support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface, since 1.6
* @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image, since 1.6
* @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
- * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10
+ * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10, deprecated 1.18
+ * (Ot support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_RECORDING: The surface is of type recording, since 1.10
- * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10
- * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10
- * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10
+ * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10, deprecated 1.18
+ * (OpenVG support have been removed, this surface type will never be set by cairo)
+ * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10, deprecated 1.18
+ * (OpenGL support have been removed, this surface type will never be set by cairo)
+ * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10, deprecated 1.18
+ * (DRM support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10
* @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10
+ * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10, deprecated 1.18
+ * (Skia support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with
* cairo_surface_create_for_rectangle(), since 1.10
- * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12
+ * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12, deprecated 1.18
+ * (Cogl support have been removed, this surface type will never be set by cairo)
*
* #cairo_surface_type_t is used to describe the type of a given
* surface. The surface types are also known as "backends" or "surface
diff --git a/src/cairoint.h b/src/cairoint.h
index 4b948cc40..e5c281842 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -896,6 +896,10 @@ cairo_private void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other);
+cairo_private cairo_bool_t
+_cairo_font_options_compare (const cairo_font_options_t *a,
+ const cairo_font_options_t *b);
+
cairo_private void
_cairo_font_options_fini (cairo_font_options_t *options);
diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index 1d84fc047..cf516d41c 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -212,6 +212,9 @@ private:
RefPtr<IDWriteFactory> DWriteFactory::mFactoryInstance;
+RefPtr<IDWriteFactory1> DWriteFactory::mFactoryInstance1;
+RefPtr<IDWriteFactory2> DWriteFactory::mFactoryInstance2;
+RefPtr<IDWriteFactory3> DWriteFactory::mFactoryInstance3;
RefPtr<IDWriteFactory4> DWriteFactory::mFactoryInstance4;
RefPtr<IWICImagingFactory> WICImagingFactory::mFactoryInstance;
@@ -221,6 +224,107 @@ RefPtr<IDWriteRenderingParams> DWriteFactory::mDefaultRenderingParams;
RefPtr<ID2D1Factory> D2DFactory::mFactoryInstance;
RefPtr<ID2D1DCRenderTarget> D2DFactory::mRenderTarget;
+static int
+_quality_from_antialias_mode(cairo_antialias_t antialias)
+{
+ switch (antialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ return NONANTIALIASED_QUALITY;
+ case CAIRO_ANTIALIAS_FAST:
+ case CAIRO_ANTIALIAS_GRAY:
+ return ANTIALIASED_QUALITY;
+ default:
+ break;
+ }
+ return CLEARTYPE_QUALITY;
+}
+
+static RefPtr<IDWriteRenderingParams>
+_create_rendering_params(IDWriteRenderingParams *params,
+ const cairo_font_options_t *options,
+ cairo_antialias_t antialias)
+{
+ if (!params)
+ params = DWriteFactory::DefaultRenderingParams();
+ FLOAT gamma = params->GetGamma();
+ FLOAT enhanced_contrast = params->GetEnhancedContrast();
+ FLOAT clear_type_level = params->GetClearTypeLevel();
+ DWRITE_PIXEL_GEOMETRY pixel_geometry = params->GetPixelGeometry();
+ DWRITE_RENDERING_MODE rendering_mode = params->GetRenderingMode();
+
+ cairo_bool_t modified = FALSE;
+ switch (antialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ if (rendering_mode != DWRITE_RENDERING_MODE_ALIASED) {
+ rendering_mode = DWRITE_RENDERING_MODE_ALIASED;
+ modified = TRUE;
+ }
+ break;
+ case CAIRO_ANTIALIAS_FAST:
+ case CAIRO_ANTIALIAS_GRAY:
+ if (clear_type_level) {
+ clear_type_level = 0;
+ modified = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ auto subpixel_order = cairo_font_options_get_subpixel_order (options);
+ switch (subpixel_order) {
+ case CAIRO_SUBPIXEL_ORDER_RGB:
+ if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_RGB) {
+ pixel_geometry = DWRITE_PIXEL_GEOMETRY_RGB;
+ modified = TRUE;
+ }
+ break;
+ case CAIRO_SUBPIXEL_ORDER_BGR:
+ if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_BGR) {
+ pixel_geometry = DWRITE_PIXEL_GEOMETRY_BGR;
+ modified = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!modified)
+ return params;
+
+ HRESULT hr;
+ RefPtr<IDWriteRenderingParams1> params1;
+ hr = params->QueryInterface(&params1);
+ if (FAILED(hr)) {
+ RefPtr<IDWriteRenderingParams> ret;
+ DWriteFactory::Instance()->CreateCustomRenderingParams(gamma, enhanced_contrast, clear_type_level, pixel_geometry, rendering_mode, &ret);
+ return ret;
+ }
+
+ FLOAT grayscaleEnhancedContrast = params1->GetGrayscaleEnhancedContrast();
+ RefPtr<IDWriteRenderingParams2> params2;
+ hr = params->QueryInterface(&params2);
+ if (FAILED(hr)) {
+ RefPtr<IDWriteRenderingParams1> ret;
+ DWriteFactory::Instance1()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, &ret);
+ return ret;
+ }
+
+ DWRITE_GRID_FIT_MODE gridFitMode = params2->GetGridFitMode();
+ RefPtr<IDWriteRenderingParams3> params3;
+ hr = params->QueryInterface(&params3);
+ if (FAILED(hr)) {
+ RefPtr<IDWriteRenderingParams2> ret;
+ DWriteFactory::Instance2()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, gridFitMode, &ret);
+ return ret;
+ }
+
+ DWRITE_RENDERING_MODE1 rendering_mode1 = params3->GetRenderingMode1();
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED;
+ RefPtr<IDWriteRenderingParams3> ret;
+ DWriteFactory::Instance3()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode1, gridFitMode, &ret);
+ return ret;
+}
+
/* Functions #cairo_font_face_backend_t */
static cairo_status_t
_cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
@@ -557,13 +661,6 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
dwrite_font->mat_inverse = dwrite_font->mat;
cairo_matrix_invert (&dwrite_font->mat_inverse);
- dwrite_font->rendering_params = NULL;
- if (font_face->rendering_params) {
- dwrite_font->rendering_params = font_face->rendering_params;
- dwrite_font->rendering_params->AddRef();
- }
- dwrite_font->measuring_mode = font_face->measuring_mode;
-
cairo_font_extents_t extents;
DWRITE_FONT_METRICS metrics;
@@ -612,6 +709,9 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
dwrite_font->antialias_mode = options->antialias;
}
+ dwrite_font->rendering_params = _create_rendering_params(font_face->rendering_params, options, dwrite_font->antialias_mode).forget().drop();
+ dwrite_font->measuring_mode = font_face->measuring_mode;
+
return _cairo_scaled_font_set_metrics (*font, &extents);
}
@@ -716,10 +816,15 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
// We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
// for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
// and therefore it does not always cover all pixels that will actually be touched.
- if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE &&
- extents.width > 0 && extents.height > 0) {
- extents.width += scaled_font->mat_inverse.xx * 2;
- extents.x_bearing -= scaled_font->mat_inverse.xx;
+ if (extents.width > 0 && extents.height > 0) {
+ double x = 1, y = 1;
+ cairo_matrix_transform_distance (&scaled_font->mat_inverse, &x, &y);
+ x = fabs(x);
+ y = fabs(y);
+ extents.width += x * 2;
+ extents.x_bearing -= x;
+ extents.height += y * 2;
+ extents.y_bearing -= y;
}
_cairo_scaled_glyph_set_metrics (scaled_glyph,
@@ -736,8 +841,9 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
class GeometryRecorder : public IDWriteGeometrySink
{
public:
- GeometryRecorder(cairo_path_fixed_t *aCairoPath)
- : mCairoPath(aCairoPath) {}
+ GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix)
+ : mCairoPath(aCairoPath)
+ , mMatrix(matrix) {}
// IUnknown interface
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
@@ -779,10 +885,14 @@ public:
D2D1_POINT_2F startPoint,
D2D1_FIGURE_BEGIN figureBegin)
{
- mStartPoint = startPoint;
+ double x = startPoint.x;
+ double y = startPoint.y;
+ cairo_matrix_transform_point(&mMatrix, &x, &y);
+ mStartPointX = _cairo_fixed_from_double(x);
+ mStartPointY = _cairo_fixed_from_double(y);
cairo_status_t status = _cairo_path_fixed_move_to(mCairoPath,
- _cairo_fixed_from_double(startPoint.x),
- _cairo_fixed_from_double(startPoint.y));
+ mStartPointX,
+ mStartPointY);
(void)status; /* squelch warning */
}
@@ -791,8 +901,8 @@ public:
{
if (figureEnd == D2D1_FIGURE_END_CLOSED) {
cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
- _cairo_fixed_from_double(mStartPoint.x),
- _cairo_fixed_from_double(mStartPoint.y));
+ mStartPointX,
+ mStartPointY);
(void)status; /* squelch warning */
}
}
@@ -802,13 +912,22 @@ public:
UINT beziersCount)
{
for (unsigned int i = 0; i < beziersCount; i++) {
+ double x1 = beziers[i].point1.x;
+ double y1 = beziers[i].point1.y;
+ double x2 = beziers[i].point2.x;
+ double y2 = beziers[i].point2.y;
+ double x3 = beziers[i].point3.x;
+ double y3 = beziers[i].point3.y;
+ cairo_matrix_transform_point(&mMatrix, &x1, &y1);
+ cairo_matrix_transform_point(&mMatrix, &x2, &y2);
+ cairo_matrix_transform_point(&mMatrix, &x3, &y3);
cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath,
- _cairo_fixed_from_double(beziers[i].point1.x),
- _cairo_fixed_from_double(beziers[i].point1.y),
- _cairo_fixed_from_double(beziers[i].point2.x),
- _cairo_fixed_from_double(beziers[i].point2.y),
- _cairo_fixed_from_double(beziers[i].point3.x),
- _cairo_fixed_from_double(beziers[i].point3.y));
+ _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));
(void)status; /* squelch warning */
}
}
@@ -818,16 +937,21 @@ public:
UINT pointsCount)
{
for (unsigned int i = 0; i < pointsCount; i++) {
+ double x = points[i].x;
+ double y = points[i].y;
+ cairo_matrix_transform_point(&mMatrix, &x, &y);
cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
- _cairo_fixed_from_double(points[i].x),
- _cairo_fixed_from_double(points[i].y));
+ _cairo_fixed_from_double(x),
+ _cairo_fixed_from_double(y));
(void)status; /* squelch warning */
}
}
private:
cairo_path_fixed_t *mCairoPath;
- D2D1_POINT_2F mStartPoint;
+ const cairo_matrix_t &mMatrix;
+ cairo_fixed_t mStartPointX;
+ cairo_fixed_t mStartPointY;
};
static cairo_int_status_t
@@ -837,7 +961,7 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
cairo_int_status_t status;
cairo_path_fixed_t *path;
path = _cairo_path_fixed_create();
- GeometryRecorder recorder(path);
+ GeometryRecorder recorder(path, scaled_font->base.scale);
DWRITE_GLYPH_OFFSET offset;
offset.advanceOffset = 0;
@@ -846,12 +970,7 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
FLOAT advance = 0.0;
cairo_dwrite_font_face_t *dwriteff = (cairo_dwrite_font_face_t*)scaled_font->base.font_face;
- /* GetGlyphRunOutline seems to ignore hinting so just use the em size to get the outline
- * to avoid rounding errors when converting to cairo_path_fixed_t.
- */
- DWRITE_FONT_METRICS metrics;
- dwriteff->dwriteface->GetMetrics(&metrics);
- HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(metrics.designUnitsPerEm,
+ HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(1,
&glyphId,
&advance,
&offset,
@@ -864,12 +983,6 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
status = (cairo_int_status_t)_cairo_path_fixed_close_path(path);
- /* Now scale the em size down to 1.0 and apply the font matrix and font ctm. */
- cairo_matrix_t mat = scaled_font->base.ctm;
- cairo_matrix_multiply(&mat, &scaled_font->base.font_matrix, &mat);
- cairo_matrix_scale (&mat, 1.0/metrics.designUnitsPerEm, 1.0/metrics.designUnitsPerEm);
- _cairo_path_fixed_transform(path, &mat);
-
_cairo_scaled_glyph_set_path (scaled_glyph,
&scaled_font->base,
path);
@@ -883,7 +996,6 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
{
int width, height;
double x1, y1, x2, y2;
- cairo_glyph_t glyph;
cairo_bool_t uses_foreground_color = FALSE;
cairo_dwrite_font_face_t *dwrite_font_face = (cairo_dwrite_font_face_t *)scaled_font->base.font_face;
@@ -900,22 +1012,18 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
width = (int)(x2 - x1);
height = (int)(y2 - y1);
- glyph.index = _cairo_scaled_glyph_index (scaled_glyph);
- glyph.x = x1;
- glyph.y = y1;
-
DWRITE_GLYPH_RUN run;
FLOAT advance = 0;
- UINT16 index = (UINT16)glyph.index;
+ UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
DWRITE_GLYPH_OFFSET offset;
- double x = -glyph.x;
- double y = -glyph.y;
+ double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
+ double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
DWRITE_MATRIX matrix;
D2D1_POINT_2F origin = {0, 0};
RefPtr<IDWriteColorGlyphRunEnumerator1> run_enumerator;
HRESULT hr;
- /**
+ /*
* We transform by the inverse transformation here. This will put our glyph
* locations in the space in which we draw. Which is later transformed by
* the transformation matrix that we use. This will transform the
@@ -924,7 +1032,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
*/
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
offset.advanceOffset = (FLOAT)x;
- /** Y-axis is inverted */
+ /* Y-axis is inverted */
offset.ascenderOffset = -(FLOAT)y;
run.fontFace = dwrite_font_face->dwriteface;
@@ -1036,8 +1144,8 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
if (FAILED(hr) || !have_run)
break;
- DWRITE_COLOR_GLYPH_RUN1 const* color_run;
- hr = run_enumerator->GetCurrentRun(&color_run);
+ DWRITE_COLOR_GLYPH_RUN1_WORKAROUND const* color_run;
+ hr = run_enumerator->GetCurrentRun(reinterpret_cast<const DWRITE_COLOR_GLYPH_RUN1**>(&color_run));
if (FAILED(hr))
return _cairo_dwrite_error (hr, "GetCurrentRun failed");
@@ -1118,48 +1226,11 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
return CAIRO_INT_STATUS_SUCCESS;
}
-/* Helper function adapted from _compute_mask in cairo-win32-font.c */
-
-/* Compute an alpha-mask from a monochrome RGB24 image
- */
-static cairo_surface_t *
-_compute_a8_mask (cairo_surface_t *surface)
-{
- cairo_image_surface_t *glyph;
- cairo_image_surface_t *mask;
- int i, j;
-
- glyph = (cairo_image_surface_t *)cairo_surface_map_to_image (surface, NULL);
- if (unlikely (glyph->base.status))
- return &glyph->base;
-
- /* No quality param, just use the non-ClearType path */
-
- /* Compute an alpha-mask by using the green channel of a (presumed monochrome)
- * RGB24 image.
- */
- mask = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_A8, glyph->width, glyph->height);
- if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
- for (i = 0; i < glyph->height; i++) {
- uint32_t *p = (uint32_t *) (glyph->data + i * glyph->stride);
- uint8_t *q = (uint8_t *) (mask->data + i * mask->stride);
-
- for (j = 0; j < glyph->width; j++)
- *q++ = 255 - ((*p++ & 0x0000ff00) >> 8);
- }
- }
-
- cairo_surface_unmap_image (surface, &glyph->base);
- return &mask->base;
-}
-
static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_int_status_t status;
- cairo_glyph_t glyph;
cairo_win32_surface_t *surface;
cairo_t *cr;
cairo_surface_t *image;
@@ -1173,16 +1244,12 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
width = (int)(x2 - x1);
height = (int)(y2 - y1);
- glyph.index = _cairo_scaled_glyph_index (scaled_glyph);
- glyph.x = -x1;
- glyph.y = -y1;
-
DWRITE_GLYPH_RUN run;
FLOAT advance = 0;
- UINT16 index = (UINT16)glyph.index;
+ UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
DWRITE_GLYPH_OFFSET offset;
- double x = glyph.x;
- double y = glyph.y;
+ double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
+ double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
RECT area;
DWRITE_MATRIX matrix;
@@ -1197,7 +1264,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
if (status)
goto FAIL;
- /**
+ /*
* We transform by the inverse transformation here. This will put our glyph
* locations in the space in which we draw. Which is later transformed by
* the transformation matrix that we use. This will transform the
@@ -1206,7 +1273,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
*/
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
offset.advanceOffset = (FLOAT)x;
- /** Y-axis is inverted */
+ /* Y-axis is inverted */
offset.ascenderOffset = -(FLOAT)y;
area.top = 0;
@@ -1232,7 +1299,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
GdiFlush();
- image = _compute_a8_mask (&surface->base);
+ image = _cairo_compute_glyph_mask (&surface->base, _quality_from_antialias_mode(scaled_font->antialias_mode));
status = (cairo_int_status_t)image->status;
if (status)
goto FAIL;
@@ -1486,6 +1553,9 @@ cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face)
* @params: The #IDWriteRenderingParams object
*
* Sets the #IDWriteRenderingParams object to @font_face.
+ * This #IDWriteRenderingParams is used to render glyphs if default values of font options are used.
+ * If non-defalut values of font options are specified when creating a #cairo_scaled_font_t,
+ * cairo creates a new #IDWriteRenderingParams object for the #cairo_scaled_font_t object by overwriting the corresponding parameters.
*
* Since: 1.18
**/
@@ -1559,13 +1629,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
}
}
- IDWriteRenderingParams *params;
- if (scaled_font->rendering_params)
- params = scaled_font->rendering_params;
- else
- params = DWriteFactory::DefaultRenderingParams();
-
- /**
+ /*
* We set the number of pixels per DIP to 1.0. This is because we always want
* to draw in device pixels, and not device independent pixels. On high DPI
* systems this value will be higher than 1.0 and automatically upscale
@@ -1573,8 +1637,15 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
*/
rt->SetPixelsPerDip(1.0);
+ float x = 0, y = 0;
if (transform) {
- rt->SetCurrentTransform(transform);
+ DWRITE_MATRIX matrix = *transform;
+ matrix.dx -= area.left;
+ matrix.dy -= area.top;
+ rt->SetCurrentTransform(&matrix);
+ } else {
+ x = (float) -area.left;
+ y = (float) -area.top;
}
BitBlt(rt->GetMemoryDC(),
0, 0,
@@ -1582,7 +1653,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
surface->dc,
area.left, area.top,
SRCCOPY | NOMIRRORBITMAP);
- rt->DrawGlyphRun(0, 0, scaled_font->measuring_mode, run, params, color);
+ rt->DrawGlyphRun(x, y, scaled_font->measuring_mode, run, scaled_font->rendering_params, color);
BitBlt(surface->dc,
area.left, area.top,
area.right - area.left, area.bottom - area.top,
@@ -1618,6 +1689,7 @@ _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
if (FAILED(hr))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ float x = 0, y = 0;
if (transform) {
rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
transform->m12,
@@ -1666,15 +1738,6 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER)
return CAIRO_INT_STATUS_UNSUPPORTED;
- /* If we have a fallback mask clip set on the dst, we have
- * to go through the fallback path */
- if (!_cairo_surface_is_win32_printing (&dst->base)) {
- if (clip != NULL)
- _cairo_win32_display_surface_set_clip (to_win32_display_surface (dst), clip);
- else
- _cairo_win32_display_surface_unset_clip (to_win32_display_surface (dst));
- }
-
/* It is vital that dx values for dxy_buf are calculated from the delta of
* _logical_ x coordinates (not user x coordinates) or else the sum of all
* previous dx values may start to diverge from the current glyph's x
@@ -1689,96 +1752,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
BOOL transform = FALSE;
- /* Needed to calculate bounding box for efficient blitting */
- INT32 smallestX = INT_MAX;
- INT32 largestX = 0;
- INT32 smallestY = INT_MAX;
- INT32 largestY = 0;
- for (int i = 0; i < num_glyphs; i++) {
- if (glyphs[i].x < smallestX) {
- smallestX = (INT32)glyphs[i].x;
- }
- if (glyphs[i].x > largestX) {
- largestX = (INT32)glyphs[i].x;
- }
- if (glyphs[i].y < smallestY) {
- smallestY = (INT32)glyphs[i].y;
- }
- if (glyphs[i].y > largestY) {
- largestY = (INT32)glyphs[i].y;
- }
- }
- /**
- * Here we try to get a rough estimate of the area that this glyph run will
- * cover on the surface. Since we use GDI interop to draw we will be copying
- * data around the size of the area of the surface that we map. We will want
- * to map an area as small as possible to prevent large surfaces to be
- * copied around. We take the X/Y-size of the font as margin on the left/top
- * twice the X/Y-size of the font as margin on the right/bottom.
- * This should always cover the entire area where the glyphs are.
- */
- RECT fontArea;
- fontArea.left = (INT32)(smallestX - scaled_font->font_matrix.xx);
- fontArea.right = (INT32)(largestX + scaled_font->font_matrix.xx * 2);
- fontArea.top = (INT32)(smallestY - scaled_font->font_matrix.yy);
- fontArea.bottom = (INT32)(largestY + scaled_font->font_matrix.yy * 2);
- if (fontArea.left < 0)
- fontArea.left = 0;
- if (fontArea.top < 0)
- fontArea.top = 0;
- if (fontArea.bottom > dst->extents.height) {
- fontArea.bottom = dst->extents.height;
- }
- if (fontArea.right > dst->extents.width) {
- fontArea.right = dst->extents.width;
- }
- if (fontArea.right <= fontArea.left ||
- fontArea.bottom <= fontArea.top) {
- return CAIRO_INT_STATUS_SUCCESS;
- }
- if (fontArea.right > dst->extents.width) {
- fontArea.right = dst->extents.width;
- }
- if (fontArea.bottom > dst->extents.height) {
- fontArea.bottom = dst->extents.height;
- }
-
- run.bidiLevel = 0;
- run.fontFace = dwriteff->dwriteface;
- run.isSideways = FALSE;
- if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
- dwritesf->mat.xx == scaled_font->font_matrix.xx &&
- dwritesf->mat.yy == scaled_font->font_matrix.yy) {
-
- for (int i = 0; i < num_glyphs; i++) {
- indices[i] = (WORD) glyphs[i].index;
- // Since we will multiply by our ctm matrix later for rotation effects
- // and such, adjust positions by the inverse matrix now.
- offsets[i].ascenderOffset = (FLOAT)(fontArea.top - glyphs[i].y);
- offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left);
- advances[i] = 0.0;
- }
- run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
- } else {
- transform = TRUE;
- // See comment about EPSILON in _cairo_dwrite_glyph_run_from_glyphs
- const double EPSILON = 0.0001;
- for (int i = 0; i < num_glyphs; i++) {
- indices[i] = (WORD) glyphs[i].index;
- double x = glyphs[i].x - fontArea.left + EPSILON;
- double y = glyphs[i].y - fontArea.top;
- cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
- /**
- * Since we will multiply by our ctm matrix later for rotation effects
- * and such, adjust positions by the inverse matrix now. The Y-axis
- * is inverted so the offset becomes negative.
- */
- offsets[i].ascenderOffset = -(FLOAT)y;
- offsets[i].advanceOffset = (FLOAT)x;
- advances[i] = 0.0;
- }
- run.fontEmSize = 1.0f;
- }
+ _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8,
@@ -1794,18 +1768,31 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
mat = NULL;
}
- RECT area;
- area.left = dst->extents.x;
- area.top = dst->extents.y;
- area.right = area.left + dst->extents.width;
- area.bottom = area.top + dst->extents.height;
+ RefPtr<IDWriteGlyphRunAnalysis> runAnalysis;
+ HRESULT hr = DWriteFactory::Instance()->
+ CreateGlyphRunAnalysis(&run, 1, mat,
+ DWRITE_RENDERING_MODE_ALIASED,
+ dwritesf->measuring_mode,
+ 0, // baselineOriginX,
+ 0, // baselineOriginY,
+ &runAnalysis);
+ if (FAILED(hr))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ RECT fontArea;
+ hr = runAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1, &fontArea);
+ if (FAILED(hr))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ InflateRect(&fontArea, 1, 1);
+ /* Needed to calculate bounding box for efficient blitting */
+ RECT copyArea, dstArea = { 0, 0, dst->extents.width, dst->extents.height };
+ IntersectRect(&copyArea, &fontArea, &dstArea);
#ifdef CAIRO_TRY_D2D_TO_GDI
status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst,
mat,
&run,
color,
- fontArea);
+ copyArea);
if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) {
#endif
@@ -1814,7 +1801,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
&run,
color,
dwritesf,
- fontArea);
+ copyArea);
#ifdef CAIRO_TRY_D2D_TO_GDI
}
diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp
index 4857739ea..c7a24822a 100644
--- a/src/win32/cairo-dwrite-private.hpp
+++ b/src/win32/cairo-dwrite-private.hpp
@@ -36,27 +36,25 @@
#include "cairoint.h"
#include "cairo-win32-refptr.hpp"
-#include <dwrite.h>
-#include <dwrite_2.h>
+#include <dwrite_3.h>
#include <d2d1.h>
-/* If either of the dwrite_3.h or d2d1_3.h headers required for color fonts
- * are not available, include our own version containing just the functions we need.
- */
-
-#if HAVE_DWRITE_3_H
-#include <dwrite_3.h>
-#else
+#ifdef __MINGW32__
#include "dw-extra.h"
+#else
+typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND;
#endif
+/* If d2d1_3.h header required for color fonts is not available,
+ * include our own version containing just the functions we need.
+ */
+
#if HAVE_D2D1_3_H
#include <d2d1_3.h>
#else
#include "d2d1-extra.h"
#endif
-
// DirectWrite is not available on all platforms.
typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
DWRITE_FACTORY_TYPE factoryType,
@@ -101,6 +99,36 @@ public:
return mFactoryInstance;
}
+ static RefPtr<IDWriteFactory1> Instance1()
+ {
+ if (!mFactoryInstance1) {
+ if (Instance()) {
+ Instance()->QueryInterface(&mFactoryInstance1);
+ }
+ }
+ return mFactoryInstance1;
+ }
+
+ static RefPtr<IDWriteFactory2> Instance2()
+ {
+ if (!mFactoryInstance2) {
+ if (Instance()) {
+ Instance()->QueryInterface(&mFactoryInstance2);
+ }
+ }
+ return mFactoryInstance2;
+ }
+
+ static RefPtr<IDWriteFactory3> Instance3()
+ {
+ if (!mFactoryInstance3) {
+ if (Instance()) {
+ Instance()->QueryInterface(&mFactoryInstance3);
+ }
+ }
+ return mFactoryInstance3;
+ }
+
static RefPtr<IDWriteFactory4> Instance4()
{
if (!mFactoryInstance4) {
@@ -151,6 +179,9 @@ public:
private:
static RefPtr<IDWriteFactory> mFactoryInstance;
+ static RefPtr<IDWriteFactory1> mFactoryInstance1;
+ static RefPtr<IDWriteFactory2> mFactoryInstance2;
+ static RefPtr<IDWriteFactory3> mFactoryInstance3;
static RefPtr<IDWriteFactory4> mFactoryInstance4;
static RefPtr<IDWriteFontCollection> mSystemCollection;
static RefPtr<IDWriteRenderingParams> mDefaultRenderingParams;
diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c
index 6bc8bef94..fd9461363 100644
--- a/src/win32/cairo-win32-font.c
+++ b/src/win32/cairo-win32-font.c
@@ -1335,9 +1335,9 @@ _cairo_win32_scaled_font_load_type1_data (void *abstract_font,
length);
}
-static cairo_surface_t *
-_compute_mask (cairo_surface_t *surface,
- int quality)
+cairo_surface_t *
+_cairo_compute_glyph_mask (cairo_surface_t *surface,
+ int quality)
{
cairo_image_surface_t *glyph;
cairo_image_surface_t *mask;
@@ -1421,7 +1421,7 @@ _cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_f
if (status)
goto FAIL;
- image = _compute_mask (surface, scaled_font->quality);
+ image = _cairo_compute_glyph_mask (surface, scaled_font->quality);
status = image->status;
if (status)
goto FAIL;
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index 486b12811..6af09c0e1 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -214,6 +214,10 @@ cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
+cairo_surface_t *
+_cairo_compute_glyph_mask (cairo_surface_t *surface,
+ int quality);
+
uint32_t
_cairo_win32_flags_for_dc (HDC dc, cairo_format_t format);
diff --git a/src/win32/dw-extra.h b/src/win32/dw-extra.h
index 4203f3427..c79e6389c 100644
--- a/src/win32/dw-extra.h
+++ b/src/win32/dw-extra.h
@@ -1,165 +1,30 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* Mingw-w64 dwrite_3.h is broken
+/* MinGW workarounds
*
- * We only need the definitions of the following functions and their dependencies.
- * IDWriteFactory4::TranslateColorGlyphRun()
- * IDWriteFontResource::GetDefaultFontAxisValues()
- * IDWriteFontResource::GetFontAxisCount()
- * IDWriteFontResource::HasVariations()
- * IDWriteFontFace5::GetFontAxisValueCount()
- * IDWriteFontFace5::GetFontAxisValues()
- * IDWriteFontFace5::HasVariations()
- * IDWriteFontFace5::GetFontResource()
- *
- * But we need to include all the prior functions in the same struct,
- * and parent structs, so that the functions are in the correct position
- * in the vtable. The parameters of the unused functions are not
- * required as we only need a function in the struct to create a
- * function pointer in the vtable.
+ * It doesn't define operators for DWRITE_GLYPH_IMAGE_FORMATS.
+ * The DWRITE_COLOR_GLYPH_RUN struct isn't valid.
+ * <https://sourceforge.net/p/mingw-w64/bugs/913/>
*/
#ifndef DWRITE_EXTRA_H
#define DWRITE_EXTRA_H
-#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
-
-#include <dwrite_2.h>
+#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10
-interface IDWriteFactory3;
-interface IDWriteFactory4;
-interface IDWriteColorGlyphRunEnumerator1;
-
-DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS);
-
-struct DWRITE_COLOR_GLYPH_RUN1 : DWRITE_COLOR_GLYPH_RUN
+typedef struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND DWRITE_COLOR_GLYPH_RUN1_WORKAROUND;
+struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND : DWRITE_COLOR_GLYPH_RUN
{
DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat;
DWRITE_MEASURING_MODE measuringMode;
};
+#else
+typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND;
+#error
-DEFINE_GUID(IID_IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35);
-MIDL_INTERFACE("7c5f86da-c7a1-4f05-b8e1-55a179fe5a35")
-IDWriteColorGlyphRunEnumerator1 : public IDWriteColorGlyphRunEnumerator
-{
- virtual HRESULT STDMETHODCALLTYPE GetCurrentRun(
- const DWRITE_COLOR_GLYPH_RUN1 **run) = 0;
-
-};
-__CRT_UUID_DECL(IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35)
-
-DEFINE_GUID(IID_IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65);
-MIDL_INTERFACE("9a1b41c3-d3bb-466a-87fc-fe67556a3b65")
-IDWriteFactory3 : public IDWriteFactory2
-{
- virtual void STDMETHODCALLTYPE CreateGlyphRunAnalysis() = 0;
- virtual void STDMETHODCALLTYPE CreateCustomRenderingParams() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFaceReference() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFaceReference2() = 0;
- virtual void STDMETHODCALLTYPE GetSystemFontSet() = 0;
- virtual void STDMETHODCALLTYPE CreateFontSetBuilder() = 0;
- virtual void STDMETHODCALLTYPE CreateFontCollectionFromFontSet() = 0;
- virtual void STDMETHODCALLTYPE GetSystemFontCollection() = 0;
- virtual void STDMETHODCALLTYPE GetFontDownloadQueue() = 0;
-};
-__CRT_UUID_DECL(IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65)
-
-DEFINE_GUID(IID_IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56);
-MIDL_INTERFACE("4b0b5bd3-0797-4549-8ac5-fe915cc53856")
-IDWriteFactory4 : public IDWriteFactory3
-{
- virtual HRESULT STDMETHODCALLTYPE TranslateColorGlyphRun(
- D2D1_POINT_2F baselineOrigin,
- DWRITE_GLYPH_RUN const *glyphRun,
- DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription,
- DWRITE_GLYPH_IMAGE_FORMATS desiredGlyphImageFormats,
- DWRITE_MEASURING_MODE measuringMode,
- DWRITE_MATRIX const *worldAndDpiTransform,
- UINT32 colorPaletteIndex,
- IDWriteColorGlyphRunEnumerator1 **colorLayers) = 0;
-};
-__CRT_UUID_DECL(IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56)
-
-typedef enum DWRITE_FONT_AXIS_TAG {
- DWRITE_FONT_AXIS_TAG_WEIGHT = 0x74686777,
- DWRITE_FONT_AXIS_TAG_WIDTH = 0x68746477,
- DWRITE_FONT_AXIS_TAG_SLANT = 0x746e6c73,
- DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE = 0x7a73706f,
- DWRITE_FONT_AXIS_TAG_ITALIC = 0x6c617469
-} DWRITE_FONT_AXIS_TAG;
-
-typedef struct DWRITE_FONT_AXIS_VALUE {
- DWRITE_FONT_AXIS_TAG axisTag;
- FLOAT value;
-} DWRITE_FONT_AXIS_VALUE;
-
-DEFINE_GUID(IID_IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2);
-MIDL_INTERFACE("1f803a76-6871-48e8-987f-b975551c50f2")
-IDWriteFontResource : public IUnknown
-{
- virtual void STDMETHODCALLTYPE GetFontFile() = 0;
- virtual void STDMETHODCALLTYPE GetFontFaceIndex() = 0;
- virtual UINT32 STDMETHODCALLTYPE GetFontAxisCount() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetDefaultFontAxisValues(
- const DWRITE_FONT_AXIS_VALUE *values,
- UINT32 num_values) = 0;
- virtual void STDMETHODCALLTYPE GetFontAxisRanges() = 0;
- virtual void STDMETHODCALLTYPE GetFontAxisAttributes() = 0;
- virtual void STDMETHODCALLTYPE GetAxisNames() = 0;
- virtual void STDMETHODCALLTYPE GetAxisValueNameCount() = 0;
- virtual void STDMETHODCALLTYPE GetAxisValueNames() = 0;
- virtual WINBOOL STDMETHODCALLTYPE HasVariations() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFace() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFaceReference() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2)
-
-DEFINE_GUID(IID_IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2);
-MIDL_INTERFACE("d37d7598-09be-4222-a236-2081341cc1f2")
-IDWriteFontFace3 : public IDWriteFontFace2
-{
- virtual void STDMETHODCALLTYPE GetFontFaceReference() = 0;
- virtual void STDMETHODCALLTYPE GetPanose() = 0;
- virtual void STDMETHODCALLTYPE GetWeight() = 0;
- virtual void STDMETHODCALLTYPE GetStretch() = 0;
- virtual void STDMETHODCALLTYPE GetStyle() = 0;
- virtual void STDMETHODCALLTYPE GetFamilyNames() = 0;
- virtual void STDMETHODCALLTYPE GetFaceNames() = 0;
- virtual void STDMETHODCALLTYPE GetInformationalStrings() = 0;
- virtual void STDMETHODCALLTYPE HasCharacter() = 0;
- virtual void STDMETHODCALLTYPE GetRecommendedRenderingMode() = 0;
- virtual void STDMETHODCALLTYPE IsCharacterLocal() = 0;
- virtual void STDMETHODCALLTYPE IsGlyphLocal() = 0;
- virtual void STDMETHODCALLTYPE AreCharactersLocal() = 0;
- virtual void STDMETHODCALLTYPE AreGlyphsLocal() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2)
-
-DEFINE_GUID(IID_IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f);
-MIDL_INTERFACE("27f2a904-4eb8-441d-9678-0563f53e3e2f")
-IDWriteFontFace4 : public IDWriteFontFace3
-{
- virtual void STDMETHODCALLTYPE GetGlyphImageFormats_() = 0;
- virtual void STDMETHODCALLTYPE GetGlyphImageFormats() = 0;
- virtual void STDMETHODCALLTYPE GetGlyphImageData() = 0;
- virtual void STDMETHODCALLTYPE ReleaseGlyphImageData() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f)
+#endif
-DEFINE_GUID(IID_IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29);
-MIDL_INTERFACE("98eff3a5-b667-479a-b145-e2fa5b9fdc29")
-IDWriteFontFace5 : public IDWriteFontFace4
-{
- virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues(
- DWRITE_FONT_AXIS_VALUE *values,
- UINT32 value_count) = 0;
- virtual WINBOOL STDMETHODCALLTYPE HasVariations() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFontResource(
- IDWriteFontResource **resource) = 0;
- virtual void STDMETHODCALLTYPE Equals() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29)
+DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS);
#endif /* DWRITE_EXTRA_H */