summaryrefslogtreecommitdiff
path: root/src/cairo-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-surface.c')
-rw-r--r--[-rwxr-xr-x]src/cairo-surface.c321
1 files changed, 227 insertions, 94 deletions
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 5c6969c8a..24ad24901 100755..100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -454,33 +454,6 @@ _cairo_surface_copy_similar_properties (cairo_surface_t *surface,
other->y_fallback_resolution);
}
-cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_surface_t *surface;
-
- if (unlikely (other->status))
- return _cairo_surface_create_in_error (other->status);
-
- surface = NULL;
- if (other->backend->create_similar)
- surface = other->backend->create_similar (other, content, width, height);
- if (surface == NULL)
- surface = cairo_surface_create_similar_image (other,
- _cairo_format_from_content (content),
- width, height);
-
- if (unlikely (surface->status))
- return surface;
-
- _cairo_surface_copy_similar_properties (surface, other);
-
- return surface;
-}
-
/**
* cairo_surface_create_similar:
* @other: an existing surface used to select the backend of the new surface
@@ -518,6 +491,8 @@ cairo_surface_create_similar (cairo_surface_t *other,
int height)
{
cairo_surface_t *surface;
+ cairo_status_t status;
+ cairo_solid_pattern_t pattern;
if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
@@ -529,9 +504,41 @@ cairo_surface_create_similar (cairo_surface_t *other,
if (unlikely (! CAIRO_CONTENT_VALID (content)))
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
- surface = _cairo_surface_create_similar_solid (other,
- content, width, height,
- CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (other->status))
+ return _cairo_surface_create_in_error (other->status);
+
+ /* We inherit the device scale, so create a larger surface */
+ width = width * other->device_transform.xx;
+ height = height * other->device_transform.yy;
+
+ surface = NULL;
+ if (other->backend->create_similar)
+ surface = other->backend->create_similar (other, content, width, height);
+ if (surface == NULL)
+ surface = cairo_surface_create_similar_image (other,
+ _cairo_format_from_content (content),
+ width, height);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_surface_copy_similar_properties (surface, other);
+ cairo_surface_set_device_scale (surface,
+ other->device_transform.xx,
+ other->device_transform.yy);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_TRANSPARENT);
+ status = _cairo_surface_paint (surface,
+ CAIRO_OPERATOR_CLEAR,
+ &pattern.base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ }
+
assert (surface->is_clear);
return surface;
@@ -852,34 +859,78 @@ error:
}
cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height,
- const cairo_color_t *color)
+_cairo_surface_create_scratch (cairo_surface_t *other,
+ cairo_content_t content,
+ int width,
+ int height,
+ const cairo_color_t *color)
{
- cairo_status_t status;
cairo_surface_t *surface;
+ cairo_status_t status;
cairo_solid_pattern_t pattern;
- surface = _cairo_surface_create_similar_scratch (other, content,
- width, height);
+ if (unlikely (other->status))
+ return _cairo_surface_create_in_error (other->status);
+
+ surface = NULL;
+ if (other->backend->create_similar)
+ surface = other->backend->create_similar (other, content, width, height);
+ if (surface == NULL)
+ surface = cairo_surface_create_similar_image (other,
+ _cairo_format_from_content (content),
+ width, height);
+
if (unlikely (surface->status))
return surface;
- _cairo_pattern_init_solid (&pattern, color);
- status = _cairo_surface_paint (surface,
- color == CAIRO_COLOR_TRANSPARENT ?
- CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- surface = _cairo_surface_create_in_error (status);
+ _cairo_surface_copy_similar_properties (surface, other);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ if (color) {
+ _cairo_pattern_init_solid (&pattern, color);
+ status = _cairo_surface_paint (surface,
+ color == CAIRO_COLOR_TRANSPARENT ?
+ CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ }
}
return surface;
}
+cairo_surface_t *
+_cairo_surface_create_similar_scratch (cairo_surface_t *other,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t *surface;
+
+ if (unlikely (other->status))
+ return _cairo_surface_create_in_error (other->status);
+
+ surface = NULL;
+ if (other->backend->create_similar)
+ surface = other->backend->create_similar (other, content, width, height);
+ if (surface == NULL)
+ surface = cairo_surface_create_similar_image (other,
+ _cairo_format_from_content (content),
+ width, height);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_surface_copy_similar_properties (surface, other);
+
+ return surface;
+}
+
+
/**
* cairo_surface_reference:
* @surface: a #cairo_surface_t
@@ -1200,6 +1251,31 @@ _cairo_mime_data_destroy (void *ptr)
}
/**
+ * CAIRO_MIME_TYPE_JBIG2:
+ *
+ * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544).
+ *
+ * Since: 1.14
+ **/
+
+/**
+ * CAIRO_MIME_TYPE_JBIG2_GLOBAL:
+ *
+ * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544) global segment.
+ *
+ * Since: 1.14
+ **/
+
+/**
+ * CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID:
+ *
+ * An unique identifier shared by a JBIG2 global segment and all JBIG2 images
+ * that depend on the global segment.
+ *
+ * Since: 1.14
+ **/
+
+/**
* CAIRO_MIME_TYPE_JP2:
*
* The Joint Photographic Experts Group (JPEG) 2000 image coding standard (ISO/IEC 15444-1).
@@ -1234,7 +1310,8 @@ _cairo_mime_data_destroy (void *ptr)
/**
* CAIRO_MIME_TYPE_UNIQUE_ID:
*
- * Unique identifier for a surface (cairo specific MIME type).
+ * Unique identifier for a surface (cairo specific MIME type). All surfaces with
+ * the same unique identifier will only be embedded once.
*
* Since: 1.12
**/
@@ -1262,13 +1339,24 @@ _cairo_mime_data_destroy (void *ptr)
*
* The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
* %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI,
- * %CAIRO_MIME_TYPE_UNIQUE_ID.
+ * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2,
+ * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID.
*
* See corresponding backend surface docs for details about which MIME
* types it can handle. Caution: the associated MIME data will be
* discarded if you draw on the surface afterwards. Use this function
* with care.
*
+ * Even if a backend supports a MIME type, that does not mean cairo
+ * will always be able to use the attached MIME data. For example, if
+ * the backend does not natively support the compositing operation used
+ * to apply the MIME data to the backend. In that case, the MIME data
+ * will be ignored. Therefore, to apply an image in all cases, it is best
+ * to create an image surface which contains the decoded image data and
+ * then attach the MIME data to that. This ensures the image will always
+ * be used while still allowing the MIME data to be used whenever
+ * possible.
+ *
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
@@ -1346,6 +1434,13 @@ cairo_surface_supports_mime_type (cairo_surface_t *surface,
{
const char **types;
+ if (unlikely (surface->status))
+ return FALSE;
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ return FALSE;
+ }
+
if (surface->backend->get_supported_mime_types) {
types = surface->backend->get_supported_mime_types (surface);
if (types) {
@@ -1617,26 +1712,28 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
slim_hidden_def (cairo_surface_mark_dirty_rectangle);
/**
- * _cairo_surface_set_device_scale:
+ * cairo_surface_set_device_scale:
* @surface: a #cairo_surface_t
- * @sx: a scale factor in the X direction
- * @sy: a scale factor in the Y direction
- *
- * Private function for setting an extra scale factor to affect all
- * drawing to a surface. This is used, for example, when replaying a
- * recording surface to an image fallback intended for an eventual
- * vector-oriented backend. Since the recording surface will record
- * coordinates in one backend space, but the image fallback uses a
- * different backend space, (differing by the fallback resolution
- * scale factors), we need a scale factor correction.
- *
- * Caution: Not all places we use device transform correctly handle
- * both a translate and a scale. An audit would be nice.
+ * @x_scale: a scale factor in the X direction
+ * @y_scale: a scale factor in the Y direction
+ *
+ * Sets a scale that is multiplied to the device coordinates determined
+ * by the CTM when drawing to @surface. One common use for this is to
+ * render to very high resolution display devices at a scale factor, so
+ * that code that assumes 1 pixel will be a certain size will still work.
+ * Setting a transformation via cairo_translate() isn't
+ * sufficient to do this, since functions like
+ * cairo_device_to_user() will expose the hidden scale.
+ *
+ * Note that the scale affects drawing to the surface as well as
+ * using the surface in a source pattern.
+ *
+ * Since: 1.14
**/
void
-_cairo_surface_set_device_scale (cairo_surface_t *surface,
- double sx,
- double sy)
+cairo_surface_set_device_scale (cairo_surface_t *surface,
+ double x_scale,
+ double y_scale)
{
cairo_status_t status;
@@ -1656,8 +1753,8 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
return;
}
- surface->device_transform.xx = sx;
- surface->device_transform.yy = sy;
+ surface->device_transform.xx = x_scale;
+ surface->device_transform.yy = y_scale;
surface->device_transform.xy = 0.0;
surface->device_transform.yx = 0.0;
@@ -1668,6 +1765,30 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
_cairo_observers_notify (&surface->device_transform_observers, surface);
}
+slim_hidden_def (cairo_surface_set_device_scale);
+
+/**
+ * cairo_surface_get_device_scale:
+ * @surface: a #cairo_surface_t
+ * @x_scale: the scale in the X direction, in device units
+ * @y_scale: the scale in the Y direction, in device units
+ *
+ * This function returns the previous device offset set by
+ * cairo_surface_set_device_scale().
+ *
+ * Since: 1.14
+ **/
+void
+cairo_surface_get_device_scale (cairo_surface_t *surface,
+ double *x_scale,
+ double *y_scale)
+{
+ if (x_scale)
+ *x_scale = surface->device_transform.xx;
+ if (y_scale)
+ *y_scale = surface->device_transform.yy;
+}
+slim_hidden_def (cairo_surface_get_device_scale);
/**
* cairo_surface_set_device_offset:
@@ -2004,6 +2125,8 @@ _cairo_surface_paint (cairo_surface_t *surface,
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
return surface->status;
+ if (unlikely (surface->finished))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
@@ -2040,6 +2163,8 @@ _cairo_surface_mask (cairo_surface_t *surface,
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
return surface->status;
+ if (unlikely (surface->finished))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
@@ -2097,6 +2222,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
return surface->status;
+ if (unlikely (surface->finished))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
@@ -2177,6 +2304,8 @@ _cairo_surface_stroke (cairo_surface_t *surface,
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
return surface->status;
+ if (unlikely (surface->finished))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
@@ -2220,6 +2349,8 @@ _cairo_surface_fill (cairo_surface_t *surface,
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
return surface->status;
+ if (unlikely (surface->finished))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
@@ -2351,6 +2482,13 @@ _cairo_surface_get_extents (cairo_surface_t *surface,
{
cairo_bool_t bounded;
+ if (unlikely (surface->status))
+ goto zero_extents;
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error(surface, CAIRO_STATUS_SURFACE_FINISHED);
+ goto zero_extents;
+ }
+
bounded = FALSE;
if (surface->backend->get_extents != NULL)
bounded = surface->backend->get_extents (surface, extents);
@@ -2359,6 +2497,11 @@ _cairo_surface_get_extents (cairo_surface_t *surface,
_cairo_unbounded_rectangle_init (extents);
return bounded;
+
+zero_extents:
+ extents->x = extents->y = 0;
+ extents->width = extents->height = 0;
+ return TRUE;
}
/**
@@ -2430,11 +2573,12 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_int_status_t status;
- cairo_scaled_font_t *dev_scaled_font = scaled_font;
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
return surface->status;
+ if (unlikely (surface->finished))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
if (num_glyphs == 0 && utf8_len == 0)
return CAIRO_STATUS_SUCCESS;
@@ -2453,25 +2597,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (unlikely (status))
return status;
- if (_cairo_surface_has_device_transform (surface) &&
- ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
- {
- cairo_font_options_t font_options;
- cairo_matrix_t dev_ctm, font_matrix;
-
- cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
- cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
- cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
- cairo_scaled_font_get_font_options (scaled_font, &font_options);
- dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
- &font_matrix,
- &dev_ctm,
- &font_options);
- }
- status = cairo_scaled_font_status (dev_scaled_font);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
status = CAIRO_INT_STATUS_UNSUPPORTED;
/* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
@@ -2485,7 +2610,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font,
+ scaled_font,
clip);
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
@@ -2494,7 +2619,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
- dev_scaled_font,
+ scaled_font,
clip);
}
} else {
@@ -2503,7 +2628,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
- dev_scaled_font,
+ scaled_font,
clip);
} else if (surface->backend->show_text_glyphs != NULL) {
/* Intentionally only try show_text_glyphs method for show_glyphs
@@ -2519,14 +2644,11 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font,
+ scaled_font,
clip);
}
}
- if (dev_scaled_font != scaled_font)
- cairo_scaled_font_destroy (dev_scaled_font);
-
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
surface->serial++;
@@ -2557,6 +2679,16 @@ _cairo_surface_set_resolution (cairo_surface_t *surface,
surface->y_resolution = y_res;
}
+/**
+ * _cairo_surface_create_in_error:
+ * @status: the error status
+ *
+ * Return an appropriate static error surface for the error status.
+ * On error, surface creation functions should always return a surface
+ * created with _cairo_surface_create_in_error() instead of a new surface
+ * in an error state. This simplifies internal code as no refcounting has
+ * to be done.
+ **/
cairo_surface_t *
_cairo_surface_create_in_error (cairo_status_t status)
{
@@ -2617,6 +2749,7 @@ _cairo_surface_create_in_error (cairo_status_t status)
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
case CAIRO_STATUS_DEVICE_FINISHED:
+ case CAIRO_STATUS_JBIG2_GLOBAL_MISSING:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t *) &_cairo_surface_nil;