Bug 542605. Update cairo to 12d521df8acc483b2daa844d4f05dc2fe2765ba6. r=vlad,jwatt,bas

Reland after fixing quartz related clipping bug.
This commit is contained in:
Jeff Muizelaar 2010-04-05 22:28:54 -04:00
parent cba86403da
commit a6ac7bede6
179 changed files with 32895 additions and 11712 deletions

View File

@ -68,6 +68,34 @@ premultiply-alpha-solid-gradients.patch: bug 539165; multiply the solid color by
xlib-initialize-members.path: bug 548793; initialize XRender version if the server doesn't have the extension
remove-comma: remove a comma from enum
d2d.patch: add d2d support
fix-zero-len-graident.patch: fix zero length gradients
fix-clip-copy.patch: fix clip copying
fix-clip-region-simplification.patch: fixes a bug in clip region simplifications
expand-in-stroke-limits.patch: expand the in-stroke limits to avoid a bug
d2d-dwrite.patch: update the d2d/dwrite stuff
add-a-stash-of-cairo_t-s.patch: use the stash to avoid malloc/freeing cairo_t's
bgr.patch: fix image wrapping
disable-server-graidents.patch: disable server-side gradients
clip-invariant.patch: make rasterization closer to being clip invariant
fix-unnecessary-fallback.patch: avoid unnecessary fallback
handle-a1-upload.patch: handle a1 image uploads through converter
surface-clipper.patch: remove an incorrect optimization
==== pixman patches ====
pixman-neon.patch: add ARM NEON optimized compositing functions

View File

@ -0,0 +1,75 @@
commit dfec2c249915560cedd2b49326c6629ad8a0b0f2
Author: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Tue Mar 2 16:01:41 2010 -0500
add a stash of cairo_t's
diff --git a/src/cairo.c b/src/cairo.c
index 3c9d892..4b27b83 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -119,7 +119,63 @@ _cairo_set_error (cairo_t *cr, cairo_status_t status)
_cairo_status_set_error (&cr->status, _cairo_error (status));
}
-#if HAS_ATOMIC_OPS
+#if defined(_MSC_VER)
+#pragma intrinsic(_BitScanForward)
+static __forceinline int
+ffs(int x)
+{
+ unsigned long i;
+
+ if (_BitScanForward(&i, x) != 0)
+ return i + 1;
+
+ return 0;
+}
+#endif
+
+
+#if CAIRO_NO_MUTEX
+/* We keep a small stash of contexts to reduce malloc pressure */
+#define CAIRO_STASH_SIZE 4
+static struct {
+ cairo_t pool[CAIRO_STASH_SIZE];
+ int occupied;
+} _context_stash;
+
+static cairo_t *
+_context_get (void)
+{
+ int avail, old, new;
+
+ old = _context_stash.occupied;
+ avail = ffs (~old) - 1;
+ if (avail >= CAIRO_STASH_SIZE)
+ return malloc (sizeof (cairo_t));
+
+ new = old | (1 << avail);
+ _context_stash.occupied = new;
+
+ return &_context_stash.pool[avail];
+}
+
+static void
+_context_put (cairo_t *cr)
+{
+ int old, new, avail;
+
+ if (cr < &_context_stash.pool[0] ||
+ cr >= &_context_stash.pool[CAIRO_STASH_SIZE])
+ {
+ free (cr);
+ return;
+ }
+
+ avail = ~(1 << (cr - &_context_stash.pool[0]));
+ old = _context_stash.occupied;
+ new = old & avail;
+ _context_stash.occupied = new;
+}
+#elif HAS_ATOMIC_OPS
/* We keep a small stash of contexts to reduce malloc pressure */
#define CAIRO_STASH_SIZE 4
static struct {

104
gfx/cairo/bgr.patch Normal file
View File

@ -0,0 +1,104 @@
commit d2120bdb06c9aacc470bb346d6bc2071c2e0749d
Author: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Fri Mar 12 15:32:09 2010 -0500
BGR
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 332e3ab..4a1d6a0 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1501,7 +1501,9 @@ static void
_wrap_release_source_image (void *data)
{
struct acquire_source_image_data *acquire_data = data;
- _cairo_surface_release_source_image (acquire_data->src, acquire_data->image, acquire_data->image_extra);
+ _cairo_surface_release_source_image (acquire_data->src,
+ acquire_data->image,
+ acquire_data->image_extra);
free(data);
}
@@ -1515,42 +1517,47 @@ _wrap_image (cairo_surface_t *src,
cairo_image_surface_t *surface;
cairo_status_t status;
- struct acquire_source_image_data *data = malloc(sizeof(*data));
+ struct acquire_source_image_data *data = malloc (sizeof (*data));
+ if (unlikely (data == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
data->src = src;
data->image = image;
data->image_extra = image_extra;
- surface = (cairo_image_surface_t*)cairo_image_surface_create_for_data (image->data,
- image->format,
- image->width,
- image->height,
- image->stride);
+ surface = (cairo_image_surface_t*)
+ _cairo_image_surface_create_with_pixman_format (image->data,
+ image->pixman_format,
+ image->width,
+ image->height,
+ image->stride);
status = surface->base.status;
- if (status)
+ if (status) {
+ free (data);
return status;
+ }
status = _cairo_user_data_array_set_data (&surface->base.user_data,
- &wrap_image_key,
- data,
- _wrap_release_source_image);
+ &wrap_image_key,
+ data,
+ _wrap_release_source_image);
if (status) {
cairo_surface_destroy (&surface->base);
+ free (data);
return status;
}
-/*
- pixman_image_set_component_alpha (surface->pixman_image,
- pixman_image_get_component_alpha (image->pixman_image));
-*/
+
+ pixman_image_set_component_alpha (
+ surface->pixman_image,
+ pixman_image_get_component_alpha (image->pixman_image));
+
*out = surface;
return CAIRO_STATUS_SUCCESS;
}
-
/**
* _cairo_surface_clone_similar:
* @surface: a #cairo_surface_t
* @src: the source image
- * @content: target content mask
* @src_x: extent for the rectangle in src we actually care about
* @src_y: extent for the rectangle in src we actually care about
* @width: extent for the rectangle in src we actually care about
@@ -1627,12 +1634,12 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
_cairo_surface_release_source_image (src, image, image_extra);
} else {
status =
- surface->backend->clone_similar (surface, &image->base,
- src_x, src_y,
- width, height,
- clone_offset_x,
- clone_offset_y,
- clone_out);
+ surface->backend->clone_similar (surface, &image->base,
+ src_x, src_y,
+ width, height,
+ clone_offset_x,
+ clone_offset_y,
+ clone_out);
cairo_surface_destroy(&image->base);
}
}

View File

@ -74,7 +74,10 @@ CSRCS = \
cairo-array.c \
cairo-atomic.c \
cairo-bentley-ottmann.c \
cairo-cache.c \
cairo-bentley-ottmann-rectilinear.c \
cairo-bentley-ottmann-rectangular.c \
cairo-base64-stream.c \
cairo-cache.c \
cairo-clip.c \
cairo-color.c \
cairo-debug.c \
@ -92,7 +95,6 @@ CSRCS = \
cairo-image-surface.c \
cairo-lzw.c \
cairo-matrix.c \
cairo-meta-surface.c \
cairo-misc.c \
cairo-mutex.c \
cairo-output-stream.c \
@ -106,17 +108,20 @@ CSRCS = \
cairo-pattern.c \
cairo-pen.c \
cairo-polygon.c \
cairo-recording-surface.c \
cairo-rectangle.c \
cairo-region.c \
cairo-scaled-font.c \
cairo-scaled-font-subsets.c \
cairo-skiplist.c \
cairo-slope.c \
cairo-spans.c \
cairo-spline.c \
cairo-stroke-style.c \
cairo-surface.c \
cairo-surface-clipper.c \
cairo-surface-fallback.c \
cairo-surface-wrapper.c \
cairo-tee-surface.c \
cairo-tor-scan-converter.c \
cairo-toy-font-face.c \
cairo-traps.c \

View File

@ -38,13 +38,11 @@
#include "cairoint.h"
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height);
_cairo_analysis_surface_create (cairo_surface_t *target);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
const cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,

View File

@ -38,14 +38,13 @@
#include "cairo-analysis-surface-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
typedef struct {
cairo_surface_t base;
int width;
int height;
cairo_surface_t *target;
cairo_surface_t *target;
cairo_bool_t first_op;
cairo_bool_t has_supported;
@ -53,7 +52,6 @@ typedef struct {
cairo_region_t supported_region;
cairo_region_t fallback_region;
cairo_rectangle_int_t current_clip;
cairo_box_t page_bbox;
cairo_bool_t has_ctm;
@ -78,9 +76,9 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (status_a == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN ||
status_b == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
@ -94,64 +92,41 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
}
static cairo_int_status_t
_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern)
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern)
{
cairo_surface_t *analysis = &surface->base;
const cairo_surface_pattern_t *surface_pattern;
cairo_status_t status;
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
cairo_rectangle_int_t old_clip;
cairo_rectangle_int_t meta_extents;
int old_width;
int old_height;
cairo_status_t status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (_cairo_surface_is_meta (surface_pattern->surface));
assert (_cairo_surface_is_recording (surface_pattern->surface));
old_width = surface->width;
old_height = surface->height;
old_clip = surface->current_clip;
status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
if (_cairo_status_is_error (status))
return status;
surface->width = meta_extents.width;
surface->height = meta_extents.height;
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
p2d = pattern->matrix;
status = cairo_matrix_invert (&p2d);
/* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
analysis);
if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status;
status = _cairo_recording_surface_replay_and_create_regions (surface_pattern->surface,
&surface->base);
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
surface->current_clip = old_clip;
surface->width = old_width;
surface->height = old_height;
return status;
}
static cairo_int_status_t
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
{
cairo_int_status_t status;
cairo_box_t bbox;
@ -174,26 +149,33 @@ _add_operation (cairo_analysis_surface_t *surface,
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
int tx, ty;
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
rect->x += tx;
rect->y += ty;
} else {
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
&bbox, NULL);
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
_cairo_box_round_to_rectangle (&bbox, rect);
}
_cairo_box_round_to_rectangle (&bbox, rect);
}
if (surface->first_op) {
@ -234,8 +216,7 @@ _add_operation (cairo_analysis_surface_t *surface,
* this region will be emitted as native operations.
*/
surface->has_supported = TRUE;
status = cairo_region_union_rectangle (&surface->supported_region, rect);
return status;
return cairo_region_union_rectangle (&surface->supported_region, rect);
}
/* Add the operation to the unsupported region. This region will
@ -246,7 +227,7 @@ _add_operation (cairo_analysis_surface_t *surface,
status = cairo_region_union_rectangle (&surface->fallback_region, rect);
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
* unsupported operations to the meta surface as using
* unsupported operations to the recording surface as using
* CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
* invoke the cairo-surface-fallback path then return
* CAIRO_STATUS_SUCCESS.
@ -270,33 +251,7 @@ _cairo_analysis_surface_finish (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
if (path == NULL) {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
} else {
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
_cairo_path_fixed_approximate_clip_extents (path, &extents);
is_empty = _cairo_rectangle_intersect (&surface->current_clip,
&extents);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_analysis_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -305,76 +260,102 @@ _cairo_analysis_surface_get_extents (void *abstract_surface,
return _cairo_surface_get_extents (surface->target, rectangle);
}
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *paint_extents)
static void
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents;
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_empty;
if (!surface->target->backend->paint)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->paint) (surface->target, op,
source, NULL);
clip_extents = NULL;
if (clip != NULL)
clip_extents = _cairo_clip_get_extents (clip);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
if (clip_extents != NULL)
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
static void
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
is_empty = _cairo_surface_get_extents (&surface->base, extents);
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
_cairo_pattern_get_extents (source, &source_extents);
is_empty = _cairo_rectangle_intersect (extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (paint_extents)
*paint_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
_rectangle_intersect_clip (extents, clip);
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *mask_extents)
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->paint (surface->target,
op, source, clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->mask)
if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->mask) (surface->target, op,
source, mask, NULL);
} else {
backend_status =
surface->target->backend->mask (surface->target,
op, source, mask, clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t *) source;
if (_cairo_surface_is_meta (surface_pattern->surface)) {
if (_cairo_surface_is_recording (surface_pattern->surface)) {
backend_source_status =
_analyze_meta_surface_pattern (surface, source);
_analyze_recording_surface_pattern (surface, source);
if (_cairo_status_is_error (backend_source_status))
return backend_source_status;
}
@ -382,9 +363,9 @@ _cairo_analysis_surface_mask (void *abstract_surface,
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
if (_cairo_surface_is_meta (surface_pattern->surface)) {
if (_cairo_surface_is_recording (surface_pattern->surface)) {
backend_mask_status =
_analyze_meta_surface_pattern (surface, mask);
_analyze_recording_surface_pattern (surface, mask);
if (_cairo_status_is_error (backend_mask_status))
return backend_mask_status;
}
@ -395,37 +376,19 @@ _cairo_analysis_surface_mask (void *abstract_surface,
backend_mask_status);
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
status = _cairo_pattern_get_extents (mask, &mask_extents);
if (unlikely (status))
return status;
_cairo_pattern_get_extents (mask, &mask_extents);
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (mask_extents)
*mask_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@ -438,55 +401,61 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *stroke_extents)
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->stroke)
if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->stroke) (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias, NULL);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
} else {
backend_status =
surface->target->backend->stroke (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_path_fixed_approximate_stroke_extents (path,
style, ctm,
&mask_extents);
/* If the backend can handle the stroke, then mark the approximate
* extents of the operation. However, if we need to fallback in order
* to draw the stroke, then ensure that the fallback is as tight as
* possible -- both to minimise output file size and to ensure good
* quality printed output for neighbouring regions.
*/
if (backend_status == CAIRO_STATUS_SUCCESS) {
_cairo_path_fixed_approximate_stroke_extents (path,
style, ctm,
&mask_extents);
} else {
cairo_status_t status;
status = _cairo_path_fixed_stroke_extents (path, style,
ctm, ctm_inverse,
tolerance,
&mask_extents);
if (unlikely (status))
return status;
}
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
if (stroke_extents)
*stroke_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@ -497,53 +466,49 @@ _cairo_analysis_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *fill_extents)
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->fill)
if (surface->target->backend->fill == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->fill) (surface->target, op,
source, path, fill_rule,
tolerance, antialias, NULL);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
} else {
backend_status =
surface->target->backend->fill (surface->target, op,
source, path, fill_rule,
tolerance, antialias,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_path_fixed_approximate_fill_extents (path,
&mask_extents);
/* We want speed for the likely case where the operation can be
* performed natively, but accuracy if we have to resort to
* using images.
*/
if (backend_status == CAIRO_STATUS_SUCCESS) {
_cairo_path_fixed_approximate_fill_extents (path, &mask_extents);
} else {
_cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
&mask_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
if (fill_extents)
*fill_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@ -553,8 +518,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *show_glyphs_extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@ -562,58 +527,56 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_bool_t is_empty;
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs)
backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
remaining_glyphs, NULL);
else if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font, NULL);
if (surface->target->backend->show_glyphs != NULL) {
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip,
remaining_glyphs);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
else if (surface->target->backend->show_text_glyphs != NULL)
{
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
else
{
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents);
&glyph_extents,
NULL);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
if (show_glyphs_extents)
*show_glyphs_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_bool_t
@ -636,7 +599,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *show_text_glyphs_extents)
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@ -645,61 +608,59 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
scaled_font, NULL);
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
if (surface->target->backend->show_text_glyphs != NULL) {
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
surface->target->backend->show_glyphs != NULL)
{
int remaining_glyphs = num_glyphs;
backend_status = surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
&remaining_glyphs, NULL);
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip,
&remaining_glyphs);
if (_cairo_status_is_error (backend_status))
return backend_status;
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
backend_status = CAIRO_STATUS_SUCCESS;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
backend_status = _analyze_recording_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents);
&glyph_extents,
NULL);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
if (show_text_glyphs_extents)
*show_text_glyphs_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
@ -718,8 +679,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_analysis_surface_intersect_clip_path,
_cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -734,7 +693,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
_cairo_analysis_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@ -743,9 +701,7 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
};
cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height)
_cairo_analysis_surface_create (cairo_surface_t *target)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
@ -763,8 +719,6 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
_cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
surface->width = width;
surface->height = height;
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
@ -781,24 +735,12 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
if (width == -1 && height == -1) {
surface->current_clip.x = CAIRO_RECT_INT_MIN;
surface->current_clip.y = CAIRO_RECT_INT_MIN;
surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
} else {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
}
return &surface->base;
}
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
const cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface;
@ -808,7 +750,7 @@ _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
}
void
@ -871,22 +813,18 @@ _return_success (void)
}
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_set_clip_region_func) (void *surface,
cairo_region_t *region);
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
@ -898,7 +836,7 @@ typedef cairo_int_status_t
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
@ -908,7 +846,7 @@ typedef cairo_int_status_t
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
@ -917,8 +855,8 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
@ -937,8 +875,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
(_set_clip_region_func) _return_success, /* set_clip_region */
NULL, /* intersect_clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -953,7 +889,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View File

@ -116,7 +116,7 @@ _arc_segments_needed (double angle,
major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius);
max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis);
return (int) ceil (angle / max_angle);
return ceil (fabs (angle) / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius

View File

@ -43,6 +43,12 @@
#include "config.h"
#endif
/* The autoconf on OpenBSD 4.5 produces the malformed constant name
* SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */
#if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__)
# define SIZEOF_VOID_P SIZEOF_VOID__
#endif
CAIRO_BEGIN_DECLS
#if HAVE_INTEL_ATOMIC_PRIMITIVES
@ -51,6 +57,9 @@ CAIRO_BEGIN_DECLS
typedef int cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_set(x, value) ((*x) = value)
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
@ -70,6 +79,35 @@ typedef long long cairo_atomic_intptr_t;
#endif
#if HAVE_LIB_ATOMIC_OPS
#include <atomic_ops.h>
#define HAS_ATOMIC_OPS 1
typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_set(x, value) (AO_store_full (x))
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) ((cairo_atomic_int_t) AO_compare_and_swap_full(x, oldv, newv) ? oldv : *x)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef unsigned long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef unsigned long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
(void*) (cairo_atomic_intptr_t) _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
#endif
#ifndef HAS_ATOMIC_OPS
@ -87,9 +125,6 @@ _cairo_atomic_int_cmpxchg (int *x, int oldv, int newv);
cairo_private void *
_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv);
#endif
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
# include "cairo-compiler-private.h"
@ -107,14 +142,16 @@ _cairo_atomic_int_set (int *x, int value);
#endif
#endif
#define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)
#define _cairo_atomic_uint_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg((int *)x, oldv, newv)
_cairo_atomic_int_cmpxchg((cairo_atomic_int_t *)x, oldv, newv)
#define _cairo_status_set_error(status, err) do { \
/* hide compiler warnings about cairo_status_t != int (gcc treats its as \
* an unsigned integer instead, and about ignoring the return value. */ \
int ret__ = _cairo_atomic_int_cmpxchg ((int *) status, CAIRO_STATUS_SUCCESS, err); \
int ret__ = _cairo_atomic_int_cmpxchg ((cairo_atomic_int_t *) status, CAIRO_STATUS_SUCCESS, err); \
(void) ret__; \
} while (0)

View File

@ -0,0 +1,143 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base64_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned int in_mem;
unsigned int trailing;
unsigned char src[3];
} cairo_base64_stream_t;
static char const base64_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static cairo_status_t
_cairo_base64_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base64_stream_t * stream = (cairo_base64_stream_t *) base;
unsigned char *src = stream->src;
unsigned int i;
if (stream->in_mem + length < 3) {
for (i = 0; i < length; i++) {
src[i + stream->in_mem] = *data++;
}
stream->in_mem += length;
return CAIRO_STATUS_SUCCESS;
}
do {
unsigned char dst[4];
for (i = stream->in_mem; i < 3; i++) {
src[i] = *data++;
length--;
}
stream->in_mem = 0;
dst[0] = base64_table[src[0] >> 2];
dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4];
dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6];
dst[3] = base64_table[src[2] & 0xfc >> 2];
/* Special case for the last missing bits */
switch (stream->trailing) {
case 2:
dst[2] = '=';
case 1:
dst[3] = '=';
default:
break;
}
_cairo_output_stream_write (stream->output, dst, 4);
} while (length >= 3);
for (i = 0; i < length; i++) {
src[i] = *data++;
}
stream->in_mem = length;
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_base64_stream_close (cairo_output_stream_t *base)
{
cairo_base64_stream_t *stream = (cairo_base64_stream_t *) base;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (stream->in_mem > 0) {
memset (stream->src + stream->in_mem, 0, 3 - stream->in_mem);
stream->trailing = 3 - stream->in_mem;
stream->in_mem = 3;
status = _cairo_base64_stream_write (base, NULL, 0);
}
return status;
}
cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output)
{
cairo_base64_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_base64_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_base64_stream_write,
NULL,
_cairo_base64_stream_close);
stream->output = output;
stream->in_mem = 0;
stream->trailing = 0;
return &stream->base;
}

View File

@ -102,9 +102,6 @@ _cairo_base85_stream_close (cairo_output_stream_t *base)
_cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
}
/* Mark end of base85 data */
_cairo_output_stream_printf (stream->output, "~>");
return _cairo_output_stream_get_status (stream->output);
}

View File

@ -0,0 +1,739 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-combsort-private.h"
#include "cairo-list-private.h"
typedef struct _cairo_bo_rectangle cairo_bo_rectangle_t;
typedef struct _cairo_bo_edge cairo_bo_edge_t;
/* A deferred trapezoid of an edge */
typedef struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
} cairo_bo_trap_t;
struct _cairo_bo_edge {
int x;
int dir;
cairo_bo_trap_t deferred_trap;
cairo_list_t link;
};
struct _cairo_bo_rectangle {
cairo_bo_edge_t left, right;
int top, bottom;
};
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
typedef struct _pqueue {
int size, max_size;
cairo_bo_rectangle_t **elements;
cairo_bo_rectangle_t *elements_embedded[1024];
} pqueue_t;
typedef struct _cairo_bo_sweep_line {
cairo_bo_rectangle_t **rectangles;
pqueue_t stop;
cairo_list_t sweep;
cairo_list_t *current_left, *current_right;
int32_t current_y;
int32_t last_y;
} cairo_bo_sweep_line_t;
#define DEBUG_TRAPS 0
#if DEBUG_TRAPS
static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
int n;
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < traps->num_traps; n++) {
fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
traps->traps[n].top,
traps->traps[n].bottom,
traps->traps[n].left.p1.x,
traps->traps[n].left.p1.y,
traps->traps[n].left.p2.x,
traps->traps[n].left.p2.y,
traps->traps[n].right.p1.x,
traps->traps[n].right.p1.y,
traps->traps[n].right.p2.x,
traps->traps[n].right.p2.y);
}
fprintf (file, "\n");
fclose (file);
}
}
#else
#define dump_traps(traps, filename)
#endif
static inline int
cairo_bo_rectangle_compare_start (const cairo_bo_rectangle_t *a,
const cairo_bo_rectangle_t *b)
{
return a->top - b->top;
}
static inline int
_cairo_bo_rectangle_compare_stop (const cairo_bo_rectangle_t *a,
const cairo_bo_rectangle_t *b)
{
return a->bottom - b->bottom;
}
static inline void
_pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
pq->elements = pq->elements_embedded;
pq->elements[PQ_FIRST_ENTRY] = NULL;
}
static inline void
_pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
static cairo_status_t
_pqueue_grow (pqueue_t *pq)
{
cairo_bo_rectangle_t **new_elements;
pq->max_size *= 2;
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (cairo_bo_rectangle_t *));
if (unlikely (new_elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (cairo_bo_rectangle_t *));
if (unlikely (new_elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pq->elements = new_elements;
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_pqueue_push (pqueue_t *pq, cairo_bo_rectangle_t *rectangle)
{
cairo_bo_rectangle_t **elements;
int i, parent;
if (unlikely (pq->size + 1 == pq->max_size)) {
cairo_status_t status;
status = _pqueue_grow (pq);
if (unlikely (status))
return status;
}
elements = pq->elements;
for (i = ++pq->size;
i != PQ_FIRST_ENTRY &&
_cairo_bo_rectangle_compare_stop (rectangle,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
elements[i] = rectangle;
return CAIRO_STATUS_SUCCESS;
}
static inline void
_pqueue_pop (pqueue_t *pq)
{
cairo_bo_rectangle_t **elements = pq->elements;
cairo_bo_rectangle_t *tail;
int child, i;
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
_cairo_bo_rectangle_compare_stop (elements[child+1],
elements[child]) < 0)
{
child++;
}
if (_cairo_bo_rectangle_compare_stop (elements[child], tail) >= 0)
break;
elements[i] = elements[child];
}
elements[i] = tail;
}
static inline cairo_bo_rectangle_t *
_cairo_bo_rectangle_pop_start (cairo_bo_sweep_line_t *sweep_line)
{
return *sweep_line->rectangles++;
}
static inline cairo_bo_rectangle_t *
_cairo_bo_rectangle_peek_stop (cairo_bo_sweep_line_t *sweep_line)
{
return sweep_line->stop.elements[PQ_FIRST_ENTRY];
}
CAIRO_COMBSORT_DECLARE (_cairo_bo_rectangle_sort,
cairo_bo_rectangle_t *,
cairo_bo_rectangle_compare_start)
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_rectangle_t **rectangles,
int num_rectangles)
{
_cairo_bo_rectangle_sort (rectangles, num_rectangles);
rectangles[num_rectangles] = NULL;
sweep_line->rectangles = rectangles;
cairo_list_init (&sweep_line->sweep);
sweep_line->current_left = &sweep_line->sweep;
sweep_line->current_right = &sweep_line->sweep;
sweep_line->current_y = INT32_MIN;
sweep_line->last_y = INT32_MIN;
_pqueue_init (&sweep_line->stop);
}
static void
_cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line)
{
_pqueue_fini (&sweep_line->stop);
}
static inline cairo_bo_edge_t *
link_to_edge (cairo_list_t *elt)
{
return cairo_container_of (elt, cairo_bo_edge_t, link);
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
cairo_line_t _left = {
{ left->x, trap->top },
{ left->x, bot },
}, _right = {
{ trap->right->x, trap->top },
{ trap->right->x, bot },
};
_cairo_traps_add_trap (traps, trap->top, bot, &_left, &_right);
}
trap->right = NULL;
return _cairo_traps_status (traps);
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
{
cairo_status_t status;
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
if (left->deferred_trap.right != NULL) {
if (right != NULL && left->deferred_trap.right->x == right->x) {
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_bo_edge_end_trap (left, top, traps);
if (unlikely (status))
return status;
}
if (right != NULL && left->x != right->x) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
}
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_sweep_line_t *sweep,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
int top = sweep->current_y;
cairo_list_t *pos = &sweep->sweep;
cairo_status_t status;
if (sweep->last_y == sweep->current_y)
return CAIRO_STATUS_SUCCESS;
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
do {
cairo_bo_edge_t *left, *right;
int in_out;
pos = pos->next;
if (pos == &sweep->sweep)
break;
left = link_to_edge (pos);
in_out = left->dir;
/* Check if there is a co-linear edge with an existing trap */
if (left->deferred_trap.right == NULL) {
right = link_to_edge (pos->next);
while (unlikely (right->x == left->x)) {
if (right->deferred_trap.right != NULL) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
break;
}
if (right->link.next == &sweep->sweep)
break;
right = link_to_edge (right->link.next);
}
}
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
right = link_to_edge (left->link.next);
do {
/* End all subsumed traps */
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
in_out += right->dir;
if (in_out == 0) {
/* skip co-linear edges */
if (likely (right->link.next == &sweep->sweep ||
right->x != link_to_edge (right->link.next)->x))
{
break;
}
}
right = link_to_edge (right->link.next);
} while (TRUE);
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
pos = &right->link;
} while (TRUE);
} else {
cairo_bo_edge_t *left, *right;
do {
int in_out = 0;
pos = pos->next;
if (pos == &sweep->sweep)
break;
left = link_to_edge (pos);
pos = pos->next;
do {
right = link_to_edge (pos);
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
if ((in_out++ & 1) == 0) {
cairo_list_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = pos->next;
if (next != &sweep->sweep)
skip = right->x == link_to_edge (next)->x;
if (! skip)
break;
}
pos = pos->next;
} while (TRUE);
right = pos == &sweep->sweep ? NULL : link_to_edge (pos);
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
} while (right != NULL);
}
sweep->last_y = sweep->current_y;
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_cairo_bo_sweep_line_delete_edge (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge,
cairo_traps_t *traps)
{
if (edge->deferred_trap.right != NULL) {
cairo_bo_edge_t *next = link_to_edge (edge->link.next);
if (&next->link != &sweep_line->sweep && next->x == edge->x) {
next->deferred_trap = edge->deferred_trap;
} else {
cairo_status_t status;
status = _cairo_bo_edge_end_trap (edge,
sweep_line->current_y,
traps);
if (unlikely (status))
return status;
}
}
if (sweep_line->current_left == &edge->link)
sweep_line->current_left = edge->link.prev;
if (sweep_line->current_right == &edge->link)
sweep_line->current_right = edge->link.next;
cairo_list_del (&edge->link);
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_rectangle_t *rectangle,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_status_t status;
if (rectangle->bottom != sweep_line->current_y) {
status = _active_edges_to_traps (sweep_line, fill_rule, traps);
if (unlikely (status))
return status;
sweep_line->current_y = rectangle->bottom;
}
status = _cairo_bo_sweep_line_delete_edge (sweep_line,
&rectangle->left,
traps);
if (unlikely (status))
return status;
status = _cairo_bo_sweep_line_delete_edge (sweep_line,
&rectangle->right,
traps);
if (unlikely (status))
return status;
_pqueue_pop (&sweep_line->stop);
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
validate_sweep_line (cairo_bo_sweep_line_t *sweep_line)
{
int32_t last_x = INT32_MIN;
cairo_bo_edge_t *edge;
cairo_list_foreach_entry (edge, cairo_bo_edge_t, &sweep_line->sweep, link) {
if (edge->x < last_x)
return FALSE;
last_x = edge->x;
}
return TRUE;
}
static inline cairo_status_t
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_rectangle_t *rectangle,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_list_t *pos;
cairo_status_t status;
if (rectangle->top != sweep_line->current_y) {
cairo_bo_rectangle_t *stop;
stop = _cairo_bo_rectangle_peek_stop (sweep_line);
while (stop != NULL && stop->bottom < rectangle->top) {
status = _cairo_bo_sweep_line_delete (sweep_line, stop,
fill_rule, traps);
if (unlikely (status))
return status;
stop = _cairo_bo_rectangle_peek_stop (sweep_line);
}
status = _active_edges_to_traps (sweep_line, fill_rule, traps);
if (unlikely (status))
return status;
sweep_line->current_y = rectangle->top;
}
/* right edge */
pos = sweep_line->current_right;
if (pos == &sweep_line->sweep)
pos = sweep_line->sweep.prev;
if (pos != &sweep_line->sweep) {
int cmp;
cmp = link_to_edge (pos)->x - rectangle->right.x;
if (cmp < 0) {
while (pos->next != &sweep_line->sweep &&
link_to_edge (pos->next)->x - rectangle->right.x < 0)
{
pos = pos->next;
}
} else if (cmp > 0) {
do {
pos = pos->prev;
} while (pos != &sweep_line->sweep &&
link_to_edge (pos)->x - rectangle->right.x > 0);
}
cairo_list_add (&rectangle->right.link, pos);
} else {
cairo_list_add_tail (&rectangle->right.link, pos);
}
sweep_line->current_right = &rectangle->right.link;
assert (validate_sweep_line (sweep_line));
/* left edge */
pos = sweep_line->current_left;
if (pos == &sweep_line->sweep)
pos = sweep_line->sweep.next;
if (pos != &sweep_line->sweep) {
int cmp;
if (link_to_edge (pos)->x >= rectangle->right.x) {
pos = rectangle->right.link.prev;
if (pos == &sweep_line->sweep)
goto left_done;
}
cmp = link_to_edge (pos)->x - rectangle->left.x;
if (cmp < 0) {
while (pos->next != &sweep_line->sweep &&
link_to_edge (pos->next)->x - rectangle->left.x < 0)
{
pos = pos->next;
}
} else if (cmp > 0) {
do {
pos = pos->prev;
} while (pos != &sweep_line->sweep &&
link_to_edge (pos)->x - rectangle->left.x > 0);
}
}
left_done:
cairo_list_add (&rectangle->left.link, pos);
sweep_line->current_left = &rectangle->left.link;
assert (validate_sweep_line (sweep_line));
return _pqueue_push (&sweep_line->stop, rectangle);
}
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular (cairo_bo_rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_rectangle_t *rectangle;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
_cairo_bo_sweep_line_init (&sweep_line, rectangles, num_rectangles);
while ((rectangle = _cairo_bo_rectangle_pop_start (&sweep_line)) != NULL) {
status = _cairo_bo_sweep_line_insert (&sweep_line, rectangle,
fill_rule, traps);
if (unlikely (status))
goto BAIL;
}
while ((rectangle = _cairo_bo_rectangle_peek_stop (&sweep_line)) != NULL) {
status = _cairo_bo_sweep_line_delete (&sweep_line, rectangle,
fill_rule, traps);
if (unlikely (status))
goto BAIL;
}
BAIL:
_cairo_bo_sweep_line_fini (&sweep_line);
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
cairo_bo_rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_rectangle_t)];
cairo_bo_rectangle_t *rectangles;
cairo_bo_rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
cairo_bo_rectangle_t **rectangles_ptrs;
cairo_status_t status;
int i;
if (unlikely (traps->num_traps == 0))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectangular);
dump_traps (traps, "bo-rects-traps-in.txt");
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (traps->num_traps,
sizeof (cairo_bo_rectangle_t) +
sizeof (cairo_bo_rectangle_t *),
sizeof (cairo_bo_rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
rectangles_ptrs = (cairo_bo_rectangle_t **) (rectangles + traps->num_traps);
}
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x < traps->traps[i].right.p1.x) {
rectangles[i].left.x = traps->traps[i].left.p1.x;
rectangles[i].left.dir = 1;
rectangles[i].right.x = traps->traps[i].right.p1.x;
rectangles[i].right.dir = -1;
} else {
rectangles[i].right.x = traps->traps[i].left.p1.x;
rectangles[i].right.dir = 1;
rectangles[i].left.x = traps->traps[i].right.p1.x;
rectangles[i].left.dir = -1;
}
rectangles[i].left.deferred_trap.right = NULL;
cairo_list_init (&rectangles[i].left.link);
rectangles[i].right.deferred_trap.right = NULL;
cairo_list_init (&rectangles[i].right.link);
rectangles[i].top = traps->traps[i].top;
rectangles[i].bottom = traps->traps[i].bottom;
rectangles_ptrs[i] = &rectangles[i];
}
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i,
fill_rule,
traps);
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
if (rectangles != stack_rectangles)
free (rectangles);
dump_traps (traps, "bo-rects-traps-out.txt");
return status;
}

View File

@ -0,0 +1,582 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2008 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-combsort-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
/* A deferred trapezoid of an edge */
struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
};
struct _cairo_bo_edge {
cairo_edge_t edge;
cairo_bo_edge_t *prev;
cairo_bo_edge_t *next;
cairo_bo_trap_t deferred_trap;
};
typedef enum {
CAIRO_BO_EVENT_TYPE_START,
CAIRO_BO_EVENT_TYPE_STOP
} cairo_bo_event_type_t;
typedef struct _cairo_bo_event {
cairo_bo_event_type_t type;
cairo_point_t point;
cairo_bo_edge_t *edge;
} cairo_bo_event_t;
typedef struct _cairo_bo_sweep_line {
cairo_bo_event_t **events;
cairo_bo_edge_t *head;
cairo_bo_edge_t *stopped;
int32_t current_y;
cairo_bo_edge_t *current_edge;
} cairo_bo_sweep_line_t;
static inline int
_cairo_point_compare (const cairo_point_t *a,
const cairo_point_t *b)
{
int cmp;
cmp = a->y - b->y;
if (likely (cmp))
return cmp;
return a->x - b->x;
}
static inline int
_cairo_bo_edge_compare (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
int cmp;
cmp = a->edge.line.p1.x - b->edge.line.p1.x;
if (likely (cmp))
return cmp;
return b->edge.bottom - a->edge.bottom;
}
static inline int
cairo_bo_event_compare (const cairo_bo_event_t *a,
const cairo_bo_event_t *b)
{
int cmp;
cmp = _cairo_point_compare (&a->point, &b->point);
if (likely (cmp))
return cmp;
cmp = a->type - b->type;
if (cmp)
return cmp;
return a - b;
}
static inline cairo_bo_event_t *
_cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line)
{
return *sweep_line->events++;
}
CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
cairo_bo_event_t *,
cairo_bo_event_compare)
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_event_t **events,
int num_events)
{
_cairo_bo_event_queue_sort (events, num_events);
events[num_events] = NULL;
sweep_line->events = events;
sweep_line->head = NULL;
sweep_line->current_y = INT32_MIN;
sweep_line->current_edge = NULL;
}
static void
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (sweep_line->current_edge != NULL) {
cairo_bo_edge_t *prev, *next;
int cmp;
cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge);
if (cmp < 0) {
prev = sweep_line->current_edge;
next = prev->next;
while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0)
prev = next, next = prev->next;
prev->next = edge;
edge->prev = prev;
edge->next = next;
if (next != NULL)
next->prev = edge;
} else if (cmp > 0) {
next = sweep_line->current_edge;
prev = next->prev;
while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0)
next = prev, prev = next->prev;
next->prev = edge;
edge->next = next;
edge->prev = prev;
if (prev != NULL)
prev->next = edge;
else
sweep_line->head = edge;
} else {
prev = sweep_line->current_edge;
edge->prev = prev;
edge->next = prev->next;
if (prev->next != NULL)
prev->next->prev = edge;
prev->next = edge;
}
} else {
sweep_line->head = edge;
}
sweep_line->current_edge = edge;
}
static void
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (edge->prev != NULL)
edge->prev->next = edge->next;
else
sweep_line->head = edge->next;
if (edge->next != NULL)
edge->next->prev = edge->prev;
if (sweep_line->current_edge == edge)
sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
}
static inline cairo_bool_t
edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{
return a->edge.line.p1.x == b->edge.line.p1.x;
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
_cairo_traps_add_trap (traps,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
}
trap->right = NULL;
return _cairo_traps_status (traps);
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
{
cairo_status_t status;
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
if (left->deferred_trap.right != NULL) {
if (right != NULL && edges_collinear (left->deferred_trap.right, right))
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_bo_edge_end_trap (left, top, traps);
if (unlikely (status))
return status;
}
if (right != NULL && ! edges_collinear (left, right)) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
}
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_edge_t *right;
cairo_status_t status;
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
while (left != NULL) {
int in_out;
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
in_out = left->edge.dir;
/* Check if there is a co-linear edge with an existing trap */
right = left->next;
if (left->deferred_trap.right == NULL) {
while (right != NULL && right->deferred_trap.right == NULL)
right = right->next;
if (right != NULL && edges_collinear (left, right)) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
}
}
/* End all subsumed traps */
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
in_out += right->edge.dir;
if (in_out == 0) {
/* skip co-linear edges */
if (right->next == NULL ||
! edges_collinear (right, right->next))
{
break;
}
}
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
left = right;
if (left != NULL)
left = left->next;
}
} else {
while (left != NULL) {
int in_out = 0;
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
if ((in_out++ & 1) == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_collinear (right, next);
if (! skip)
break;
}
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
left = right;
if (left != NULL)
left = left->next;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
cairo_status_t status;
_cairo_bo_sweep_line_init (&sweep_line, start_events, num_events);
while ((event = _cairo_bo_event_dequeue (&sweep_line))) {
if (event->point.y != sweep_line.current_y) {
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
fill_rule, traps);
if (unlikely (status))
return status;
sweep_line.current_y = event->point.y;
}
switch (event->type) {
case CAIRO_BO_EVENT_TYPE_START:
_cairo_bo_sweep_line_insert (&sweep_line, event->edge);
break;
case CAIRO_BO_EVENT_TYPE_STOP:
_cairo_bo_sweep_line_delete (&sweep_line, event->edge);
if (event->edge->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (event->edge,
sweep_line.current_y,
traps);
if (unlikely (status))
return status;
}
break;
}
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
int num_events;
int i, j;
if (unlikely (polygon->num_edges == 0))
return CAIRO_STATUS_SUCCESS;
num_events = 2 * polygon->num_edges;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
event_ptrs = (cairo_bo_event_t **) (events + num_events);
edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
}
for (i = j = 0; i < polygon->num_edges; i++) {
edges[i].edge = polygon->edges[i];
edges[i].deferred_trap.right = NULL;
edges[i].prev = NULL;
edges[i].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = polygon->edges[i].top;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = polygon->edges[i].bottom;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
}
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule, traps);
if (events != stack_events)
free (events);
traps->is_rectilinear = TRUE;
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
cairo_status_t status;
int i, j, k;
if (unlikely (traps->num_traps == 0))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectilinear);
i = 4 * traps->num_traps;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (i > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (i,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
event_ptrs = (cairo_bo_event_t **) (events + i);
edges = (cairo_bo_edge_t *) (event_ptrs + i + 1);
}
for (i = j = k = 0; i < traps->num_traps; i++) {
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].left;
edges[k].edge.dir = 1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
k++;
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].right;
edges[k].edge.dir = -1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
k++;
}
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
traps);
traps->is_rectilinear = TRUE;
if (events != stack_events)
free (events);
return status;
}

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,12 @@
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
enum {
CAIRO_CLIP_PATH_HAS_REGION = 0x1,
CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2,
CAIRO_CLIP_PATH_IS_BOX = 0x4
};
struct _cairo_clip_path {
cairo_reference_count_t ref_count;
cairo_path_fixed_t path;
@ -50,83 +56,80 @@ struct _cairo_clip_path {
double tolerance;
cairo_antialias_t antialias;
cairo_clip_path_t *prev;
cairo_rectangle_int_t extents;
/* partial caches */
unsigned int flags;
cairo_region_t *region;
cairo_surface_t *surface;
};
struct _cairo_clip {
cairo_clip_mode_t mode;
/* can be used as a cairo_hash_entry_t for live clips */
cairo_clip_path_t *path;
cairo_bool_t all_clipped;
/*
* Mask-based clipping for cases where the backend
* clipping isn't sufficiently able.
*
* The rectangle here represents the
* portion of the destination surface that this
* clip surface maps to, it does not
* represent the extents of the clip region or
* clip paths
*/
cairo_surface_t *surface;
cairo_rectangle_int_t surface_rect;
/*
* Surface clip serial number to store
* in the surface when this clip is set
*/
unsigned int serial;
/*
* A clip region that can be placed in the surface
*/
cairo_region_t *region;
/*
* If the surface supports path clipping, we store the list of
* clipping paths that has been set here as a linked list.
*/
cairo_clip_path_t *path;
};
cairo_private void
_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target);
_cairo_clip_init (cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_init_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
cairo_private_no_warn cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
cairo_private cairo_status_t
_cairo_clip_init_deep_copy (cairo_clip_t *clip,
cairo_clip_t *other,
cairo_surface_t *target);
_cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_clip_t *other,
const cairo_matrix_t *matrix);
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
#define _cairo_clip_fini(clip) _cairo_clip_reset (clip)
cairo_private cairo_status_t
_cairo_clip_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rectangle);
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
cairo_path_fixed_t *path,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_surface_t *target);
cairo_antialias_t antialias);
cairo_private cairo_status_t
_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
cairo_rectangle_int_t *rectangle);
_cairo_clip_apply_clip (cairo_clip_t *clip,
const cairo_clip_t *other);
cairo_private const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst);
cairo_private cairo_status_t
_cairo_clip_intersect_to_region (cairo_clip_t *clip,
cairo_region_t *region);
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
cairo_operator_t op,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents);
cairo_private cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
cairo_region_t **region);
cairo_private cairo_int_status_t
_cairo_clip_get_boxes (cairo_clip_t *clip,
cairo_box_t **boxes,
int *count);
cairo_private void
_cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx,
cairo_fixed_t ty);
_cairo_clip_drop_cache (cairo_clip_t *clip);
cairo_private cairo_rectangle_list_t*
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);

File diff suppressed because it is too large Load Diff

View File

@ -56,7 +56,7 @@ NAME (TYPE *base, unsigned int nmemb) \
int swapped; \
do { \
gap = _cairo_combsort_newgap (gap); \
swapped = 0; \
swapped = gap > 1; \
for (i = 0; i < nmemb-gap ; i++) { \
j = i + gap; \
if (CMP (base[i], base[j]) > 0 ) { \
@ -67,5 +67,5 @@ NAME (TYPE *base, unsigned int nmemb) \
swapped = 1; \
} \
} \
} while (gap > 1 || swapped); \
} while (swapped); \
}

View File

@ -45,6 +45,7 @@
extern "C" {
#include "cairoint.h"
#include "cairo-surface-clipper-private.h"
}
struct _cairo_d2d_surface {
@ -91,6 +92,8 @@ struct _cairo_d2d_surface {
bool isDrawing;
/** Indicates if text rendering is initialized */
bool textRenderingInit;
cairo_surface_clipper_t clipper;
};
typedef struct _cairo_d2d_surface cairo_d2d_surface_t;
@ -217,5 +220,8 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
unsigned int *runs_remaining,
bool *pushed_clip,
bool unique = false);
void
_cairo_d2d_begin_draw_state(cairo_d2d_surface_t *d2dsurf);
#endif /* CAIRO_HAS_D2D_SURFACE */
#endif /* CAIRO_D2D_PRIVATE_H */

View File

@ -42,6 +42,7 @@
extern "C" {
#include "cairo-win32.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-surface-clipper-private.h"
}
@ -159,7 +160,7 @@ _cairo_d2d_flush(void *surface);
* \param fill_rule The fill rule to uses on the path
* \param tolerance The tolerance applied to the filling
* \param antialias The anti-alias mode to use
* \param extents The extents of the surface to which to apply this operation
* \param clip The clip of this operation
* \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
* CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
*/
@ -171,17 +172,16 @@ _cairo_d2d_fill(void *surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
/**
* Paint this surface, applying the operation to the entire surface
* or to the passed in 'extents' of the surface.
*
* \param surface The surface to apply this operation to, must be
* a D2D surface
* \param op Operator to use when painting
* \param source The pattern to fill this surface with, source of the op
* \param Extents of the surface to apply this operation to
* \param clip The clip of this operation
* \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
* CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
*/
@ -189,7 +189,7 @@ static cairo_int_status_t
_cairo_d2d_paint(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
/**
* Paint something on the surface applying a certain mask to that
@ -200,7 +200,7 @@ _cairo_d2d_paint(void *surface,
* \param op Operator to use
* \param source Source for this operation
* \param mask Pattern to mask source with
* \param extents Extents of the surface to apply this operation to
* \param clip The clip of this operation
* \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
* CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
*/
@ -209,7 +209,7 @@ _cairo_d2d_mask(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
/**
* Show a glyph run on the target D2D surface.
@ -223,7 +223,7 @@ _cairo_d2d_mask(void *surface,
* \param scaled_font Scaled font to draw
* \param remaining_glyphs Pointer to store amount of glyphs still
* requiring drawing.
* \param extents Extents this operation applies to.
* \param clip The clip of this operation
* \return CAIRO_ERROR_SURFACE_TYPE_MISMATCH, CAIRO_ERROR_FONT_TYPE_MISMATCH,
* CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
*/
@ -234,8 +234,8 @@ _cairo_d2d_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
/**
* Get the extents of this surface.
@ -244,20 +244,17 @@ _cairo_d2d_show_glyphs (void *surface,
* \param extents Pointer to where to store the extents
* \param CAIRO_ERROR_SURFACE_TYPE_MISTMATCH or CAIRO_STATUS_SUCCESS
*/
static cairo_int_status_t
static cairo_bool_t
_cairo_d2d_getextents(void *surface,
cairo_rectangle_int_t *extents);
/**
* See cairo backend documentation.
*/
static cairo_int_status_t
_cairo_d2d_intersect_clip_path(void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
static cairo_status_t
_cairo_d2d_surface_clipper_intersect_clip_path(cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
/**
* Stroke a path on this D2D surface.
@ -275,7 +272,7 @@ _cairo_d2d_intersect_clip_path(void *dst,
* to logical space.
* \param tolerance Tolerance to stroke with
* \param antialias Antialias mode to use
* \param extents Extents of the surface to apply this operation to
* \param clip The clip of this operation
* \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
* CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
*/
@ -289,7 +286,7 @@ _cairo_d2d_stroke(void *surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
static const cairo_surface_backend_t cairo_d2d_surface_backend = {
CAIRO_SURFACE_TYPE_D2D,
@ -307,9 +304,7 @@ static const cairo_surface_backend_t cairo_d2d_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_d2d_intersect_clip_path, /* intersect_clip_path */
_cairo_d2d_getextents, /* getextents */
_cairo_d2d_getextents, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
_cairo_d2d_flush, /* flush */
@ -322,7 +317,6 @@ static const cairo_surface_backend_t cairo_d2d_surface_backend = {
_cairo_d2d_fill, /* fill */
_cairo_d2d_show_glyphs, /* show_glyphs */
NULL, /* snapshot */
NULL,
NULL
};
@ -502,6 +496,15 @@ static void _begin_draw_state(cairo_d2d_surface_t* surface)
}
}
/* External helper called from dwrite code.
* Will hopefully go away when/if that code
* moves into here */
void
_cairo_d2d_begin_draw_state(cairo_d2d_surface_t *d2dsurf)
{
_begin_draw_state(d2dsurf);
}
/**
* Get a D2D matrix from a cairo matrix. Note that D2D uses row vectors where cairo
* uses column vectors. Hence the transposition.
@ -1285,6 +1288,7 @@ _cairo_d2d_create_similar(void *surface,
memset(newSurf, 0, sizeof(cairo_d2d_surface_t));
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
_cairo_surface_clipper_init(&newSurf->clipper, _cairo_d2d_surface_clipper_intersect_clip_path);
D2D1_SIZE_U sizePixels;
D2D1_SIZE_F size;
@ -1391,6 +1395,9 @@ static cairo_status_t
_cairo_d2d_finish(void *surface)
{
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
_cairo_surface_clipper_reset (&d2dsurf->clipper);
if (d2dsurf->rt) {
d2dsurf->rt->Release();
}
@ -1430,6 +1437,7 @@ _cairo_d2d_finish(void *surface)
if (d2dsurf->bufferTexture) {
d2dsurf->bufferTexture->Release();
}
return CAIRO_STATUS_SUCCESS;
}
@ -1588,14 +1596,14 @@ _cairo_d2d_release_dest_image(void *abstract_surface,
softTexture->Release();
}
cairo_int_status_t
_cairo_d2d_intersect_clip_path(void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
static cairo_status_t
_cairo_d2d_surface_clipper_intersect_clip_path(cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(dst);
cairo_d2d_surface_t *d2dsurf = cairo_container_of (clipper, cairo_d2d_surface_t, clipper);
_cairo_d2d_surface_pop_clip(d2dsurf);
if (!path) {
@ -1607,7 +1615,7 @@ _cairo_d2d_intersect_clip_path(void *dst,
delete d2dsurf->clipRect;
d2dsurf->clipRect = NULL;
}
return CAIRO_INT_STATUS_SUCCESS;
return CAIRO_STATUS_SUCCESS;
}
cairo_box_t box;
@ -1618,11 +1626,12 @@ _cairo_d2d_intersect_clip_path(void *dst,
*/
if (!d2dsurf->clipRect && !d2dsurf->clipMask) {
/** Nothing yet, just use this clip rect */
//XXX: unchecked allocation
d2dsurf->clipRect = new D2D1_RECT_F(D2D1::RectF(_cairo_fixed_to_float(box.p1.x),
_cairo_fixed_to_float(box.p1.y),
_cairo_fixed_to_float(box.p2.x),
_cairo_fixed_to_float(box.p2.y)));
return CAIRO_INT_STATUS_SUCCESS;
return CAIRO_STATUS_SUCCESS;
} else if (!d2dsurf->clipMask) {
/** We have a clip rect, intersect of two rects is simple */
d2dsurf->clipRect->top = max(_cairo_fixed_to_float(box.p1.y), d2dsurf->clipRect->top);
@ -1635,7 +1644,7 @@ _cairo_d2d_intersect_clip_path(void *dst,
if (d2dsurf->clipRect->left > d2dsurf->clipRect->right) {
d2dsurf->clipRect->left = d2dsurf->clipRect->right;
}
return CAIRO_INT_STATUS_SUCCESS;
return CAIRO_STATUS_SUCCESS;
} else {
/**
* We have a mask, see if this rect is completely contained by it, so we
@ -1653,11 +1662,12 @@ _cairo_d2d_intersect_clip_path(void *dst,
d2dsurf->clipMask->Release();
d2dsurf->clipMask = NULL;
newMask->Release();
//XXX: unchecked allocation
d2dsurf->clipRect = new D2D1_RECT_F(D2D1::RectF(_cairo_fixed_to_float(box.p1.x),
_cairo_fixed_to_float(box.p1.y),
_cairo_fixed_to_float(box.p2.x),
_cairo_fixed_to_float(box.p2.y)));
return CAIRO_INT_STATUS_SUCCESS;
return CAIRO_STATUS_SUCCESS;
}
newMask->Release();
@ -1697,7 +1707,7 @@ _cairo_d2d_intersect_clip_path(void *dst,
if (relation == D2D1_GEOMETRY_RELATION_CONTAINS) {
currentMask->Release();
newMask->Release();
return CAIRO_INT_STATUS_SUCCESS;
return CAIRO_STATUS_SUCCESS;
} else if (relation == D2D1_GEOMETRY_RELATION_IS_CONTAINED) {
currentMask->Release();
d2dsurf->clipMask = newMask;
@ -1723,7 +1733,7 @@ _cairo_d2d_intersect_clip_path(void *dst,
d2dsurf->clipRect = NULL;
}
return CAIRO_INT_STATUS_SUCCESS;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@ -1743,9 +1753,15 @@ static cairo_int_status_t
_cairo_d2d_paint(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
cairo_int_status_t status;
status = (cairo_int_status_t)_cairo_surface_clipper_set_clip (&d2dsurf->clipper, clip);
if (unlikely(status))
return status;
_begin_draw_state(d2dsurf);
op = _cairo_d2d_simplify_operator(op, source);
@ -1771,20 +1787,14 @@ _cairo_d2d_paint(void *surface,
if (!brush) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (op == CAIRO_OPERATOR_OVER && extents) {
d2dsurf->rt->FillRectangle(D2D1::RectF((FLOAT)extents->x,
(FLOAT)extents->y,
(FLOAT)extents->x + extents->width,
(FLOAT)extents->y + extents->height),
brush);
} else if (op == CAIRO_OPERATOR_OVER) {
if (op == CAIRO_OPERATOR_OVER) {
D2D1_SIZE_F size = d2dsurf->rt->GetSize();
d2dsurf->rt->FillRectangle(D2D1::RectF((FLOAT)0,
(FLOAT)0,
(FLOAT)size.width,
(FLOAT)size.height),
brush);
} else if (op == CAIRO_OPERATOR_SOURCE && !extents) {
} else if (op == CAIRO_OPERATOR_SOURCE) {
D2D1_SIZE_F size = d2dsurf->rt->GetSize();
d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
d2dsurf->rt->FillRectangle(D2D1::RectF((FLOAT)0,
@ -1810,13 +1820,28 @@ _cairo_d2d_mask(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
_begin_draw_state(d2dsurf);
cairo_rectangle_int_t extents;
unsigned int runs_remaining = 0;
bool pushed_clip;
cairo_int_status_t status;
status = (cairo_int_status_t)_cairo_surface_clipper_set_clip (&d2dsurf->clipper, clip);
if (unlikely (status))
return status;
_begin_draw_state(d2dsurf);
status = (cairo_int_status_t)_cairo_surface_mask_extents (&d2dsurf->base,
op, source,
mask,
clip, &extents);
if (unlikely (status))
return status;
ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source, 0, &runs_remaining, &pushed_clip);
if (!brush) {
@ -1831,12 +1856,12 @@ _cairo_d2d_mask(void *surface,
0,
(FLOAT)d2dsurf->rt->GetPixelSize().width,
(FLOAT)d2dsurf->rt->GetPixelSize().height);
if (extents) {
rect.left = (FLOAT)extents->x;
rect.right = (FLOAT)(extents->x + extents->width);
rect.top = (FLOAT)extents->y;
rect.bottom = (FLOAT)(extents->y + extents->height);
}
rect.left = (FLOAT)extents.x;
rect.right = (FLOAT)(extents.x + extents.width);
rect.top = (FLOAT)extents.y;
rect.bottom = (FLOAT)(extents.y + extents.height);
if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solidPattern =
@ -1889,10 +1914,11 @@ _cairo_d2d_stroke(void *surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_int_status_t status;
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
_begin_draw_state(d2dsurf);
op = _cairo_d2d_simplify_operator(op, source);
@ -1906,6 +1932,12 @@ _cairo_d2d_stroke(void *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
status = (cairo_int_status_t)_cairo_surface_clipper_set_clip (&d2dsurf->clipper, clip);
if (unlikely(status))
return status;
_begin_draw_state(d2dsurf);
if (antialias == CAIRO_ANTIALIAS_NONE) {
d2dsurf->rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
} else {
@ -2018,13 +2050,11 @@ _cairo_d2d_fill(void *surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
cairo_int_status_t status;
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
_begin_draw_state(d2dsurf);
op = _cairo_d2d_simplify_operator(op, source);
@ -2038,6 +2068,12 @@ _cairo_d2d_fill(void *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
status = (cairo_int_status_t)_cairo_surface_clipper_set_clip (&d2dsurf->clipper, clip);
if (unlikely (status))
return status;
_begin_draw_state(d2dsurf);
if (antialias == CAIRO_ANTIALIAS_NONE) {
d2dsurf->rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
} else {
@ -2118,6 +2154,7 @@ _cairo_d2d_fill(void *surface,
return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_d2d_show_glyphs (void *surface,
cairo_operator_t op,
@ -2125,8 +2162,8 @@ _cairo_d2d_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D) {
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -2139,30 +2176,27 @@ _cairo_d2d_show_glyphs (void *surface,
d2dsurf->textRenderingInit = true;
params->Release();
}
_begin_draw_state(d2dsurf);
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
status = (cairo_int_status_t)
cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, extents);
_cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
}
return status;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_d2d_getextents(void *surface,
cairo_rectangle_int_t *extents)
{
if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D) {
return (cairo_int_status_t)CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
}
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
extents->x = 0;
extents->y = 0;
D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
extents->width = size.width;
extents->height = size.height;
return CAIRO_INT_STATUS_SUCCESS;
return TRUE;
}
@ -2183,6 +2217,7 @@ cairo_d2d_surface_create_for_hwnd(HWND wnd)
memset(newSurf, 0, sizeof(cairo_d2d_surface_t));
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR);
_cairo_surface_clipper_init(&newSurf->clipper, _cairo_d2d_surface_clipper_intersect_clip_path);
RECT rc;
HRESULT hr;
@ -2318,6 +2353,9 @@ cairo_d2d_surface_create(cairo_format_t format,
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_ALPHA);
dxgiformat = DXGI_FORMAT_A8_UNORM;
}
_cairo_surface_clipper_init(&newSurf->clipper, _cairo_d2d_surface_clipper_intersect_clip_path);
newSurf->format = format;
D2D1_SIZE_U sizePixels;

View File

@ -37,6 +37,7 @@
#include "cairo-ddraw.h"
#include "cairoint.h"
#include "cairo-region-private.h"
#ifdef CAIRO_DDRAW_USE_GL
#include <EGL/egl.h>

View File

@ -241,28 +241,6 @@ _cairo_ddraw_check_ogl_error (const char *context)
#endif /* CAIRO_DDRAW_USE_GL */
static cairo_status_t
_cairo_ddraw_surface_set_image_clip (cairo_ddraw_surface_t *surface)
{
if (surface->image_clip_invalid) {
surface->image_clip_invalid = FALSE;
if (surface->has_clip_region) {
unsigned int serial =
_cairo_surface_allocate_clip_serial (surface->image);
surface->has_image_clip = TRUE;
return _cairo_surface_set_clip_region (surface->image,
&surface->clip_region,
serial);
} else {
surface->has_image_clip = FALSE;
return _cairo_surface_set_clip_region (surface->image,
NULL, 0);
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ddraw_surface_set_clip_list (cairo_ddraw_surface_t * surface)
{
@ -371,10 +349,7 @@ _cairo_ddraw_surface_lock (cairo_ddraw_surface_t *surface)
if (surface->image->status)
return surface->image->status;
surface->has_image_clip = FALSE;
surface->image_clip_invalid = surface->has_clip_region;
return _cairo_ddraw_surface_set_image_clip (surface);
return CAIRO_STATUS_SUCCESS;
}
if (surface->locked)
@ -408,10 +383,7 @@ _cairo_ddraw_surface_lock (cairo_ddraw_surface_t *surface)
if (surface->image->status)
return surface->image->status;
surface->has_image_clip = FALSE;
surface->image_clip_invalid = surface->has_clip_region;
return _cairo_ddraw_surface_set_image_clip (surface);
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
@ -464,6 +436,8 @@ _cairo_ddraw_surface_reset_clipper (cairo_ddraw_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
#ifdef CAIRO_DDRAW_USE_GL
#define CAIRO_DDRAW_API_ENTRY_STATUS \
do { \
@ -572,7 +546,7 @@ _cairo_ddraw_surface_flush (void *abstract_surface)
cairo_status_t
_cairo_ddraw_surface_reset (cairo_surface_t *surface)
{
return _cairo_surface_reset_clip (surface);
return _cairo_ddraw_surface_set_clip_region (surface, NULL);
}
static cairo_surface_t *
@ -2477,8 +2451,8 @@ _cairo_ddraw_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_ddraw_surface_t * dst = (cairo_ddraw_surface_t *) abstract_dst;
cairo_color_t * color;
@ -2502,10 +2476,17 @@ _cairo_ddraw_surface_show_glyphs (void *abstract_dst,
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (dst->base.clip &&
(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
dst->base.clip->surface != NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clip != NULL) {
cairo_region_t *clip_region;
cairo_status_t status;
status = _cairo_clip_get_region (clip, &clip_region);
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (status)
return status;
_cairo_ddraw_surface_set_clip_region (surface, clip_region);
}
color = &((cairo_solid_pattern_t *)pattern)->color;
@ -2711,7 +2692,8 @@ _cairo_ddraw_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_regiont_t *clip_region)
{
cairo_ddraw_surface_t * dst = (cairo_ddraw_surface_t *) abstract_dst;
cairo_ddraw_ogl_program_info_t * info = NULL;
@ -2741,6 +2723,10 @@ _cairo_ddraw_surface_composite (cairo_operator_t op,
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
status = _cairo_ddraw_surface_set_clip_region (dst, clip_region);
if (status)
return status;
/* bail out for source copies that aren't ddraw surfaces) */
if (src->type == CAIRO_PATTERN_TYPE_SURFACE &&
(((cairo_surface_pattern_t *) src)->surface->type
@ -3136,9 +3122,6 @@ _cairo_ddraw_surface_acquire_dest_image (void *abstract_surfa
return status;
END_TIMER(acquiredst);
if ((status = _cairo_ddraw_surface_set_image_clip (surface)))
return status;
*image_out = (cairo_image_surface_t *) surface->image;
*image_rect = surface->extents;
*image_extra = NULL;
@ -3167,7 +3150,6 @@ _cairo_ddraw_surface_set_clip_region (void *abstract_surface,
if (region) {
cairo_region_t *tmp_region;
surface->has_clip_region = TRUE;
surface->image_clip_invalid = TRUE;
surface->clip_list_invalid = TRUE;
tmp_region = &surface->clip_region;
@ -3180,7 +3162,6 @@ _cairo_ddraw_surface_set_clip_region (void *abstract_surface,
-surface->extents.y);
} else {
surface->has_clip_region = FALSE;
surface->image_clip_invalid = surface->has_image_clip;
}
return CAIRO_STATUS_SUCCESS;
@ -3284,8 +3265,6 @@ cairo_ddraw_surface_create (LPDIRECTDRAW lpdd,
surface->dirty = FALSE;
#endif
surface->has_clip_region = FALSE;
surface->has_image_clip = FALSE;
surface->image_clip_invalid = FALSE;
surface->clip_list_invalid = FALSE;
surface->installed_clipper = NULL;
@ -3361,8 +3340,6 @@ cairo_ddraw_surface_create_alias (cairo_surface_t *root_surface,
surface->dirty = FALSE;
#endif
surface->has_clip_region = FALSE;
surface->has_image_clip = FALSE;
surface->image_clip_invalid = FALSE;
surface->clip_list_invalid = FALSE;
surface->format = root->format;
@ -3566,6 +3543,10 @@ _cairo_ddraw_surface_fill_rectangles (void *abstract_surface,
sb = color->blue_short * (1.0f / 65535.0f);
sa = color->alpha_short * (1.0f / 65535.0f);
status = _cairo_ddraw_surface_set_clip_region (surface, NULL);
if (status)
return status;
/* convert to solid clears if we can (so we can use glClear) */
if (op == CAIRO_OPERATOR_SOURCE ||
op == CAIRO_OPERATOR_OVER && color->alpha_short >= 0xff00) {
@ -4110,8 +4091,6 @@ static const cairo_surface_backend_t _cairo_ddraw_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_ddraw_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_ddraw_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */

View File

@ -75,6 +75,12 @@ cairo_debug_reset_static_data (void)
_cairo_pattern_reset_static_data ();
_cairo_clip_reset_static_data ();
#if CAIRO_HAS_DRM_SURFACE
_cairo_drm_device_reset_static_data ();
#endif
CAIRO_MUTEX_FINALIZE ();
}
@ -159,3 +165,70 @@ _cairo_image_surface_write_to_ppm (cairo_image_surface_t *isurf, const char *fn)
fprintf (stderr, "Wrote %s\n", fn);
}
#endif
static cairo_status_t
_print_move_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f m",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_line_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f l",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
fprintf (closure,
" %f %f %f %f %f %f c",
_cairo_fixed_to_double (p1->x),
_cairo_fixed_to_double (p1->y),
_cairo_fixed_to_double (p2->x),
_cairo_fixed_to_double (p2->y),
_cairo_fixed_to_double (p3->x),
_cairo_fixed_to_double (p3->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_close (void *closure)
{
fprintf (closure, " h");
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_print_move_to,
_print_line_to,
_print_curve_to,
_print_close,
stream);
assert (status == CAIRO_STATUS_SUCCESS);
printf ("\n");
}

View File

@ -38,14 +38,16 @@
#include "cairoint.h"
#include "cairo-directfb.h"
#include "cairo-clip-private.h"
#include <pixman.h>
#include <directfb.h>
#include <direct/types.h>
#include <direct/debug.h>
#include <direct/memcpy.h>
#include <direct/util.h>
#include "cairo-clip-private.h"
/*
* Rectangle works fine.
* Bugs 361377, 359553, 359243 in Gnome BTS are caused
@ -68,6 +70,8 @@
*/
#define DFB_SHOW_GLYPHS 1
#define PIXMAN_invalid (pixman_format_code_t) 0
D_DEBUG_DOMAIN (CairoDFB_Acquire, "CairoDFB/Acquire", "Cairo DirectFB Acquire");
D_DEBUG_DOMAIN (CairoDFB_Clip, "CairoDFB/Clip", "Cairo DirectFB Clipping");
@ -78,17 +82,15 @@ D_DEBUG_DOMAIN (CairoDFB_Surface, "CairoDFB/Surface", "Cairo DirectFB Surface");
/*****************************************************************************/
typedef struct _cairo_directfb_surface {
cairo_surface_t base;
cairo_format_t format;
cairo_content_t content;
cairo_surface_t base;
IDirectFB *dfb;
IDirectFBSurface *dfbsurface;
IDirectFBSurface *tmpsurface;
pixman_format_code_t pixman_format;
cairo_bool_t supported_destination;
cairo_bool_t has_clip;
DFBRegion *clips;
int n_clips;
IDirectFB *dfb;
IDirectFBSurface *dfbsurface;
IDirectFBSurface *tmpsurface;
pixman_format_code_t tmpformat;
int width;
int height;
@ -119,13 +121,18 @@ static int _directfb_argb_font = 0;
/*****************************************************************************/
#define RUN_CLIPPED(surface, clip, func) {\
if ((surface)->has_clip) {\
int k;\
for (k = 0; k < (surface)->n_clips; k++) {\
#define RUN_CLIPPED(surface, clip_region, clip, func) {\
if ((clip_region) != NULL) {\
int n_clips = cairo_region_num_rectangles (clip_region), n; \
for (n = 0; n < n_clips; n++) {\
if (clip) {\
DFBRegion reg = (surface)->clips[k];\
DFBRegion *cli = (clip);\
DFBRegion reg, *cli = (clip); \
cairo_rectangle_int_t rect; \
cairo_region_get_rectangle (clip_region, n, &rect); \
reg.x1 = rect.x; \
reg.y1 = rect.y; \
reg.x2 = rect.x + rect.width - 1; \
reg.y2 = rect.y + rect.height - 1; \
if (reg.x2 < cli->x1 || reg.y2 < cli->y1 ||\
reg.x1 > cli->x2 || reg.y1 > cli->y2)\
continue;\
@ -139,8 +146,14 @@ static int _directfb_argb_font = 0;
reg.y2 = cli->y2;\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg);\
} else {\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface,\
&(surface)->clips[k]);\
DFBRegion reg; \
cairo_rectangle_int_t rect; \
cairo_region_get_rectangle (clip_region, n, &rect); \
reg.x1 = rect.x; \
reg.y1 = rect.y; \
reg.x2 = rect.x + rect.width - 1; \
reg.y2 = rect.y + rect.height - 1; \
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg); \
}\
func;\
}\
@ -150,19 +163,19 @@ static int _directfb_argb_font = 0;
}\
}
#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) {\
double _x = (x);\
double _y = (y);\
(ret_x) = (_x * (m).xx + (m).x0);\
(ret_y) = (_y * (m).yy + (m).y0);\
}
#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) do { \
double _x = (x); \
double _y = (y); \
(ret_x) = (_x * (m).xx + (m).x0); \
(ret_y) = (_y * (m).yy + (m).y0); \
} while (0)
#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) {\
double _x = (x);\
double _y = (y);\
(ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0);\
(ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0);\
}
#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) do { \
double _x = (x); \
double _y = (y); \
(ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0); \
(ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0); \
} while (0)
/* XXX: A1 has a different bits ordering in cairo.
* Probably we should drop it.
@ -200,23 +213,69 @@ _cairo_to_directfb_format (cairo_format_t format)
return -1;
}
static inline cairo_format_t
_directfb_to_cairo_format (DFBSurfacePixelFormat format)
static inline pixman_format_code_t
_directfb_to_pixman_format (DFBSurfacePixelFormat format)
{
switch (format) {
case DSPF_RGB32:
return CAIRO_FORMAT_RGB24;
case DSPF_ARGB:
return CAIRO_FORMAT_ARGB32;
case DSPF_A8:
return CAIRO_FORMAT_A8;
case DSPF_A1:
return CAIRO_FORMAT_A1;
default:
break;
case DSPF_UNKNOWN: return PIXMAN_invalid;
case DSPF_ARGB1555: return PIXMAN_a1r5g5b5;
case DSPF_RGB16: return PIXMAN_r5g6b5;
case DSPF_RGB24: return PIXMAN_r8g8b8;
case DSPF_RGB32: return PIXMAN_x8r8g8b8;
case DSPF_ARGB: return PIXMAN_a8r8g8b8;
case DSPF_A8: return PIXMAN_a8;
case DSPF_YUY2: return PIXMAN_yuy2;
case DSPF_RGB332: return PIXMAN_r3g3b2;
case DSPF_UYVY: return PIXMAN_invalid;
case DSPF_I420: return PIXMAN_invalid;
case DSPF_YV12: return PIXMAN_yv12;
case DSPF_LUT8: return PIXMAN_invalid;
case DSPF_ALUT44: return PIXMAN_invalid;
case DSPF_AiRGB: return PIXMAN_invalid;
case DSPF_A1: return PIXMAN_a1; /* bit reversed, oops */
case DSPF_NV12: return PIXMAN_invalid;
case DSPF_NV16: return PIXMAN_invalid;
case DSPF_ARGB2554: return PIXMAN_invalid;
case DSPF_ARGB4444: return PIXMAN_a4r4g4b4;
case DSPF_NV21: return PIXMAN_invalid;
case DSPF_AYUV: return PIXMAN_invalid;
case DSPF_A4: return PIXMAN_a4;
case DSPF_ARGB1666: return PIXMAN_invalid;
case DSPF_ARGB6666: return PIXMAN_invalid;
case DSPF_RGB18: return PIXMAN_invalid;
case DSPF_LUT2: return PIXMAN_invalid;
case DSPF_RGB444: return PIXMAN_x4r4g4b4;
case DSPF_RGB555: return PIXMAN_x1r5g5b5;
#if DFB_NUM_PIXELFORMATS >= 29
case DSPF_BGR555: return PIXMAN_x1b5g5r5;
#endif
}
return PIXMAN_invalid;
}
return -1;
static inline DFBSurfacePixelFormat
_directfb_from_pixman_format (pixman_format_code_t format)
{
switch ((int) format) {
case PIXMAN_a1r5g5b5: return DSPF_ARGB1555;
case PIXMAN_r5g6b5: return DSPF_RGB16;
case PIXMAN_r8g8b8: return DSPF_RGB24;
case PIXMAN_x8r8g8b8: return DSPF_RGB32;
case PIXMAN_a8r8g8b8: return DSPF_ARGB;
case PIXMAN_a8: return DSPF_A8;
case PIXMAN_yuy2: return DSPF_YUY2;
case PIXMAN_r3g3b2: return DSPF_RGB332;
case PIXMAN_yv12: return DSPF_YV12;
case PIXMAN_a1: return DSPF_A1; /* bit reversed, oops */
case PIXMAN_a4r4g4b4: return DSPF_ARGB4444;
case PIXMAN_a4: return DSPF_A4;
case PIXMAN_x4r4g4b4: return DSPF_RGB444;
case PIXMAN_x1r5g5b5: return DSPF_RGB555;
#if DFB_NUM_PIXELFORMATS >= 29
case PIXMAN_x1b5g5r5: return DSPF_BGR555;
#endif
default: return 0;
}
}
static cairo_bool_t
@ -287,6 +346,21 @@ _directfb_get_operator (cairo_operator_t operator,
dstblend = DSBF_ONE;
break;
#endif
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
default:
return FALSE;
}
@ -335,17 +409,14 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
IDirectFBSurface *buffer = NULL;
DFBRectangle source_rect;
cairo_surface_t *image;
cairo_format_t cairo_format;
pixman_image_t *pixman_image;
pixman_format_code_t pixman_format;
cairo_status_t status;
void *data;
int pitch;
if (surface->format == (cairo_format_t) -1 ||
(lock_flags & DSLF_WRITE && surface->has_clip))
{
DFBSurfaceCapabilities caps;
if (intrest_rec) {
if (surface->pixman_format == PIXMAN_invalid) {
if (intrest_rec != NULL) {
source_rect.x = intrest_rec->x;
source_rect.y = intrest_rec->y;
source_rect.w = intrest_rec->width;
@ -357,30 +428,38 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
&source_rect.w, &source_rect.h);
}
if (surface->tmpsurface) {
if (surface->tmpsurface != NULL) {
int w, h;
surface->tmpsurface->GetSize (surface->tmpsurface, &w, &h);
if (w < source_rect.w || h < source_rect.h) {
surface->tmpsurface->Release (surface->tmpsurface);
surface->tmpsurface = NULL;
surface->tmpformat = PIXMAN_invalid;
}
}
cairo_format = _cairo_format_from_content (surface->content);
if (!surface->tmpsurface) {
if (surface->tmpsurface == NULL) {
DFBSurfacePixelFormat format;
D_DEBUG_AT (CairoDFB_Acquire, "Allocating buffer for surface %p.\n", surface);
format = _cairo_to_directfb_format (_cairo_format_from_content (surface->base.content));
status =
_directfb_buffer_surface_create (surface->dfb,
_cairo_to_directfb_format (cairo_format),
_directfb_buffer_surface_create (surface->dfb, format,
source_rect.w, source_rect.h,
&surface->tmpsurface);
if (status)
if (unlikely (status))
goto ERROR;
surface->tmpformat = _directfb_to_pixman_format (format);
}
buffer = surface->tmpsurface;
pixman_format = surface->tmpformat;
/* surface->dfbsurface->GetCapabilities (surface->dfbsurface, &caps);
DFBSurfaceCapabilities caps;
if (caps & DSCAPS_FLIPPING) {
DFBRegion region = { .x1 = source_rect.x, .y1 = source_rect.y,
.x2 = source_rect.x + source_rect.w - 1,
@ -391,7 +470,7 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
} else {
/*might be a subsurface get the offset*/
surface->dfbsurface->GetVisibleRectangle (surface->dfbsurface, &source_rect);
cairo_format = surface->format;
pixman_format = surface->pixman_format;
buffer = surface->dfbsurface;
}
@ -401,9 +480,16 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
goto ERROR;
}
image = cairo_image_surface_create_for_data (data, cairo_format,
source_rect.w, source_rect.h,
pitch);
pixman_image = pixman_image_create_bits (pixman_format,
source_rect.w, source_rect.h,
data, pitch);
if (pixman_image == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto ERROR;
}
image = _cairo_image_surface_create_for_pixman_image (pixman_image,
pixman_format);
status = image->status;
if (status)
goto ERROR;
@ -436,37 +522,27 @@ ERROR:
}
static cairo_surface_t *
_cairo_directfb_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height)
_cairo_directfb_surface_create_internal (IDirectFB *dfb,
DFBSurfacePixelFormat format,
cairo_content_t content,
int width,
int height)
{
cairo_directfb_surface_t *source = abstract_src;
cairo_directfb_surface_t *surface;
cairo_format_t format;
cairo_status_t status;
D_DEBUG_AT (CairoDFB_Surface,
"%s( src=%p, content=0x%x, width=%d, height=%d).\n",
__FUNCTION__, source, content, width, height);
width = (width <= 0) ? 1 : width;
height = (height<= 0) ? 1 : height;
format = _cairo_format_from_content (content);
surface = calloc (1, sizeof (cairo_directfb_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
surface->dfb = source->dfb;
surface->dfb = dfb;
if (width < 8 || height < 8) {
IDirectFBSurface *tmp;
DFBRectangle rect = { .x=0, .y=0, .w=width, .h=height };
/* Some cards (e.g. Matrox) don't support surfaces smaller than 8x8 */
status = _directfb_buffer_surface_create (surface->dfb,
_cairo_to_directfb_format (format),
status = _directfb_buffer_surface_create (dfb, format,
MAX (width, 8), MAX (height, 8),
&tmp);
if (status) {
@ -477,11 +553,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
tmp->GetSubSurface (tmp, &rect, &surface->dfbsurface);
tmp->Release (tmp);
} else {
status =
_directfb_buffer_surface_create (surface->dfb,
_cairo_to_directfb_format (format),
width, height,
&surface->dfbsurface);
status = _directfb_buffer_surface_create (dfb, format,
width, height,
&surface->dfbsurface);
if (status) {
free (surface);
return _cairo_surface_create_in_error (status);
@ -491,8 +565,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
content);
surface->format = format;
surface->content = content;
surface->pixman_format = _directfb_to_pixman_format (format);
surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
surface->width = width;
surface->height = height;
surface->local = TRUE;
@ -501,6 +576,27 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
return &surface->base;
}
static cairo_surface_t *
_cairo_directfb_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height)
{
cairo_directfb_surface_t *other = abstract_src;
DFBSurfacePixelFormat format;
D_DEBUG_AT (CairoDFB_Surface,
"%s( src=%p, content=0x%x, width=%d, height=%d).\n",
__FUNCTION__, other, content, width, height);
width = (width <= 0) ? 1 : width;
height = (height<= 0) ? 1 : height;
format = _cairo_to_directfb_format (_cairo_format_from_content (content));
return _cairo_directfb_surface_create_internal (other->dfb, format,
content, width, height);
}
static cairo_status_t
_cairo_directfb_surface_finish (void *data)
{
@ -508,12 +604,6 @@ _cairo_directfb_surface_finish (void *data)
D_DEBUG_AT (CairoDFB_Surface, "%s( surface=%p ).\n", __FUNCTION__, surface);
if (surface->clips) {
free (surface->clips);
surface->clips = NULL;
surface->n_clips = 0;
}
if (surface->tmpsurface) {
surface->tmpsurface->Release (surface->tmpsurface);
surface->tmpsurface = NULL;
@ -549,11 +639,10 @@ _cairo_directfb_surface_release_source_image (void *abstract_su
cairo_image_surface_t *image,
void *image_extra)
{
cairo_directfb_surface_t *surface = abstract_surface;
IDirectFBSurface *buffer = image_extra;
D_DEBUG_AT (CairoDFB_Acquire,
"%s( surface=%p ).\n", __FUNCTION__, surface);
"%s( release=%p ).\n", __FUNCTION__, abstract_surface);
buffer->Unlock (buffer);
@ -605,10 +694,10 @@ _cairo_directfb_surface_release_dest_image (void *abstract_surf
.y2 = interest_rect->y + interest_rect->height - 1
};
surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, DSBLIT_NOFX);
RUN_CLIPPED (surface, &region,
surface->dfbsurface->Blit (surface->dfbsurface,
buffer, NULL,
image_rect->x, image_rect->y));
surface->dfbsurface->SetClip (surface->dfbsurface, &region);
surface->dfbsurface->Blit (surface->dfbsurface,
buffer, NULL,
image_rect->x, image_rect->y);
}
cairo_surface_destroy (&image->base);
@ -617,7 +706,6 @@ _cairo_directfb_surface_release_dest_image (void *abstract_surf
static cairo_status_t
_cairo_directfb_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
cairo_content_t content,
int src_x,
int src_y,
int width,
@ -640,56 +728,51 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
} else if (_cairo_surface_is_image (src)) {
cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
unsigned char *dst, *src = image_src->data;
int pitch;
int i, j;
DFBSurfacePixelFormat format;
DFBResult ret;
pixman_image_t *pixman_image;
void *data;
int pitch;
format = _directfb_from_pixman_format (image_src->pixman_format);
if (format == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
clone = (cairo_directfb_surface_t *)
_cairo_directfb_surface_create_similar (surface,
_cairo_content_from_format (image_src->format),
width, height);
if (clone == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clone->base.status)
_cairo_directfb_surface_create_internal (surface->dfb, format,
image_src->base.content,
width, height);
if (unlikely (clone->base.status))
return clone->base.status;
ret = clone->dfbsurface->Lock (clone->dfbsurface,
DSLF_WRITE, (void *)&dst, &pitch);
DSLF_WRITE, (void *)&data, &pitch);
if (ret) {
DirectFBError ("IDirectFBSurface::Lock()", ret);
cairo_surface_destroy (&clone->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
src += image_src->stride * src_y;
if (image_src->format == CAIRO_FORMAT_A1) {
/* A1 -> A8 */
dst -= src_x;
for (i = 0; i < height; i++) {
for (j = src_x; j < src_x + width; j++)
dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00;
dst += pitch;
src += image_src->stride;
}
} else {
int len;
if (image_src->format == CAIRO_FORMAT_A8) {
src += src_x;
len = width;
} else {
src += src_x * 4;
len = width * 4;
}
for (i = 0; i < height; i++) {
direct_memcpy (dst, src, len);
dst += pitch;
src += image_src->stride;
}
pixman_image = pixman_image_create_bits (clone->pixman_format,
width, height,
data, pitch);
if (unlikely (pixman_image == NULL)) {
DirectFBError ("IDirectFBSurface::Lock()", ret);
cairo_surface_destroy (&clone->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pixman_image_composite (PIXMAN_OP_SRC,
image_src->pixman_image,
NULL,
pixman_image,
src_x, src_y,
0, 0,
0, 0,
width, height);
pixman_image_unref (pixman_image);
clone->dfbsurface->Unlock (clone->dfbsurface);
*clone_offset_x = src_x;
@ -730,8 +813,6 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
if (mask_pattern) {
cairo_solid_pattern_t *pattern;
return CAIRO_INT_STATUS_UNSUPPORTED;
if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
const cairo_pattern_t *tmp;
@ -764,7 +845,6 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
}
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
*src_x, *src_y, width, height,
CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
(cairo_surface_t **) &src,
@ -779,7 +859,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (src->content == CAIRO_CONTENT_COLOR) {
if ((src->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_SRCALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVSRCALPHA)
@ -791,7 +871,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
dblend = DSBF_ZERO;
}
if (dst->content == CAIRO_CONTENT_COLOR) {
if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
@ -898,7 +978,8 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
int mask_x, int mask_y,
int dst_x, int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src;
@ -915,6 +996,9 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
__FUNCTION__, op, src_pattern, mask_pattern, dst,
src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _directfb_prepare_composite (dst, src_pattern, mask_pattern, op,
&src_x, &src_y, &mask_x, &mask_y,
width, height, &src, &src_attr);
@ -941,7 +1025,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
src_x += src_attr.x_offset;
src_y += src_attr.y_offset;
switch (accel) {
switch ((int) accel) {
case DFXL_BLIT:
{
DFBRectangle sr;
@ -959,11 +1043,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
if (src_attr.extend == CAIRO_EXTEND_NONE) {
D_DEBUG_AT (CairoDFB_Render, "Running Blit().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->Blit (dst->dfbsurface,
src->dfbsurface,
&sr,
dst_x, dst_y));
&sr, dst_x, dst_y));
} else if (src_attr.extend == CAIRO_EXTEND_REPEAT) {
DFBRegion clip;
@ -974,11 +1057,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TileBlit().\n");
RUN_CLIPPED (dst, &clip,
RUN_CLIPPED (dst, clip_region, &clip,
dst->dfbsurface->TileBlit (dst->dfbsurface,
src->dfbsurface,
&sr,
dst_x, dst_y));
&sr, dst_x, dst_y));
}
break;
}
@ -1005,9 +1087,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running StretchBlit().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->StretchBlit (dst->dfbsurface,
src->dfbsurface, &sr, &dr));
src->dfbsurface,
&sr, &dr));
break;
}
@ -1029,29 +1112,25 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
src->dfbsurface->GetSize (src->dfbsurface, &w, &h);
TRANSFORM_POINT3X (src_attr.matrix,
x1, y1, v[0].x, v[0].y);
TRANSFORM_POINT3X (src_attr.matrix, x1, y1, v[0].x, v[0].y);
v[0].z = 0;
v[0].w = 1;
v[0].s = x1 / w;
v[0].t = y1 / h;
TRANSFORM_POINT3X (src_attr.matrix,
x2, y1, v[1].x, v[1].y);
TRANSFORM_POINT3X (src_attr.matrix, x2, y1, v[1].x, v[1].y);
v[1].z = 0;
v[1].w = 1;
v[1].s = x2 / w;
v[1].t = y1 / h;
TRANSFORM_POINT3X (src_attr.matrix,
x2, y2, v[2].x, v[2].y);
TRANSFORM_POINT3X (src_attr.matrix, x2, y2, v[2].x, v[2].y);
v[2].z = 0;
v[2].w = 1;
v[2].s = x2 / w;
v[2].t = y2 / h;
TRANSFORM_POINT3X (src_attr.matrix,
x1, y2, v[3].x, v[3].y);
TRANSFORM_POINT3X (src_attr.matrix, x1, y2, v[3].x, v[3].y);
v[3].z = 0;
v[3].w = 1;
v[3].s = x1 / w;
@ -1064,9 +1143,11 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
RUN_CLIPPED (dst, &clip,
RUN_CLIPPED (dst, clip_region, &clip,
dst->dfbsurface->TextureTriangles (dst->dfbsurface,
src->dfbsurface, v, NULL, 4, DTTF_FAN));
src->dfbsurface,
v, NULL,
4, DTTF_FAN));
break;
}
@ -1077,7 +1158,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
_directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
return status;
return CAIRO_STATUS_SUCCESS;
}
#endif /* DFB_COMPOSITE */
@ -1100,8 +1181,8 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
"%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n",
__FUNCTION__, dst, op, color, rects, n_rects);
if (! _cairo_operator_bounded_by_source (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend))
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1117,7 +1198,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
else if (dblend == DSBF_INVSRCALPHA)
dblend = DSBF_ZERO;
}
if (dst->content == CAIRO_CONTENT_COLOR) {
if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
@ -1149,7 +1230,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
r[i].h = rects[i].height;
}
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, NULL, NULL,
dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects));
return CAIRO_STATUS_SUCCESS;
@ -1167,7 +1248,8 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
int num_traps,
cairo_region_t *clip_region)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src;
@ -1182,6 +1264,9 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
__FUNCTION__, op, pattern, dst, antialias,
src_x, src_y, dst_x, dst_y, width, height, traps, num_traps);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (antialias != CAIRO_ANTIALIAS_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1276,7 +1361,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->TextureTriangles (dst->dfbsurface,
src->dfbsurface,
vertex, NULL, n,
@ -1291,64 +1376,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
}
#endif /* DFB_COMPOSITE_TRAPEZOIDS */
static cairo_int_status_t
_cairo_directfb_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_directfb_surface_t *surface = abstract_surface;
D_DEBUG_AT (CairoDFB_Clip,
"%s( surface=%p, region=%p ).\n",
__FUNCTION__, surface, region);
if (region) {
int n_rects;
cairo_status_t status;
int i;
surface->has_clip = TRUE;
n_rects = cairo_region_num_rectangles (region);
if (n_rects == 0)
return CAIRO_STATUS_SUCCESS;
if (surface->n_clips != n_rects) {
if (surface->clips)
free (surface->clips);
surface->clips = _cairo_malloc_ab (n_rects, sizeof (DFBRegion));
if (!surface->clips) {
surface->n_clips = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
surface->n_clips = n_rects;
}
for (i = 0; i < n_rects; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
surface->clips[i].x1 = rect.x;
surface->clips[i].y1 = rect.y;
surface->clips[i].x2 = rect.x + rect.width - 1;
surface->clips[i].y2 = rect.y + rect.height - 1;
}
} else {
surface->has_clip = FALSE;
if (surface->clips) {
free (surface->clips);
surface->clips = NULL;
surface->n_clips = 0;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_directfb_abstract_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1368,7 +1396,7 @@ _cairo_directfb_abstract_surface_get_extents (void *abstract_su
rectangle->width = surface->width;
rectangle->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
#if DFB_SHOW_GLYPHS
@ -1407,6 +1435,7 @@ _directfb_destroy_font_cache (cairo_directfb_font_cache_t *cache)
free (cache);
}
/* XXX hook into rtree font cache from drm */
static cairo_status_t
_directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
cairo_scaled_font_t *scaled_font,
@ -1458,6 +1487,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_ARGB32:
break;
case CAIRO_FORMAT_RGB24:
default:
D_DEBUG_AT (CairoDFB_Font,
" -> Unsupported font format %d!\n", img->format);
@ -1690,8 +1720,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_font_cache_t *cache;
@ -1703,28 +1733,29 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
DFBPoint points[num_glyphs];
int num;
const cairo_color_t *color;
cairo_region_t *clip_region = NULL;
D_DEBUG_AT (CairoDFB_Font,
"%s( dst=%p, op=%d, pattern=%p, glyphs=%p, num_glyphs=%d, scaled_font=%p ).\n",
__FUNCTION__, dst, op, pattern, glyphs, num_glyphs, scaled_font);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Fallback if we need to emulate clip regions */
if (dst->base.clip &&
(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
dst->base.clip->surface != NULL))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (status)
return status;
}
/* XXX Unbounded operators are not handled correctly */
if (! _cairo_operator_bounded_by_mask (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _cairo_operator_bounded_by_source (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend) ||
sblend == DSBF_DESTALPHA || sblend == DSBF_INVDESTALPHA)
@ -1773,7 +1804,7 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
D_DEBUG_AT (CairoDFB_Font, "Running BatchBlit().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->BatchBlit (dst->dfbsurface,
cache->dfbsurface, rects, points, num));
@ -1820,8 +1851,6 @@ _cairo_directfb_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_directfb_surface_set_clip_region,/* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_directfb_abstract_surface_get_extents,/* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -1845,7 +1874,6 @@ _cairo_directfb_surface_backend = {
#endif
NULL, /* snapshot */
_cairo_directfb_surface_is_similar,
NULL /* reset */
};
@ -1918,8 +1946,8 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
dfbsurface->GetSize (dfbsurface, &surface->width, &surface->height);
surface->dfb = dfb;
surface->dfbsurface = dfbsurface;
surface->format = _directfb_to_cairo_format (format);
surface->content = _directfb_format_to_content (format);
surface->pixman_format = _directfb_to_pixman_format (format);
surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
dfbsurface->GetCapabilities (dfbsurface, &caps);
if (caps & DSCAPS_PREMULTIPLIED)
@ -1927,7 +1955,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
surface->content);
_directfb_format_to_content (format));
return &surface->base;
}

View File

@ -0,0 +1,135 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*/
#ifndef CAIRO_DRM_H
#define CAIRO_DRM_H
#include "cairo.h"
#if CAIRO_HAS_DRM_SURFACE
CAIRO_BEGIN_DECLS
typedef struct _cairo_drm_device cairo_drm_device_t;
struct udev_device;
cairo_public cairo_drm_device_t *
cairo_drm_device_get (struct udev_device *device);
cairo_public cairo_drm_device_t *
cairo_drm_device_get_for_fd (int fd);
cairo_public cairo_drm_device_t *
cairo_drm_device_default (void);
cairo_public cairo_drm_device_t *
cairo_drm_device_reference (cairo_drm_device_t *device);
cairo_public cairo_status_t
cairo_drm_device_status (cairo_drm_device_t *device);
cairo_public int
cairo_drm_device_get_fd (cairo_drm_device_t *device);
cairo_public void
cairo_drm_device_throttle (cairo_drm_device_t *device);
cairo_public void
cairo_drm_device_destroy (cairo_drm_device_t *device);
cairo_public cairo_surface_t *
cairo_drm_surface_create (cairo_drm_device_t *device,
cairo_content_t content,
int width, int height);
cairo_public cairo_surface_t *
cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
unsigned int name,
cairo_format_t format,
int width, int height, int stride);
cairo_public cairo_surface_t *
cairo_drm_surface_create_from_cacheable_image (cairo_drm_device_t *device,
cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_drm_surface_enable_scan_out (cairo_surface_t *surface);
cairo_public cairo_drm_device_t *
cairo_drm_surface_get_device (cairo_surface_t *abstract_surface);
cairo_public unsigned int
cairo_drm_surface_get_handle (cairo_surface_t *surface);
cairo_public unsigned int
cairo_drm_surface_get_name (cairo_surface_t *surface);
cairo_public cairo_format_t
cairo_drm_surface_get_format (cairo_surface_t *surface);
cairo_public int
cairo_drm_surface_get_width (cairo_surface_t *surface);
cairo_public int
cairo_drm_surface_get_height (cairo_surface_t *surface);
cairo_public int
cairo_drm_surface_get_stride (cairo_surface_t *surface);
/* XXX map/unmap, general surface layer? */
/* Rough outline, culled from a conversation on IRC:
* map() returns an image-surface representation of the drm-surface,
* which you unmap() when you are finished, i.e. map() pulls the buffer back
* from the GPU, maps it into the CPU domain and gives you direct access to
* the pixels. With the unmap(), the buffer is ready to be used again by the
* GPU and *until* the unmap(), all operations will be done in software.
*
* (Technically calling cairo_surface_flush() on the underlying drm-surface
* will also disassociate the mapping.)
*/
cairo_public cairo_surface_t *
cairo_drm_surface_map (cairo_surface_t *surface);
cairo_public void
cairo_drm_surface_unmap (cairo_surface_t *drm_surface,
cairo_surface_t *image_surface);
CAIRO_END_DECLS
#else /* CAIRO_HAS_DRM_SURFACE */
# error Cairo was not compiled with support for the DRM backend
#endif /* CAIRO_HAS_DRM_SURFACE */
#endif /* CAIRO_DRM_H */

View File

@ -181,6 +181,7 @@ _cairo_dwrite_scaled_show_glyphs(void *scaled_font,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region,
int *remaining_glyphs);
cairo_int_status_t
@ -425,6 +426,7 @@ _cairo_dwrite_scaled_show_glyphs(void *scaled_font,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region,
int *remaining_glyphs)
{
cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
@ -437,7 +439,9 @@ _cairo_dwrite_scaled_show_glyphs(void *scaled_font,
surface->format == CAIRO_FORMAT_RGB24 &&
op == CAIRO_OPERATOR_OVER) {
status = (cairo_int_status_t)cairo_dwrite_show_glyphs_on_surface (surface, op, pattern,
//XXX: we need to set the clip region here
status = (cairo_int_status_t)_cairo_dwrite_show_glyphs_on_surface (surface, op, pattern,
glyphs, num_glyphs,
(cairo_scaled_font_t*)scaled_font, NULL);
@ -547,7 +551,8 @@ _cairo_dwrite_scaled_show_glyphs(void *scaled_font,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height);
width, height,
clip_region);
_cairo_pattern_fini (&mask.base);
@ -1022,29 +1027,20 @@ _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
}
/* Surface helper function */
cairo_public cairo_int_status_t
cairo_dwrite_show_glyphs_on_surface(void *surface,
cairo_int_status_t
_cairo_dwrite_show_glyphs_on_surface(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
// TODO: Check font & surface for types.
cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->font_face);
cairo_win32_surface_t *dst = reinterpret_cast<cairo_win32_surface_t*>(surface);
cairo_int_status_t status;
/* If we have a fallback mask clip set on the dst, we have
* to go through the fallback path, but only if we're not
* doing this for printing */
if (dst->base.clip &&
(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
dst->base.clip->surface != NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
/* We can only handle dwrite fonts */
if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1059,6 +1055,21 @@ cairo_dwrite_show_glyphs_on_surface(void *surface,
(dst->format != CAIRO_FORMAT_RGB24))
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 (clip != NULL) {
if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
cairo_region_t *clip_region;
cairo_int_status_t status;
status = _cairo_clip_get_region (clip, &clip_region);
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (status)
return status;
_cairo_win32_surface_set_clip_region (dst, clip_region);
}
}
/* 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
@ -1212,21 +1223,25 @@ cairo_dwrite_show_glyphs_on_surface(void *surface,
#if CAIRO_HAS_D2D_SURFACE
/* Surface helper function */
//XXX: this function should probably be in cairo-d2d-surface.cpp
cairo_int_status_t
cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
_cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_int_status_t status;
// TODO: Check font & surface for types.
cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->font_face);
cairo_d2d_surface_t *dst = reinterpret_cast<cairo_d2d_surface_t*>(surface);
/* We can only handle dwrite fonts */
//XXX: this is checked by at least one caller
if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1236,6 +1251,11 @@ cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = (cairo_int_status_t)_cairo_surface_clipper_set_clip (&dst->clipper, clip);
if (unlikely (status))
return status;
_cairo_d2d_begin_draw_state(dst);
D2D1_TEXT_ANTIALIAS_MODE cleartype = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;

View File

@ -98,10 +98,10 @@ private:
};
cairo_int_status_t
cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
_cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);

View File

@ -0,0 +1,181 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include <i915_drm.h> /* XXX dummy surface for glewInit() */
#include <sys/ioctl.h>
typedef struct _cairo_eagle_context {
cairo_gl_context_t base;
EGLDisplay display;
EGLContext context;
} cairo_eagle_context_t;
typedef struct _cairo_eagle_surface {
cairo_gl_surface_t base;
EGLSurface eagle;
} cairo_eagle_surface_t;
static void
_eagle_make_current (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
{
cairo_eagle_context_t *ctx = abstract_ctx;
cairo_eagle_surface_t *surface = (cairo_eagle_surface_t *) abstract_surface;
eagleMakeCurrent (ctx->display, surface->eagle, surface->eagle, ctx->context);
}
static void
_eagle_swap_buffers (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
{
cairo_eagle_context_t *ctx = abstract_ctx;
cairo_eagle_surface_t *surface = (cairo_eagle_surface_t *) abstract_surface;
eagleSwapBuffers (ctx->display, surface->eagle);
}
static void
_eagle_destroy (void *abstract_ctx)
{
}
static cairo_bool_t
_eagle_init (EGLDisplay display, EGLContext context)
{
const EGLint config_attribs[] = {
EGL_CONFIG_CAVEAT, EGL_NONE,
EGL_NONE
};
const EGLint surface_attribs[] = {
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
EGL_NONE
};
EGLConfig config;
EGLSurface dummy;
struct drm_i915_gem_create create;
struct drm_gem_flink flink;
int fd;
GLenum err;
if (! eagleChooseConfig (display, config_attribs, &config, 1, NULL)) {
fprintf (stderr, "Unable to choose config\n");
return FALSE;
}
/* XXX */
fd = eagleGetDisplayFD (display);
create.size = 4096;
if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
fprintf (stderr, "gem create failed: %m\n");
return FALSE;
}
flink.handle = create.handle;
if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
fprintf (stderr, "gem flink failed: %m\n");
return FALSE;
}
dummy = eagleCreateSurfaceForName (display, config, flink.name,
1, 1, 4, surface_attribs);
if (dummy == NULL) {
fprintf (stderr, "Failed to create dummy surface\n");
return FALSE;
}
eagleMakeCurrent (display, dummy, dummy, context);
}
cairo_gl_context_t *
cairo_eagle_context_create (EGLDisplay display, EGLContext context)
{
cairo_eagle_context_t *ctx;
cairo_status_t status;
if (! _eagle_init (display, context)) {
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
ctx = calloc (1, sizeof (cairo_eagle_context_t));
if (ctx == NULL)
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
ctx->display = display;
ctx->context = context;
ctx->base.make_current = _eagle_make_current;
ctx->base.swap_buffers = _eagle_swap_buffers;
ctx->base.destroy = _eagle_destroy;
status = _cairo_gl_context_init (&ctx->base);
if (status) {
free (ctx);
return _cairo_gl_context_create_in_error (status);
}
return &ctx->base;
}
cairo_surface_t *
cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
EGLSurface eagle,
int width,
int height)
{
cairo_eagle_surface_t *surface;
if (ctx->status)
return _cairo_surface_create_in_error (ctx->status);
surface = calloc (1, sizeof (cairo_eagle_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_gl_surface_init (ctx, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA, width, height);
surface->eagle = eagle;
return &surface->base.base;
}

View File

@ -0,0 +1,16 @@
/* Generated by configure. Do not edit. */
#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H
#define HAVE_WINDOWS_H 1
#define CAIRO_HAS_WIN32_SURFACE 1
#define CAIRO_HAS_WIN32_FONT 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
#define CAIRO_HAS_PS_SURFACE 1
#define CAIRO_HAS_PDF_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_USER_FONT 1
#endif

View File

@ -224,6 +224,15 @@ _cairo_fixed_16_16_from_double (double d)
#endif
}
static inline int
_cairo_fixed_16_16_floor (cairo_fixed_t f)
{
if (f >= 0)
return f >> 16;
else
return -((-f - 1) >> 16) - 1;
}
#if CAIRO_FIXED_BITS == 32
static inline cairo_fixed_t
@ -233,15 +242,61 @@ _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes a * b / c */
/* computes round (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
}
return _cairo_int64_to_int32(quo);
/* computes floor (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
}
static inline cairo_fixed_t
_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t x)
{
cairo_fixed_t y, dx;
if (x == p1->x)
return p1->y;
if (x == p2->x)
return p2->y;
y = p1->y;
dx = p2->x - p1->x;
if (dx != 0)
y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
return y;
}
static inline cairo_fixed_t
_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
if (y == p1->y)
return p1->x;
if (y == p2->y)
return p2->x;
x = p1->x;
dy = p2->y - p1->y;
if (dy != 0)
x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
return x;
}
#else

View File

@ -67,4 +67,9 @@ typedef int32_t cairo_fixed_t;
/* An unsigned type of the same size as #cairo_fixed_t */
typedef uint32_t cairo_fixed_unsigned_t;
typedef struct _cairo_point {
cairo_fixed_t x;
cairo_fixed_t y;
} cairo_point_t;
#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */

View File

@ -294,6 +294,8 @@ twin_font_face_create_properties (cairo_font_face_t *twin_face,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
props->stretch = TWIN_STRETCH_NORMAL;
props->slant = CAIRO_FONT_SLANT_NORMAL;
props->weight = TWIN_WEIGHT_NORMAL;
props->monospace = FALSE;
props->smallcaps = FALSE;

View File

@ -25,19 +25,40 @@
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
/* Opaque implementation types. */
typedef struct _cairo_freelist cairo_freelist_t;
typedef struct _cairo_freelist_node cairo_freelist_node_t;
/* for stand-alone compilation*/
#ifndef VG
#define VG(x)
#endif
#ifndef NULL
#define NULL (void *) 0
#endif
typedef struct _cairo_freelist_node cairo_freelist_node_t;
struct _cairo_freelist_node {
cairo_freelist_node_t *next;
};
struct _cairo_freelist {
typedef struct _cairo_freelist {
cairo_freelist_node_t *first_free_node;
unsigned nodesize;
} cairo_freelist_t;
typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
struct _cairo_freelist_pool {
cairo_freelist_pool_t *next;
unsigned size, rem;
uint8_t *data;
};
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_pool_t *pools;
unsigned nodesize;
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
} cairo_freepool_t;
/* Initialise a freelist that will be responsible for allocating
* nodes of size nodesize. */
@ -68,4 +89,62 @@ _cairo_freelist_calloc (cairo_freelist_t *freelist);
cairo_private void
_cairo_freelist_free (cairo_freelist_t *freelist, void *node);
cairo_private void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize);
cairo_private void
_cairo_freepool_fini (cairo_freepool_t *freepool);
cairo_private void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
static inline void *
_cairo_freepool_alloc_from_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
uint8_t *ptr;
pool = freepool->pools;
if (unlikely (freepool->nodesize > pool->rem))
return _cairo_freepool_alloc_from_new_pool (freepool);
ptr = pool->data;
pool->data += freepool->nodesize;
pool->rem -= freepool->nodesize;
VG (VALGRIND_MAKE_MEM_UNDEFINED (ptr, freepool->nodesize));
return ptr;
}
static inline void *
_cairo_freepool_alloc (cairo_freepool_t *freepool)
{
cairo_freelist_node_t *node;
node = freepool->first_free_node;
if (unlikely (node == NULL))
return _cairo_freepool_alloc_from_pool (freepool);
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
return node;
}
cairo_private cairo_status_t
_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
int count,
void **array);
static inline void
_cairo_freepool_free (cairo_freepool_t *freepool, void *ptr)
{
cairo_freelist_node_t *node = ptr;
node->next = freepool->first_free_node;
freepool->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freepool->nodesize));
}
#endif /* CAIRO_FREELIST_H */

View File

@ -82,3 +82,92 @@ _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freelist->nodesize));
}
}
void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
{
freepool->first_free_node = NULL;
freepool->pools = &freepool->embedded_pool;
freepool->nodesize = nodesize;
freepool->embedded_pool.next = NULL;
freepool->embedded_pool.size = sizeof (freepool->embedded_data);
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data,
sizeof (freepool->embedded_data)));
}
void
_cairo_freepool_fini (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool = freepool->pools;
while (pool != &freepool->embedded_pool) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
}
void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
int poolsize;
if (freepool->pools != &freepool->embedded_pool)
poolsize = 2 * freepool->pools->size;
else
poolsize = (128 * freepool->nodesize + 8191) & -8192;
pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
if (unlikely (pool == NULL))
return pool;
pool->next = freepool->pools;
freepool->pools = pool;
pool->size = poolsize;
pool->rem = poolsize - freepool->nodesize;
pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize));
VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize));
return pool + 1;
}
cairo_status_t
_cairo_freepool_alloc_array (cairo_freepool_t *freepool,
int count,
void **array)
{
int i;
for (i = 0; i < count; i++) {
cairo_freelist_node_t *node;
node = freepool->first_free_node;
if (likely (node != NULL)) {
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;
VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
} else {
node = _cairo_freepool_alloc_from_pool (freepool);
if (unlikely (node == NULL))
goto CLEANUP;
}
array[i] = node;
}
return CAIRO_STATUS_SUCCESS;
CLEANUP:
while (i--)
_cairo_freepool_free (freepool, array[i]);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}

View File

@ -808,7 +808,6 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
int width, height, stride;
unsigned char *data;
int format = CAIRO_FORMAT_A8;
cairo_bool_t subpixel = FALSE;
width = bitmap->width;
height = bitmap->rows;
@ -976,7 +975,6 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
data = data_rgba;
stride = stride_rgba;
format = CAIRO_FORMAT_ARGB32;
subpixel = TRUE;
break;
}
}
@ -999,9 +997,6 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
return (*surface)->base.status;
}
if (subpixel)
pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE);
_cairo_image_surface_assume_ownership_of_data ((*surface));
_cairo_debug_check_image_surface_is_defined (&(*surface)->base);
@ -1152,7 +1147,7 @@ _render_glyph_bitmap (FT_Face face,
cairo_image_surface_t **surface)
{
FT_GlyphSlot glyphslot = face->glyph;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_status_t status;
FT_Error error;
/* According to the FreeType docs, glyphslot->format could be
@ -1168,7 +1163,9 @@ _render_glyph_bitmap (FT_Face face,
if (error == FT_Err_Out_Of_Memory)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface);
status = _get_bitmap_surface (&glyphslot->bitmap,
FALSE, font_options,
surface);
if (unlikely (status))
return status;
@ -1183,7 +1180,7 @@ _render_glyph_bitmap (FT_Face face,
-glyphslot->bitmap_left,
+glyphslot->bitmap_top);
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@ -1281,11 +1278,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
_cairo_pattern_init_for_surface (&pattern, &(*surface)->base);
cairo_pattern_set_matrix (&pattern.base, &transformed_to_original);
status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
&pattern.base, NULL, image,
0, 0, 0, 0, 0, 0,
width,
height);
status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER,
&pattern.base, NULL);
_cairo_pattern_fini (&pattern.base);
@ -1307,7 +1301,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
cairo_surface_set_device_offset (&(*surface)->base,
_cairo_lround (origin_x),
_cairo_lround (origin_y));
return status;
return CAIRO_STATUS_SUCCESS;
}
static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
@ -1396,8 +1390,8 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
}
#ifdef FC_HINT_STYLE
if (FcPatternGetInteger (pattern,
#ifdef FC_HINT_STYLE
if (FcPatternGetInteger (pattern,
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
hintstyle = FC_HINT_FULL;
@ -1406,7 +1400,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
switch (hintstyle) {
case FC_HINT_NONE:
ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
break;
case FC_HINT_SLIGHT:
ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT;
@ -1450,14 +1444,14 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
if (vertical_layout)
ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT;
#ifndef FC_EMBOLDEN
#define FC_EMBOLDEN "embolden"
#endif
if (FcPatternGetBool (pattern,
FC_EMBOLDEN, 0, &embolden) != FcResultMatch)
embolden = FcFalse;
if (embolden)
ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN;
@ -1474,7 +1468,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
/* clear load target mode */
load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags)));
if (load_flags & FT_LOAD_NO_HINTING)
other->base.hint_style = CAIRO_HINT_STYLE_NONE;
@ -1485,7 +1479,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
}
if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL &&
(options->base.antialias == CAIRO_ANTIALIAS_DEFAULT ||
(options->base.antialias == CAIRO_ANTIALIAS_DEFAULT ||
options->base.antialias == CAIRO_ANTIALIAS_GRAY)) {
options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
options->base.subpixel_order = other->base.subpixel_order;
@ -1940,12 +1934,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
y1 = (-metrics->horiBearingY) & -64;
y2 = (-metrics->horiBearingY + metrics->height + 63) & -64;
advance = ((metrics->horiAdvance + 32) & -64);
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
@ -1956,12 +1950,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
x2 = (metrics->vertBearingX + metrics->width + 63) & -64;
y1 = (metrics->vertBearingY) & -64;
y2 = (metrics->vertBearingY + metrics->height + 63) & -64;
advance = ((metrics->vertAdvance + 32) & -64);
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
@ -1975,7 +1969,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
if (!vertical_layout) {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
else
@ -1984,7 +1978,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
} else {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor;
fs_metrics.x_advance = 0 * x_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
@ -2142,11 +2136,11 @@ _cairo_ft_index_to_ucs4(void *abstract_font,
*ucs4 = (uint32_t) -1;
charcode = FT_Get_First_Char(face, &gindex);
while (gindex != 0) {
charcode = FT_Get_Next_Char (face, charcode, &gindex);
if (gindex == index) {
*ucs4 = charcode;
break;
}
charcode = FT_Get_Next_Char (face, charcode, &gindex);
}
_cairo_ft_unscaled_font_unlock_face (unscaled);
@ -2160,7 +2154,7 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
_cairo_ft_scaled_glyph_init,
NULL, /* text_to_glyphs */
_cairo_ft_ucs4_to_index,
NULL, /* show_glyphs */
NULL, /* show_glyphs */
_cairo_ft_load_truetype_table,
_cairo_ft_index_to_ucs4
};
@ -2241,12 +2235,6 @@ _cairo_ft_font_face_destroy (void *abstract_face)
{
cairo_ft_font_face_t *font_face = abstract_face;
cairo_ft_font_face_t *tmp_face = NULL;
cairo_ft_font_face_t *last_face = NULL;
if (font_face == NULL)
return;
/* When destroying a face created by cairo_ft_font_face_create_for_ft_face,
* we have a special "zombie" state for the face when the unscaled font
* is still alive but there are no other references to a font face with
@ -2277,6 +2265,9 @@ _cairo_ft_font_face_destroy (void *abstract_face)
}
if (font_face->unscaled) {
cairo_ft_font_face_t *tmp_face = NULL;
cairo_ft_font_face_t *last_face = NULL;
/* Remove face from linked list */
for (tmp_face = font_face->unscaled->faces;
tmp_face;
@ -2341,12 +2332,15 @@ _cairo_ft_font_face_get_implementation (void *abstract_face,
return cairo_font_face_reference (resolved);
cairo_font_face_destroy (resolved);
font_face->resolved_font_face = NULL;
}
resolved = _cairo_ft_resolve_pattern (font_face->pattern,
font_matrix,
ctm,
options);
if (unlikely (resolved->status))
return resolved;
font_face->resolved_font_face = cairo_font_face_reference (resolved);
font_face->resolved_config = FcConfigGetCurrent ();
@ -2917,10 +2911,10 @@ cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font)
{
cairo_ft_scaled_font_t *ft_scaled_font;
if (!_cairo_scaled_font_is_ft (scaled_font))
return FALSE;
ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT)
return TRUE;

View File

@ -0,0 +1,797 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-rtree-private.h"
#define GLYPH_CACHE_WIDTH 1024
#define GLYPH_CACHE_HEIGHT 1024
#define GLYPH_CACHE_MIN_SIZE 4
#define GLYPH_CACHE_MAX_SIZE 128
typedef struct _cairo_gl_glyph_private {
cairo_rtree_node_t node;
cairo_gl_glyph_cache_t *cache;
struct { float x, y; } p1, p2;
} cairo_gl_glyph_private_t;
static cairo_status_t
_cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_gl_glyph_private_t *glyph_private;
cairo_rtree_node_t *node = NULL;
cairo_image_surface_t *clone = NULL;
cairo_status_t status;
int width, height;
GLenum internal_format, format, type;
cairo_bool_t has_alpha;
if (! _cairo_gl_get_image_format_and_type (glyph_surface->pixman_format,
&internal_format,
&format,
&type,
&has_alpha))
{
cairo_bool_t is_supported;
clone = _cairo_image_surface_coerce (glyph_surface,
_cairo_format_from_content (glyph_surface->base.content));
if (unlikely (clone->base.status))
return clone->base.status;
is_supported =
_cairo_gl_get_image_format_and_type (clone->pixman_format,
&internal_format,
&format,
&type,
&has_alpha);
assert (is_supported);
glyph_surface = clone;
}
width = glyph_surface->width;
if (width < GLYPH_CACHE_MIN_SIZE)
width = GLYPH_CACHE_MIN_SIZE;
height = glyph_surface->height;
if (height < GLYPH_CACHE_MIN_SIZE)
height = GLYPH_CACHE_MIN_SIZE;
/* search for an available slot */
status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
/* search for an unlocked slot */
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_rtree_evict_random (&cache->rtree,
width, height, &node);
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_rtree_node_insert (&cache->rtree,
node, width, height, &node);
}
}
if (status)
return status;
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_ROW_LENGTH,
glyph_surface->stride /
(PIXMAN_FORMAT_BPP (glyph_surface->pixman_format) / 8));
glTexSubImage2D (GL_TEXTURE_2D, 0,
node->x, node->y,
glyph_surface->width, glyph_surface->height,
format, type,
glyph_surface->data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
scaled_glyph->surface_private = node;
node->owner = &scaled_glyph->surface_private;
glyph_private = (cairo_gl_glyph_private_t *) node;
glyph_private->cache = cache;
/* compute tex coords */
glyph_private->p1.x = node->x / (double) cache->width;
glyph_private->p1.y = node->y / (double) cache->height;
glyph_private->p2.x =
(node->x + glyph_surface->width) / (double) cache->width;
glyph_private->p2.y =
(node->y + glyph_surface->height) / (double) cache->height;
cairo_surface_destroy (&clone->base);
return CAIRO_STATUS_SUCCESS;
}
static cairo_gl_glyph_private_t *
_cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph)
{
return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private);
}
static cairo_gl_glyph_cache_t *
cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
cairo_format_t format)
{
cairo_gl_glyph_cache_t *cache;
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
cache = &ctx->glyph_cache[0];
format = CAIRO_FORMAT_ARGB32;
break;
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
cache = &ctx->glyph_cache[1];
format = CAIRO_FORMAT_A8;
break;
}
if (unlikely (cache->tex == 0)) {
GLenum internal_format;
cache->width = GLYPH_CACHE_WIDTH;
cache->height = GLYPH_CACHE_HEIGHT;
switch (format) {
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_RGB24:
ASSERT_NOT_REACHED;
case CAIRO_FORMAT_ARGB32:
internal_format = GL_RGBA;
break;
case CAIRO_FORMAT_A8:
internal_format = GL_ALPHA;
break;
}
glGenTextures (1, &cache->tex);
glBindTexture (GL_TEXTURE_2D, cache->tex);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D (GL_TEXTURE_2D, 0, internal_format,
GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, 0,
internal_format, GL_FLOAT, NULL);
}
return cache;
}
static void
_cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
{
_cairo_rtree_unpin (&cache->rtree);
}
static cairo_bool_t
_cairo_gl_surface_owns_font (cairo_gl_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
cairo_gl_context_t *font_private;
font_private = scaled_font->surface_private;
if ((scaled_font->surface_backend != NULL &&
scaled_font->surface_backend != &_cairo_gl_surface_backend) ||
(font_private != NULL && font_private != surface->ctx))
{
return FALSE;
}
return TRUE;
}
void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font)
{
cairo_gl_glyph_private_t *glyph_private;
glyph_private = scaled_glyph->surface_private;
if (glyph_private != NULL) {
glyph_private->node.owner = NULL;
if (! glyph_private->node.pinned) {
/* XXX thread-safety? Probably ok due to the frozen scaled-font. */
_cairo_rtree_node_remove (&glyph_private->cache->rtree,
&glyph_private->node);
}
}
}
typedef struct _cairo_gl_glyphs_setup
{
unsigned int vbo_size; /* units of floats */
unsigned int vb_offset; /* units of floats */
unsigned int vertex_size; /* units of floats */
unsigned int num_prims;
float *vb;
cairo_gl_composite_setup_t *composite;
cairo_region_t *clip;
cairo_gl_surface_t *dst;
} cairo_gl_glyphs_setup_t;
static void
_cairo_gl_flush_glyphs (cairo_gl_context_t *ctx,
cairo_gl_glyphs_setup_t *setup)
{
int i;
if (setup->vb != NULL) {
glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
setup->vb = NULL;
if (setup->num_prims != 0) {
if (setup->clip) {
int num_rectangles = cairo_region_num_rectangles (setup->clip);
glEnable (GL_SCISSOR_TEST);
for (i = 0; i < num_rectangles; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (setup->clip, i, &rect);
glScissor (rect.x,
_cairo_gl_y_flip (setup->dst, rect.y),
rect.x + rect.width,
_cairo_gl_y_flip (setup->dst,
rect.y + rect.height));
glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
}
glDisable (GL_SCISSOR_TEST);
} else {
glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
}
setup->num_prims = 0;
}
}
}
static void
_cairo_gl_glyphs_emit_vertex (cairo_gl_glyphs_setup_t *setup,
int x, int y, float glyph_x, float glyph_y)
{
int i = 0;
float *vb = &setup->vb[setup->vb_offset];
cairo_surface_attributes_t *src_attributes;
src_attributes = &setup->composite->src.operand.texture.attributes;
vb[i++] = x;
vb[i++] = y;
vb[i++] = glyph_x;
vb[i++] = glyph_y;
if (setup->composite->src.type == OPERAND_TEXTURE) {
double s = x;
double t = y;
cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
vb[i++] = s;
vb[i++] = t;
}
setup->vb_offset += setup->vertex_size;
}
static void
_cairo_gl_emit_glyph_rectangle (cairo_gl_context_t *ctx,
cairo_gl_glyphs_setup_t *setup,
int x1, int y1,
int x2, int y2,
cairo_gl_glyph_private_t *glyph)
{
if (setup->vb != NULL &&
setup->vb_offset + 4 * setup->vertex_size > setup->vbo_size) {
_cairo_gl_flush_glyphs (ctx, setup);
}
if (setup->vb == NULL) {
glBufferDataARB (GL_ARRAY_BUFFER_ARB,
setup->vbo_size * sizeof (GLfloat),
NULL, GL_STREAM_DRAW_ARB);
setup->vb = glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
setup->vb_offset = 0;
}
_cairo_gl_glyphs_emit_vertex (setup, x1, y1, glyph->p1.x, glyph->p1.y);
_cairo_gl_glyphs_emit_vertex (setup, x2, y1, glyph->p2.x, glyph->p1.y);
_cairo_gl_glyphs_emit_vertex (setup, x2, y2, glyph->p2.x, glyph->p2.y);
_cairo_gl_glyphs_emit_vertex (setup, x1, y2, glyph->p1.x, glyph->p2.y);
setup->num_prims++;
}
static cairo_status_t
_render_glyphs (cairo_gl_surface_t *dst,
int dst_x, int dst_y,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_rectangle_int_t *glyph_extents,
cairo_scaled_font_t *scaled_font,
cairo_bool_t *has_component_alpha,
cairo_region_t *clip_region,
int *remaining_glyphs)
{
cairo_format_t last_format = (cairo_format_t) -1;
cairo_gl_glyph_cache_t *cache = NULL;
cairo_gl_context_t *ctx;
cairo_gl_glyphs_setup_t setup;
cairo_gl_composite_setup_t composite_setup;
cairo_status_t status;
int i = 0;
GLuint vbo = 0;
*has_component_alpha = FALSE;
status = _cairo_gl_operand_init (&composite_setup.src, source, dst,
glyph_extents->x, glyph_extents->y,
dst_x, dst_y,
glyph_extents->width,
glyph_extents->height);
if (unlikely (status))
return status;
ctx = _cairo_gl_context_acquire (dst->ctx);
/* Set up the IN operator for source IN mask.
*
* IN (normal, any op): dst.argb = src.argb * mask.aaaa
* IN (component, ADD): dst.argb = src.argb * mask.argb
*
* The mask channel selection for component alpha ADD will be updated in
* the loop over glyphs below.
*/
glActiveTexture (GL_TEXTURE1);
glEnable (GL_TEXTURE_2D);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
_cairo_gl_set_destination (dst);
/* If we're doing some CA glyphs, we're only doing it for ADD,
* which doesn't require the source alpha value in blending.
*/
_cairo_gl_set_operator (dst, op, FALSE);
_cairo_gl_set_src_operand (ctx, &composite_setup);
_cairo_scaled_font_freeze_cache (scaled_font);
if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP_FONT;
}
if (scaled_font->surface_private == NULL) {
/* XXX couple into list to remove on context destruction */
scaled_font->surface_private = ctx;
scaled_font->surface_backend = &_cairo_gl_surface_backend;
}
/* Create our VBO so that we can accumulate a bunch of glyph primitives
* into one giant DrawArrays.
*/
memset(&setup, 0, sizeof(setup));
setup.composite = &composite_setup;
setup.clip = clip_region;
setup.dst = dst;
setup.vertex_size = 4;
if (composite_setup.src.type == OPERAND_TEXTURE)
setup.vertex_size += 2;
setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
if (setup.vbo_size > 4096)
setup.vbo_size = 4096;
glGenBuffersARB (1, &vbo);
glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo);
glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
(void *)(uintptr_t)(0));
glEnableClientState (GL_VERTEX_ARRAY);
if (composite_setup.src.type == OPERAND_TEXTURE) {
/* Note that we're packing texcoord 0 after texcoord 1, for
* convenience.
*/
glClientActiveTexture (GL_TEXTURE0);
glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
(void *)(uintptr_t)(4 * sizeof (GLfloat)));
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
}
glClientActiveTexture (GL_TEXTURE1);
glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
(void *)(uintptr_t)(2 * sizeof (GLfloat)));
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
double x_offset, y_offset;
double x1, x2, y1, y2;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (unlikely (status))
goto FINISH;
if (scaled_glyph->surface->width == 0 ||
scaled_glyph->surface->height == 0)
{
continue;
}
if (scaled_glyph->surface->width > GLYPH_CACHE_MAX_SIZE ||
scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE)
{
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto FINISH;
}
if (scaled_glyph->surface->format != last_format) {
/* Switching textures, so flush any queued prims. */
_cairo_gl_flush_glyphs (ctx, &setup);
glActiveTexture (GL_TEXTURE1);
cache = cairo_gl_context_get_glyph_cache (ctx,
scaled_glyph->surface->format);
glBindTexture (GL_TEXTURE_2D, cache->tex);
last_format = scaled_glyph->surface->format;
/* If we're doing component alpha in this function, it should
* only be in the case of CAIRO_OPERATOR_ADD. In that case, we just
* need to make sure we send the rgb bits down to the destination.
*/
if (last_format == CAIRO_FORMAT_ARGB32) {
assert (op == CAIRO_OPERATOR_ADD);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
*has_component_alpha = TRUE;
} else {
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
}
/* XXX component alpha */
}
if (scaled_glyph->surface_private == NULL) {
status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
/* Cache is full, so flush existing prims and try again. */
_cairo_gl_flush_glyphs (ctx, &setup);
_cairo_gl_glyph_cache_unlock (cache);
status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
}
if (unlikely (_cairo_status_is_error (status)))
goto FINISH;
}
x_offset = scaled_glyph->surface->base.device_transform.x0;
y_offset = scaled_glyph->surface->base.device_transform.y0;
x1 = _cairo_lround (glyphs[i].x - x_offset);
y1 = _cairo_lround (glyphs[i].y - y_offset);
x2 = x1 + scaled_glyph->surface->width;
y2 = y1 + scaled_glyph->surface->height;
_cairo_gl_emit_glyph_rectangle (ctx, &setup,
x1, y1, x2, y2,
_cairo_gl_glyph_cache_lock (cache, scaled_glyph));
}
status = CAIRO_STATUS_SUCCESS;
FINISH:
_cairo_gl_flush_glyphs (ctx, &setup);
CLEANUP_FONT:
_cairo_scaled_font_thaw_cache (scaled_font);
glDisable (GL_BLEND);
glDisable (GL_SCISSOR_TEST);
glDisableClientState (GL_VERTEX_ARRAY);
glClientActiveTexture (GL_TEXTURE0);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glActiveTexture (GL_TEXTURE0);
glDisable (GL_TEXTURE_2D);
glClientActiveTexture (GL_TEXTURE1);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glActiveTexture (GL_TEXTURE1);
glDisable (GL_TEXTURE_2D);
if (vbo != 0) {
glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
glDeleteBuffersARB (1, &vbo);
}
_cairo_gl_context_release (ctx);
_cairo_gl_operand_destroy (&composite_setup.src);
*remaining_glyphs = num_glyphs - i;
return status;
}
static cairo_int_status_t
_cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_rectangle_int_t *glyph_extents,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_surface_t *mask;
cairo_status_t status;
cairo_solid_pattern_t solid;
cairo_bool_t has_component_alpha;
int i;
/* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
mask = cairo_gl_surface_create (dst->ctx,
CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents->width,
glyph_extents->height);
if (unlikely (mask->status))
return mask->status;
for (i = 0; i < num_glyphs; i++) {
glyphs[i].x -= glyph_extents->x;
glyphs[i].y -= glyph_extents->y;
}
_cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR_ALPHA);
status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
CAIRO_OPERATOR_ADD, &solid.base,
glyphs, num_glyphs, glyph_extents,
scaled_font, &has_component_alpha,
NULL, remaining_glyphs);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
cairo_surface_pattern_t mask_pattern;
mask->is_clear = FALSE;
_cairo_pattern_init_for_surface (&mask_pattern, mask);
mask_pattern.base.has_component_alpha = has_component_alpha;
cairo_matrix_init_translate (&mask_pattern.base.matrix,
-glyph_extents->x, -glyph_extents->y);
status = _cairo_surface_mask (&dst->base, op,
source, &mask_pattern.base, clip);
_cairo_pattern_fini (&mask_pattern.base);
} else {
for (i = 0; i < num_glyphs; i++) {
glyphs[i].x += glyph_extents->x;
glyphs[i].y += glyph_extents->y;
}
*remaining_glyphs = num_glyphs;
}
cairo_surface_destroy (mask);
return status;
}
cairo_int_status_t
_cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_gl_surface_t *dst = abstract_dst;
cairo_rectangle_int_t surface_extents;
cairo_rectangle_int_t extents;
cairo_region_t *clip_region = NULL;
cairo_solid_pattern_t solid_pattern;
cairo_bool_t overlap, use_mask = FALSE;
cairo_bool_t has_component_alpha;
cairo_status_t status;
int i;
if (! GLEW_ARB_vertex_buffer_object)
return UNSUPPORTED ("requires ARB_vertex_buffer_object");
if (! _cairo_gl_operator_is_supported (op))
return UNSUPPORTED ("unsupported operator");
if (! _cairo_operator_bounded_by_mask (op))
use_mask |= TRUE;
/* If any of the glyphs are component alpha, we have to go through a mask,
* since only _cairo_gl_surface_composite() currently supports component
* alpha.
*/
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (!_cairo_status_is_error (status) &&
scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
{
use_mask = TRUE;
break;
}
}
/* For CLEAR, cairo's rendering equation (quoting Owen's description in:
* http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
* is:
* mask IN clip ? src OP dest : dest
* or more simply:
* mask IN CLIP ? 0 : dest
*
* where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
*
* The model we use in _cairo_gl_set_operator() is Render's:
* src IN mask IN clip OP dest
* which would boil down to:
* 0 (bounded by the extents of the drawing).
*
* However, we can do a Render operation using an opaque source
* and DEST_OUT to produce:
* 1 IN mask IN clip DEST_OUT dest
* which is
* mask IN clip ? 0 : dest
*/
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
source = &solid_pattern.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
/* For SOURCE, cairo's rendering equation is:
* (mask IN clip) ? src OP dest : dest
* or more simply:
* (mask IN clip) ? src : dest.
*
* If we just used the Render equation, we would get:
* (src IN mask IN clip) OP dest
* or:
* (src IN mask IN clip) bounded by extents of the drawing.
*
* The trick is that for GL blending, we only get our 4 source values
* into the blender, and since we need all 4 components of source, we
* can't also get the mask IN clip into the blender. But if we did
* two passes we could make it work:
* dest = (mask IN clip) DEST_OUT dest
* dest = src IN mask IN clip ADD dest
*
* But for now, composite via an intermediate mask.
*/
if (op == CAIRO_OPERATOR_SOURCE)
use_mask |= TRUE;
/* XXX we don't need ownership of the font as we use a global
* glyph cache -- but we do need scaled_glyph eviction notification. :-(
*/
if (! _cairo_gl_surface_owns_font (dst, scaled_font))
return UNSUPPORTED ("do not control font");
/* If the glyphs overlap, we need to build an intermediate mask rather
* then perform the compositing directly.
*/
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs, num_glyphs,
&extents,
&overlap);
if (unlikely (status))
return status;
use_mask |= overlap;
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
/* the empty clip should never be propagated this far */
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (unlikely (_cairo_status_is_error (status)))
return status;
use_mask |= status == CAIRO_INT_STATUS_UNSUPPORTED;
if (! _cairo_rectangle_intersect (&extents,
_cairo_clip_get_extents (clip)))
goto EMPTY;
}
surface_extents.x = surface_extents.y = 0;
surface_extents.width = dst->width;
surface_extents.height = dst->height;
if (! _cairo_rectangle_intersect (&extents, &surface_extents))
goto EMPTY;
if (use_mask) {
return _cairo_gl_surface_show_glyphs_via_mask (dst, op,
source,
glyphs, num_glyphs,
&extents,
scaled_font,
clip,
remaining_glyphs);
}
return _render_glyphs (dst, extents.x, extents.y,
op, source,
glyphs, num_glyphs, &extents,
scaled_font, &has_component_alpha,
clip_region, remaining_glyphs);
EMPTY:
*remaining_glyphs = 0;
if (! _cairo_operator_bounded_by_mask (op))
return _cairo_surface_paint (&dst->base, op, source, clip);
else
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache)
{
if (cache->tex == 0)
return;
glDeleteTextures (1, &cache->tex);
_cairo_rtree_fini (&cache->rtree);
}
void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
{
cache->tex = 0;
_cairo_rtree_init (&cache->rtree,
GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT,
GLYPH_CACHE_MIN_SIZE,
sizeof (cairo_gl_glyph_private_t),
NULL);
}

View File

@ -0,0 +1,222 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_GL_PRIVATE_H
#define CAIRO_GL_PRIVATE_H
#include "cairoint.h"
#include "cairo-rtree-private.h"
#include <GL/glew.h>
#include "cairo-gl.h"
#include <GL/gl.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/glext.h>
#define DEBUG_GL 0
#if DEBUG_GL && __GNUC__
#define UNSUPPORTED(reason) ({ \
fprintf (stderr, \
"cairo-gl: hit unsupported operation in %s(), line %d: %s\n", \
__FUNCTION__, __LINE__, reason); \
CAIRO_INT_STATUS_UNSUPPORTED; \
})
#else
#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
#endif
typedef struct _cairo_gl_surface {
cairo_surface_t base;
cairo_gl_context_t *ctx;
int width, height;
GLuint tex; /* GL texture object containing our data. */
GLuint fb; /* GL framebuffer object wrapping our data. */
} cairo_gl_surface_t;
typedef struct cairo_gl_glyph_cache {
cairo_rtree_t rtree;
GLuint tex;
unsigned int width, height;
} cairo_gl_glyph_cache_t;
struct _cairo_gl_context {
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_mutex_t mutex; /* needed? */
GLuint dummy_tex;
GLint fill_rectangles_shader;
GLint fill_rectangles_color_uniform;
GLint max_framebuffer_size;
GLint max_texture_size;
cairo_gl_surface_t *current_target;
cairo_gl_glyph_cache_t glyph_cache[2];
void (*make_current)(void *ctx, cairo_gl_surface_t *surface);
void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
void (*destroy) (void *ctx);
};
enum cairo_gl_composite_operand_type {
OPERAND_CONSTANT,
OPERAND_TEXTURE,
};
/* This union structure describes a potential source or mask operand to the
* compositing equation.
*/
typedef struct cairo_gl_composite_operand {
enum cairo_gl_composite_operand_type type;
union {
struct {
GLuint tex;
cairo_gl_surface_t *surface;
cairo_surface_attributes_t attributes;
} texture;
struct {
GLfloat color[4];
} constant;
} operand;
const cairo_pattern_t *pattern;
} cairo_gl_composite_operand_t;
typedef struct _cairo_gl_composite_setup {
cairo_gl_composite_operand_t src;
cairo_gl_composite_operand_t mask;
} cairo_gl_composite_setup_t;
cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
cairo_private cairo_gl_context_t *
_cairo_gl_context_create_in_error (cairo_status_t status);
cairo_private cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_surface_init (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface,
cairo_content_t content,
int width, int height);
cairo_private cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
int src_x, int src_y,
int width, int height,
int dst_x, int dst_y);
cairo_private cairo_int_status_t
_cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
cairo_private cairo_gl_context_t *
_cairo_gl_context_acquire (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_context_release (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_set_destination (cairo_gl_surface_t *surface);
cairo_private cairo_bool_t
_cairo_gl_operator_is_supported (cairo_operator_t op);
cairo_private void
_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
cairo_bool_t component_alpha);
cairo_private void
_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
cairo_gl_composite_setup_t *setup);
cairo_private void
_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand);
cairo_private cairo_bool_t
_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
GLenum *internal_format, GLenum *format,
GLenum *type, cairo_bool_t *has_alpha);
cairo_private void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
cairo_private void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
cairo_private cairo_int_status_t
_cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs);
cairo_private void
_cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache);
cairo_private cairo_status_t
_cairo_gl_load_glsl (GLint *shader,
const char *vs_source, const char *fs_source);
static inline int
_cairo_gl_y_flip (cairo_gl_surface_t *surface, int y)
{
if (surface->fb)
return y;
else
return (surface->height - 1) - y;
}
slim_hidden_proto (cairo_gl_surface_create);
#endif /* CAIRO_GL_PRIVATE_H */

View File

@ -0,0 +1,117 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Eric Anholt
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Eric Anholt.
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
static GLint
_cairo_gl_compile_glsl(GLenum type, GLint *shader_out, const char *source)
{
GLint ok;
GLint shader;
shader = glCreateShaderObjectARB (type);
glShaderSourceARB (shader, 1, (const GLchar **)&source, NULL);
glCompileShaderARB (shader);
glGetObjectParameterivARB (shader, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetObjectParameterivARB (shader, GL_OBJECT_INFO_LOG_LENGTH_ARB,
&size);
info = malloc (size);
if (info)
glGetInfoLogARB (shader, size, NULL, info);
fprintf (stderr, "Failed to compile %s: %s\n",
type == GL_FRAGMENT_SHADER ? "FS" : "VS",
info);
fprintf (stderr, "Shader source:\n%s", source);
fprintf (stderr, "GLSL compile failure\n");
glDeleteObjectARB (shader);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
*shader_out = shader;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_gl_load_glsl (GLint *shader_out,
const char *vs_source, const char *fs_source)
{
GLint ok;
GLint shader, vs, fs;
cairo_status_t status;
shader = glCreateProgramObjectARB ();
status = _cairo_gl_compile_glsl (GL_VERTEX_SHADER_ARB, &vs, vs_source);
if (_cairo_status_is_error (status))
goto fail;
status = _cairo_gl_compile_glsl (GL_FRAGMENT_SHADER_ARB, &fs, fs_source);
if (_cairo_status_is_error (status))
goto fail;
glAttachObjectARB (shader, vs);
glAttachObjectARB (shader, fs);
glLinkProgram (shader);
glGetObjectParameterivARB (shader, GL_OBJECT_LINK_STATUS_ARB, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetObjectParameterivARB (shader, GL_OBJECT_INFO_LOG_LENGTH_ARB,
&size);
info = malloc (size);
if (info)
glGetInfoLogARB (shader, size, NULL, info);
fprintf (stderr, "Failed to link: %s\n", info);
free (info);
status = CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
*shader_out = shader;
return CAIRO_STATUS_SUCCESS;
fail:
glDeleteObjectARB (shader);
return status;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,101 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Eric Anholt.
*/
#ifndef CAIRO_GL_H
#define CAIRO_GL_H
#include "cairo.h"
#if CAIRO_HAS_GL_SURFACE
CAIRO_BEGIN_DECLS
typedef struct _cairo_gl_context cairo_gl_context_t;
cairo_public cairo_gl_context_t *
cairo_gl_context_reference (cairo_gl_context_t *context);
cairo_public void
cairo_gl_context_destroy (cairo_gl_context_t *context);
cairo_public cairo_surface_t *
cairo_gl_surface_create (cairo_gl_context_t *ctx,
cairo_content_t content,
int width, int height);
cairo_public void
cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
cairo_public int
cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
cairo_public int
cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
cairo_public void
cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_gl_surface_glfinish (cairo_surface_t *surface);
#if CAIRO_HAS_GLX_FUNCTIONS
#include <GL/glx.h>
cairo_public cairo_gl_context_t *
cairo_glx_context_create (Display *dpy, GLXContext gl_ctx);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
Window win,
int width, int height);
#endif
#if CAIRO_HAS_EAGLE_FUNCTIONS
#include <eagle.h>
cairo_public cairo_gl_context_t *
cairo_eagle_context_create (EGLDisplay display, EGLContext context);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
EGLSurface surface,
int width, int height);
#endif
CAIRO_END_DECLS
#else /* CAIRO_HAS_GL_SURFACE */
# error Cairo was not compiled with support for the GL backend
#endif /* CAIRO_HAS_GL_SURFACE */
#endif /* CAIRO_GL_H */

View File

@ -27,6 +27,7 @@
#include "cairoint.h"
#include "cairo-glitz.h"
#include "cairo-glitz-private.h"
#include "cairo-region-private.h"
typedef struct _cairo_glitz_surface {
cairo_surface_t base;
@ -34,6 +35,7 @@ typedef struct _cairo_glitz_surface {
glitz_surface_t *surface;
glitz_format_t *format;
cairo_region_t *clip_region;
cairo_bool_t has_clip;
glitz_box_t *clip_boxes;
int num_clip_boxes;
@ -50,6 +52,7 @@ _cairo_glitz_surface_finish (void *abstract_surface)
if (surface->clip_boxes)
free (surface->clip_boxes);
cairo_region_destroy (surface->clip_region);
glitz_surface_destroy (surface->surface);
return CAIRO_STATUS_SUCCESS;
@ -106,43 +109,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
return crsurface;
}
static cairo_status_t
_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
glitz_box_t **boxes,
int *nboxes)
{
pixman_box32_t *pboxes;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
int n, i;
n = 0;
pboxes = pixman_region32_rectangles (&region->rgn, &n);
if (n == 0) {
*nboxes = 0;
return CAIRO_STATUS_SUCCESS;
}
if (n > *nboxes) {
*boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
if (*boxes == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto done;
}
}
for (i = 0; i < n; i++) {
(*boxes)[i].x1 = pboxes[i].x1;
(*boxes)[i].y1 = pboxes[i].y1;
(*boxes)[i].x2 = pboxes[i].x2;
(*boxes)[i].y2 = pboxes[i].y2;
}
*nboxes = n;
done:
return status;
}
static cairo_status_t
_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_rectangle_int_t *interest,
@ -366,7 +332,6 @@ _cairo_glitz_surface_release_dest_image (void *abstract_surfa
static cairo_status_t
_cairo_glitz_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
cairo_content_t content,
int src_x,
int src_y,
int width,
@ -441,10 +406,57 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
glitz_surface_set_transform (surface->surface, &transform);
}
static cairo_bool_t
_is_supported_operator (cairo_operator_t op)
{
/* This is really just a if (op < SATURATE), but we use a switch
* so the compiler will warn if we ever add more operators.
*/
switch (op) {
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_DEST_ATOP:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
return TRUE;
default:
ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_SATURATE:
/* nobody likes saturate, expect that it's required to do
* seamless polygons!
*/
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return FALSE;
}
}
static glitz_operator_t
_glitz_operator (cairo_operator_t op)
{
switch (op) {
switch ((int) op) {
case CAIRO_OPERATOR_CLEAR:
return GLITZ_OPERATOR_CLEAR;
@ -474,24 +486,17 @@ _glitz_operator (cairo_operator_t op)
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
case CAIRO_OPERATOR_SATURATE:
/* XXX: This line should never be reached. Glitz backend should bail
out earlier if saturate operator is used. OpenGL can't do saturate
with pre-multiplied colors. Solid colors can still be done as we
can just un-pre-multiply them. However, support for that will have
to be added to glitz. */
/* fall-through */
break;
default:
ASSERT_NOT_REACHED;
/* Something's very broken if this line of code can be reached, so
* we want to return something that would give a noticeably
* incorrect result. The XOR operator seems so rearely desired
* that it should fit the bill here.
*/
return CAIRO_OPERATOR_XOR;
}
ASSERT_NOT_REACHED;
/* Something's very broken if this line of code can be reached, so
we want to return something that would give a noticeably
incorrect result. The XOR operator seems so rearely desired
that it should fit the bill here. */
return CAIRO_OPERATOR_XOR;
}
#define CAIRO_GLITZ_FEATURE_OK(surface, name) \
@ -649,9 +654,9 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
}
src = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
gradient->n_stops, 1);
_cairo_glitz_surface_create_similar (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
gradient->n_stops, 1);
if (src->base.status) {
glitz_buffer_destroy (buffer);
free (data);
@ -731,7 +736,6 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_int_status_t status;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
x, y, width, height,
CAIRO_PATTERN_ACQUIRE_NONE,
(cairo_surface_t **) &src,
@ -877,6 +881,77 @@ _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
a->params, a->n_params);
}
static cairo_status_t
_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
glitz_box_t **boxes,
int *nboxes)
{
pixman_box32_t *pboxes;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
int n, i;
n = 0;
pboxes = pixman_region32_rectangles (&region->rgn, &n);
if (n == 0) {
*nboxes = 0;
return CAIRO_STATUS_SUCCESS;
}
if (n > *nboxes) {
*boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
if (*boxes == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto done;
}
}
for (i = 0; i < n; i++) {
(*boxes)[i].x1 = pboxes[i].x1;
(*boxes)[i].y1 = pboxes[i].y1;
(*boxes)[i].x2 = pboxes[i].x2;
(*boxes)[i].y2 = pboxes[i].y2;
}
*nboxes = n;
done:
return status;
}
static cairo_status_t
_cairo_glitz_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_glitz_surface_t *surface = abstract_surface;
if (region == surface->clip_region)
return CAIRO_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
if (region != NULL) {
cairo_status_t status;
status = _cairo_glitz_get_boxes_from_region (region,
&surface->clip_boxes,
&surface->num_clip_boxes);
if (status)
return status;
glitz_surface_set_clip_region (surface->surface,
0, 0,
surface->clip_boxes,
surface->num_clip_boxes);
surface->has_clip = TRUE;
} else {
glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
surface->has_clip = FALSE;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_glitz_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
@ -889,7 +964,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t src_attr, mask_attr;
cairo_glitz_surface_t *dst = abstract_dst;
@ -897,12 +973,16 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
cairo_glitz_surface_t *mask;
cairo_int_status_t status;
if (op == CAIRO_OPERATOR_SATURATE)
if (! _is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, clip_region);
if (status)
return status;
status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
dst,
src_x, src_y,
@ -969,7 +1049,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
mask_width, mask_height,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
}
if (mask)
@ -1000,8 +1081,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)];
glitz_rectangle_t *glitz_rects = stack_rects;
glitz_rectangle_t *current_rect;
cairo_status_t status;
int i;
if (! _is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
if (n_rects > ARRAY_LENGTH (stack_rects)) {
glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t));
if (glitz_rects == NULL)
@ -1064,12 +1152,12 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
_cairo_surface_create_similar_solid (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
1, 1,
(cairo_color_t *) color);
if (src->base.status)
{
(cairo_color_t *) color,
FALSE);
if (src == NULL || src->base.status) {
if (glitz_rects != stack_rects)
free (glitz_rects);
return src->base.status;
return src ? src->base.status : CAIRO_INT_STATUS_UNSUPPORTED;
}
glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
@ -1113,7 +1201,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int n_traps)
int n_traps,
cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_t *dst = abstract_dst;
@ -1133,12 +1222,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (op == CAIRO_OPERATOR_SATURATE)
if (! _is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
/* Convert traps to pixman traps */
if (n_traps > ARRAY_LENGTH (stack_traps)) {
pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t));
@ -1281,7 +1374,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
n_traps, (pixman_trapezoid_t *) pixman_traps);
mask = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
_cairo_glitz_surface_create_similar (&dst->base,
CAIRO_CONTENT_ALPHA,
width, height);
status = mask->base.status;
@ -1338,7 +1431,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
0, 0,
dst_x, dst_y,
width, height);
width, height,
clip_region);
}
FAIL:
@ -1353,35 +1447,7 @@ FAIL:
return status;
}
static cairo_int_status_t
_cairo_glitz_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_glitz_surface_t *surface = abstract_surface;
if (region != NULL) {
cairo_status_t status;
status = _cairo_glitz_get_boxes_from_region (region,
&surface->clip_boxes,
&surface->num_clip_boxes);
if (status)
return status;
glitz_surface_set_clip_region (surface->surface,
0, 0,
surface->clip_boxes,
surface->num_clip_boxes);
surface->has_clip = TRUE;
} else {
glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
surface->has_clip = FALSE;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_glitz_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1392,7 +1458,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface,
rectangle->width = glitz_surface_get_width (surface->surface);
rectangle->height = glitz_surface_get_height (surface->surface);
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
#define CAIRO_GLITZ_AREA_AVAILABLE 0
@ -1995,7 +2061,8 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs)
int num_glyphs,
cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_glyph_private_t *glyph_private;
@ -2028,7 +2095,7 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
scaled_font->surface_backend != _cairo_glitz_surface_get_backend ())
return CAIRO_INT_STATUS_UNSUPPORTED;
if (op == CAIRO_OPERATOR_SATURATE)
if (! _is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
/* XXX Unbounded operators are not handled correctly */
@ -2038,6 +2105,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, NULL);
if (unlikely (status))
return status;
status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
src_x, src_y,
width, height,
@ -2150,7 +2221,6 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
status =
_cairo_glitz_surface_clone_similar (abstract_surface,
image,
CAIRO_CONTENT_COLOR_ALPHA,
0,
0,
glyph_width,
@ -2286,25 +2356,13 @@ _cairo_glitz_surface_is_similar (void *surface_a,
return drawable_a == drawable_b;
}
static cairo_status_t
_cairo_glitz_surface_reset (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_glitz_surface_set_clip_region (surface, NULL);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
CAIRO_SURFACE_TYPE_GLITZ,
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_finish,
_cairo_glitz_surface_acquire_source_image,
_cairo_glitz_surface_release_source_image,
_cairo_glitz_surface_acquire_dest_image,
_cairo_glitz_surface_release_dest_image,
_cairo_glitz_surface_clone_similar,
@ -2313,10 +2371,9 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_composite_trapezoids,
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_glitz_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_glitz_surface_get_extents,
_cairo_glitz_surface_old_show_glyphs,
NULL, /* get_font_options */
@ -2333,8 +2390,6 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_snapshot,
_cairo_glitz_surface_is_similar,
_cairo_glitz_surface_reset
};
static const cairo_surface_backend_t *
@ -2384,6 +2439,7 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
crsurface->has_clip = FALSE;
crsurface->clip_boxes = NULL;
crsurface->num_clip_boxes = 0;
crsurface->clip_region = NULL;
return &crsurface->base;
}

View File

@ -0,0 +1,195 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include <X11/Xutil.h>
/* XXX needs hooking into XCloseDisplay() */
typedef struct _cairo_glx_context {
cairo_gl_context_t base;
Display *display;
Window dummy_window;
GLXContext context;
} cairo_glx_context_t;
typedef struct _cairo_glx_surface {
cairo_gl_surface_t base;
Window win;
} cairo_glx_surface_t;
static void
_glx_make_current (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
{
cairo_glx_context_t *ctx = abstract_ctx;
cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
/* Set the window as the target of our context. */
glXMakeCurrent (ctx->display, surface->win, ctx->context);
}
static void
_glx_swap_buffers (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
{
cairo_glx_context_t *ctx = abstract_ctx;
cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
glXSwapBuffers (ctx->display, surface->win);
}
static void
_glx_destroy (void *abstract_ctx)
{
cairo_glx_context_t *ctx = abstract_ctx;
if (ctx->dummy_window != None)
XDestroyWindow (ctx->display, ctx->dummy_window);
}
static cairo_status_t
_glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy)
{
int attr[3] = { GLX_FBCONFIG_ID, 0, None };
GLXFBConfig *config;
XVisualInfo *vi;
Colormap cmap;
XSetWindowAttributes swa;
Window win = None;
int cnt;
/* Create a dummy window created for the target GLX context that we can
* use to query the available GL/GLX extensions.
*/
glXQueryContext (dpy, gl_ctx, GLX_FBCONFIG_ID, &attr[1]);
cnt = 0;
config = glXChooseFBConfig (dpy, DefaultScreen (dpy), attr, &cnt);
if (unlikely (cnt == 0))
return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
vi = glXGetVisualFromFBConfig (dpy, config[0]);
XFree (config);
if (unlikely (vi == NULL))
return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
cmap = XCreateColormap (dpy,
RootWindow (dpy, vi->screen),
vi->visual,
AllocNone);
swa.colormap = cmap;
swa.border_pixel = 0;
win = XCreateWindow (dpy, RootWindow (dpy, vi->screen),
-1, -1, 1, 1, 0,
vi->depth,
InputOutput,
vi->visual,
CWBorderPixel | CWColormap, &swa);
XFreeColormap (dpy, cmap);
XFree (vi);
XFlush (dpy);
if (unlikely (! glXMakeCurrent (dpy, win, gl_ctx))) {
XDestroyWindow (dpy, win);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
*dummy = win;
return CAIRO_STATUS_SUCCESS;
}
cairo_gl_context_t *
cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
{
cairo_glx_context_t *ctx;
cairo_status_t status;
Window dummy = None;
status = _glx_dummy_ctx (dpy, gl_ctx, &dummy);
if (unlikely (status))
return _cairo_gl_context_create_in_error (status);
ctx = calloc (1, sizeof (cairo_glx_context_t));
if (unlikely (ctx == NULL))
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
ctx->display = dpy;
ctx->dummy_window = dummy;
ctx->context = gl_ctx;
ctx->base.make_current = _glx_make_current;
ctx->base.swap_buffers = _glx_swap_buffers;
ctx->base.destroy = _glx_destroy;
status = _cairo_gl_context_init (&ctx->base);
if (unlikely (status)) {
free (ctx);
return _cairo_gl_context_create_in_error (status);
}
return &ctx->base;
}
cairo_surface_t *
cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
Window win,
int width,
int height)
{
cairo_glx_surface_t *surface;
if (unlikely (ctx->status))
return _cairo_surface_create_in_error (ctx->status);
surface = calloc (1, sizeof (cairo_glx_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_gl_surface_init (ctx, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA, width, height);
surface->win = win;
return &surface->base.base;
}

View File

@ -100,7 +100,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
_cairo_font_options_init_default (&gstate->font_options);
_cairo_clip_init (&gstate->clip, target);
_cairo_clip_init (&gstate->clip);
gstate->target = cairo_surface_reference (target);
gstate->parent_target = NULL;
@ -164,14 +164,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
status = _cairo_clip_init_copy (&gstate->clip, &other->clip);
if (unlikely (status)) {
_cairo_stroke_style_fini (&gstate->stroke_style);
cairo_font_face_destroy (gstate->font_face);
cairo_scaled_font_destroy (gstate->scaled_font);
cairo_scaled_font_destroy (gstate->previous_scaled_font);
return status;
}
_cairo_clip_init_copy (&gstate->clip, &other->clip);
gstate->target = cairo_surface_reference (other->target);
/* parent_target is always set to NULL; it's only ever set by redirect_target */
@ -299,7 +292,7 @@ _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
cairo_status_t
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
{
cairo_status_t status;
cairo_matrix_t matrix;
/* If this gstate is already redirected, this is an error; we need a
* new gstate to be able to redirect */
@ -315,18 +308,15 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
* since its ref is now owned by gstate->parent_target */
gstate->target = cairo_surface_reference (child);
_cairo_clip_reset (&gstate->clip);
status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child);
if (unlikely (status))
return status;
/* The clip is in surface backend coordinates for the previous target;
* translate it into the child's backend coordinates. */
_cairo_clip_translate (&gstate->clip,
_cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0),
_cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0));
return CAIRO_STATUS_SUCCESS;
cairo_matrix_init_translate (&matrix,
child->device_transform.x0 - gstate->parent_target->device_transform.x0,
child->device_transform.y0 - gstate->parent_target->device_transform.y0);
_cairo_clip_reset (&gstate->clip);
return _cairo_clip_init_copy_transformed (&gstate->clip,
&gstate->next->clip,
&matrix);
}
/**
@ -549,16 +539,19 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash
if (dash_total == 0.0)
return _cairo_error (CAIRO_STATUS_INVALID_DASH);
/* A single dash value indicate symmetric repeating, so the total
/* An odd dash value indicate symmetric repeating, so the total
* is twice as long. */
if (gstate->stroke_style.num_dashes == 1)
if (gstate->stroke_style.num_dashes & 1)
dash_total *= 2;
/* The dashing code doesn't like a negative offset, so we compute
* the equivalent positive offset. */
if (offset < 0)
offset += ceil (-offset / dash_total + 0.5) * dash_total;
/* The dashing code doesn't like a negative offset or a big positive
* offset, so we compute an equivalent offset which is guaranteed to be
* positive and less than twice the pattern length. */
offset = fmod (offset, dash_total);
if (offset < 0.0)
offset += dash_total;
if (offset <= 0.0) /* Take care of -0 */
offset = 0.0;
gstate->stroke_style.dash_offset = offset;
return CAIRO_STATUS_SUCCESS;
@ -827,13 +820,83 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
*y2 = py2;
}
static void
_init_solid_for_color_stop (cairo_solid_pattern_t *solid,
const cairo_color_t *color)
{
cairo_color_t premult;
/* Color stops aren't premultiplied, so fix that here */
_cairo_color_init_rgba (&premult,
color->red,
color->green,
color->blue,
color->alpha);
_cairo_pattern_init_solid (solid, &premult, CAIRO_CONTENT_COLOR_ALPHA);
}
static void
_cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original)
{
/* First check if the we can replace the original with a much simpler
* pattern. For example, gradients that are uniform or just have a single
* stop can be replace with a solid.
*/
switch (original->type) {
case CAIRO_PATTERN_TYPE_SOLID:
case CAIRO_PATTERN_TYPE_SURFACE:
break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
{
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) original;
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2) {
if (src->n_stops) {
_init_solid_for_color_stop ((cairo_solid_pattern_t *) pattern,
&src->stops->color);
} else {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_ALPHA);
}
return;
} else {
unsigned int i;
/* Is the gradient a uniform colour?
* Happens more often than you would believe.
*/
for (i = 1; i < src->n_stops; i++) {
if (! _cairo_color_equal (&src->stops[0].color,
&src->stops[i].color))
{
break;
}
}
if (i == src->n_stops) {
_init_solid_for_color_stop ((cairo_solid_pattern_t *) pattern,
&src->stops->color);
return;
}
}
}
}
_cairo_pattern_init_static_copy (pattern, original);
}
static void
_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
cairo_pattern_t *pattern,
cairo_pattern_t *original,
cairo_matrix_t *ctm_inverse)
const cairo_pattern_t *original,
const cairo_matrix_t *ctm_inverse)
{
_cairo_pattern_init_static_copy (pattern, original);
_cairo_gstate_copy_pattern (pattern, original);
/* apply device_transform first so that it is transformed by ctm_inverse */
if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
@ -849,6 +912,10 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
if (_cairo_surface_has_device_transform (gstate->target))
_cairo_pattern_transform (pattern,
&gstate->target->device_transform_inverse);
}
static void
@ -870,82 +937,156 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
&gstate->ctm_inverse);
}
/* We need to take a copy of the clip so that the lower layers may modify it
* by, perhaps, intersecting it with the operation extents and other paths.
*/
#define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip)
static cairo_bool_t
_clipped (cairo_gstate_t *gstate)
{
cairo_rectangle_int_t extents;
if (gstate->clip.all_clipped)
return TRUE;
/* XXX consider applying a surface clip? */
if (gstate->clip.path == NULL)
return FALSE;
if (_cairo_surface_get_extents (gstate->target, &extents)) {
if (extents.width == 0 || extents.height == 0)
return TRUE;
if (! _cairo_rectangle_intersect (&extents,
&gstate->clip.path->extents))
{
return TRUE;
}
}
/* perform a simple query to exclude trivial all-clipped cases */
return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
}
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_clip_t clip;
cairo_status_t status;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
return _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
NULL);
status = _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
return status;
}
cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern, mask_pattern;
cairo_clip_t clip;
cairo_status_t status;
if (mask->status)
if (unlikely (mask->status))
return mask->status;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
if (_cairo_pattern_is_opaque (mask))
return _cairo_gstate_paint (gstate);
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
return _cairo_surface_mask (gstate->target,
gstate->op,
&source_pattern.base,
&mask_pattern.base,
NULL);
if (source_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_color_t combined;
if (mask_pattern.base.has_component_alpha) {
#define M(R, A, B, c) R.c = A.c * B.c
M(combined, source_pattern.solid.color, mask_pattern.solid.color, red);
M(combined, source_pattern.solid.color, mask_pattern.solid.color, green);
M(combined, source_pattern.solid.color, mask_pattern.solid.color, blue);
M(combined, source_pattern.solid.color, mask_pattern.solid.color, alpha);
#undef M
} else {
combined = source_pattern.solid.color;
_cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
}
_cairo_pattern_init_solid (&source_pattern.solid, &combined,
source_pattern.solid.content |
mask_pattern.solid.content);
status = _cairo_surface_paint (gstate->target,
gstate->op,
&source_pattern.base,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_mask (gstate->target,
gstate->op,
&source_pattern.base,
&mask_pattern.base,
_gstate_get_clip (gstate, &clip));
}
_cairo_clip_fini (&clip);
return status;
}
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern;
cairo_clip_t clip;
cairo_status_t status;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
return _cairo_surface_stroke (gstate->target,
gstate->op,
&source_pattern.base,
path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
NULL);
status = _cairo_surface_stroke (gstate->target,
gstate->op,
&source_pattern.base,
path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
return status;
}
cairo_status_t
@ -981,13 +1122,13 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
return CAIRO_STATUS_SUCCESS;
}
limit.p1.x = _cairo_fixed_from_double (x) - 1;
limit.p1.y = _cairo_fixed_from_double (y) - 1;
limit.p2.x = limit.p1.x + 2;
limit.p2.y = limit.p1.y + 2;
limit.p1.x = _cairo_fixed_from_double (x) - 5;
limit.p1.y = _cairo_fixed_from_double (y) - 5;
limit.p2.x = limit.p1.x + 5;
limit.p2.y = limit.p1.y + 5;
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &limit);
_cairo_traps_limit (&traps, &limit, 1);
status = _cairo_path_fixed_stroke_to_traps (path,
&gstate->stroke_style,
@ -1009,42 +1150,92 @@ BAIL:
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_clip_t clip;
cairo_status_t status;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
if (_cairo_path_fixed_fill_is_empty (path)) {
if (_cairo_operator_bounded_by_mask (gstate->op))
return CAIRO_STATUS_SUCCESS;
return _cairo_surface_fill (gstate->target,
gstate->op,
&pattern.base,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
NULL);
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_COLOR_ALPHA);
status = _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
&pattern.base,
_gstate_get_clip (gstate, &clip));
} else {
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
status = _cairo_surface_fill (gstate->target,
gstate->op,
&pattern.base,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
}
_cairo_clip_fini (&clip);
return status;
}
void
cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret)
double y)
{
_cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_path_fixed_in_fill (path,
gstate->fill_rule,
gstate->tolerance,
x, y,
inside_ret);
return _cairo_path_fixed_in_fill (path,
gstate->fill_rule,
gstate->tolerance,
x, y);
}
cairo_bool_t
_cairo_gstate_in_clip (cairo_gstate_t *gstate,
double x,
double y)
{
cairo_clip_path_t *clip_path;
if (gstate->clip.all_clipped)
return FALSE;
clip_path = gstate->clip.path;
if (clip_path == NULL)
return TRUE;
_cairo_gstate_user_to_backend (gstate, &x, &y);
if (x < clip_path->extents.x ||
x >= clip_path->extents.x + clip_path->extents.width ||
y < clip_path->extents.y ||
y >= clip_path->extents.y + clip_path->extents.height)
{
return FALSE;
}
do {
if (! _cairo_path_fixed_in_fill (&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
x, y))
return FALSE;
} while ((clip_path = clip_path->prev) != NULL);
return TRUE;
}
cairo_status_t
@ -1132,7 +1323,7 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
&gstate->ctm_inverse,
gstate->tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS) {
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
@ -1151,13 +1342,25 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
cairo_status_t status;
cairo_traps_t traps;
if (path->is_empty_fill) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
return CAIRO_STATUS_SUCCESS;
}
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_to_traps (path,
gstate->fill_rule,
gstate->tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS) {
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
@ -1179,26 +1382,31 @@ cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
return _cairo_clip_clip (&gstate->clip,
path, gstate->fill_rule, gstate->tolerance,
gstate->antialias, gstate->target);
path, gstate->fill_rule,
gstate->tolerance, gstate->antialias);
}
static cairo_status_t
static cairo_bool_t
_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_bounded;
status = _cairo_surface_get_extents (gstate->target, extents);
if (unlikely (status))
return status;
is_bounded = _cairo_surface_get_extents (gstate->target, extents);
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
clip_extents = _cairo_clip_get_extents (&gstate->clip);
if (clip_extents != NULL) {
cairo_bool_t is_empty;
return status;
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
is_bounded = TRUE;
}
return is_bounded;
}
cairo_status_t
cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
@ -1207,11 +1415,9 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
{
cairo_rectangle_int_t extents;
double px1, py1, px2, py2;
cairo_status_t status;
status = _cairo_gstate_int_clip_extents (gstate, &extents);
if (unlikely (status))
return status;
if (! _cairo_gstate_int_clip_extents (gstate, &extents))
return FALSE;
px1 = extents.x;
py1 = extents.y;
@ -1231,7 +1437,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
if (y2)
*y2 = py2;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
cairo_rectangle_list_t*
@ -1580,13 +1786,13 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
cairo_text_cluster_t *transformed_clusters;
cairo_status_t status;
cairo_clip_t clip;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
@ -1653,8 +1859,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
transformed_clusters, num_clusters,
cluster_flags,
gstate->scaled_font, NULL);
} else {
gstate->scaled_font,
_gstate_get_clip (gstate, &clip));
}
else
{
cairo_path_fixed_t path;
_cairo_path_fixed_init (&path);
@ -1663,18 +1872,22 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&path);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias, NULL);
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
_gstate_get_clip (gstate, &clip));
}
_cairo_path_fixed_fini (&path);
}
_cairo_clip_fini (&clip);
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs);
@ -1775,17 +1988,12 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
cairo_status_t status;
if (num_transformed_glyphs != NULL) {
cairo_rectangle_int_t surface_extents;
drop = TRUE;
status = _cairo_gstate_int_clip_extents (gstate, &surface_extents);
if (_cairo_status_is_error (status))
return status;
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
drop = FALSE; /* unbounded surface */
} else {
double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);

View File

@ -191,9 +191,6 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
{
if (hash_table == NULL)
return;
/* The hash table must be empty. Otherwise, halt. */
assert (hash_table->live_entries == 0);
/* No iterators can be running. Otherwise, halt. */
@ -525,9 +522,6 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
unsigned long i;
cairo_hash_entry_t *entry;
if (hash_table == NULL)
return;
/* Mark the table for iteration */
++hash_table->iterating;
for (i = 0; i < hash_table->arrangement->size; i++) {

View File

@ -36,6 +36,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
typedef struct cairo_hull {
cairo_point_t point;
cairo_slope_t slope;

View File

@ -37,6 +37,21 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-region-private.h"
/* Limit on the width / height of an image surface in pixels. This is
* mainly determined by coordinates of things sent to pixman at the
* moment being in 16.16 format. */
#define MAX_IMAGE_SIZE 32767
static cairo_bool_t
_cairo_image_surface_is_size_valid (int width, int height)
{
return 0 <= width && width <= MAX_IMAGE_SIZE &&
0 <= height && height <= MAX_IMAGE_SIZE;
}
static cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
@ -63,6 +78,14 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_x2b10g10r10:
case PIXMAN_a2b10g10r10:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
case PIXMAN_b8g8r8x8:
case PIXMAN_b8g8r8a8:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_x2r10g10b10:
case PIXMAN_a2r10g10b10:
#endif
default:
return CAIRO_FORMAT_INVALID;
@ -87,6 +110,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
case PIXMAN_a1b1g1r1:
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_a2b10g10r10:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
case PIXMAN_b8g8r8a8:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_a2r10g10b10:
#endif
return CAIRO_CONTENT_COLOR_ALPHA;
case PIXMAN_x8r8g8b8:
@ -112,6 +141,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
case PIXMAN_yv12:
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_x2b10g10r10:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
case PIXMAN_b8g8r8x8:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_x2r10g10b10:
#endif
return CAIRO_CONTENT_COLOR;
case PIXMAN_a8:
@ -129,6 +164,12 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
pixman_format_code_t pixman_format)
{
cairo_image_surface_t *surface;
int width = pixman_image_get_width (pixman_image);
int height = pixman_image_get_height (pixman_image);
if (! _cairo_image_surface_is_size_valid (width, height)) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
}
surface = malloc (sizeof (cairo_image_surface_t));
if (unlikely (surface == NULL))
@ -143,14 +184,15 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->format = _cairo_format_from_pixman_format (pixman_format);
surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
surface->owns_data = FALSE;
surface->has_clip = FALSE;
surface->transparency = CAIRO_IMAGE_UNKNOWN;
surface->width = pixman_image_get_width (pixman_image);
surface->height = pixman_image_get_height (pixman_image);
surface->width = width;
surface->height = height;
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
surface->clip_region = NULL;
return &surface->base;
}
@ -188,11 +230,10 @@ _pixman_format_from_masks (cairo_format_masks_t *masks,
* expected. This avoid any problems from something bizarre like
* alpha in the least-significant bits, or insane channel order,
* or whatever. */
_pixman_format_to_masks (format, &format_masks);
if (masks->bpp != format_masks.bpp ||
masks->red_mask != format_masks.red_mask ||
masks->green_mask != format_masks.green_mask ||
if (!_pixman_format_to_masks (format, &format_masks) ||
masks->bpp != format_masks.bpp ||
masks->red_mask != format_masks.red_mask ||
masks->green_mask != format_masks.green_mask ||
masks->blue_mask != format_masks.blue_mask)
{
return FALSE;
@ -205,7 +246,7 @@ _pixman_format_from_masks (cairo_format_masks_t *masks,
/* A mask consisting of N bits set to 1. */
#define MASK(N) ((1UL << (N))-1)
void
cairo_bool_t
_pixman_format_to_masks (pixman_format_code_t format,
cairo_format_masks_t *masks)
{
@ -225,19 +266,27 @@ _pixman_format_to_masks (pixman_format_code_t format,
masks->red_mask = MASK (r) << (g + b);
masks->green_mask = MASK (g) << (b);
masks->blue_mask = MASK (b);
return;
return TRUE;
case PIXMAN_TYPE_ABGR:
masks->alpha_mask = MASK (a) << (b + g + r);
masks->blue_mask = MASK (b) << (g +r);
masks->blue_mask = MASK (b) << (g + r);
masks->green_mask = MASK (g) << (r);
masks->red_mask = MASK (r);
return;
return TRUE;
#ifdef PIXMAN_TYPE_BGRA
case PIXMAN_TYPE_BGRA:
masks->blue_mask = MASK (b) << (masks->bpp - b);
masks->green_mask = MASK (g) << (masks->bpp - b - g);
masks->red_mask = MASK (r) << (masks->bpp - b - g - r);
masks->alpha_mask = MASK (a);
return TRUE;
#endif
case PIXMAN_TYPE_A:
masks->alpha_mask = MASK (a);
masks->red_mask = 0;
masks->green_mask = 0;
masks->blue_mask = 0;
return;
return TRUE;
case PIXMAN_TYPE_OTHER:
case PIXMAN_TYPE_COLOR:
case PIXMAN_TYPE_GRAY:
@ -248,7 +297,7 @@ _pixman_format_to_masks (pixman_format_code_t format,
masks->red_mask = 0;
masks->green_mask = 0;
masks->blue_mask = 0;
return;
return FALSE;
}
}
@ -324,6 +373,11 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
cairo_surface_t *surface;
pixman_image_t *pixman_image;
if (! _cairo_image_surface_is_size_valid (width, height))
{
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
}
pixman_image = pixman_image_create_bits (pixman_format, width ? width : 1, height ? height : 1,
(uint32_t *) data, stride ? stride : 4);
@ -332,9 +386,13 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
pixman_format);
if (cairo_surface_status (surface))
if (unlikely (surface->status)) {
pixman_image_unref (pixman_image);
return surface;
}
/* we can not make any assumptions about the initial state of user data */
surface->is_clear = data == NULL;
return surface;
}
@ -458,7 +516,7 @@ slim_hidden_def (cairo_format_stride_for_width);
* and row. This alignment is required to allow high-performance rendering
* within cairo. The correct way to obtain a legal stride value is to
* call cairo_format_stride_for_width() with the desired format and
* maximum image width value, and the use the resulting stride value
* maximum image width value, and then use the resulting stride value
* to allocate the data and to create the image surface. See
* cairo_format_stride_for_width() for example code.
*
@ -504,9 +562,10 @@ cairo_image_surface_create_for_data (unsigned char *data,
}
pixman_format = _cairo_format_to_pixman_format_code (format);
return _cairo_image_surface_create_with_pixman_format (data, pixman_format,
width, height, stride);
return _cairo_image_surface_create_with_pixman_format (data,
pixman_format,
width, height,
stride);
}
slim_hidden_def (cairo_image_surface_create_for_data);
@ -574,6 +633,7 @@ cairo_image_surface_get_format (cairo_surface_t *surface)
return image_surface->format;
}
slim_hidden_def (cairo_image_surface_get_format);
/**
* cairo_image_surface_get_width:
@ -699,12 +759,19 @@ _cairo_format_bits_per_pixel (cairo_format_t format)
}
static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_src,
_cairo_image_surface_create_similar (void *abstract_other,
cairo_content_t content,
int width,
int height)
{
assert (CAIRO_CONTENT_VALID (content));
cairo_image_surface_t *other = abstract_other;
if (content == other->base.content) {
return _cairo_image_surface_create_with_pixman_format (NULL,
other->pixman_format,
width, height,
0);
}
return _cairo_image_surface_create_with_content (content,
width, height);
@ -725,6 +792,8 @@ _cairo_image_surface_finish (void *abstract_surface)
surface->data = NULL;
}
cairo_region_destroy (surface->clip_region);
return CAIRO_STATUS_SUCCESS;
}
@ -784,7 +853,6 @@ _cairo_image_surface_release_dest_image (void *abstract_surfa
static cairo_status_t
_cairo_image_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
cairo_content_t content,
int src_x,
int src_y,
int width,
@ -862,6 +930,39 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_surface_set_extend (cairo_image_surface_t *surface,
cairo_extend_t extend)
{
pixman_repeat_t pixman_repeat;
switch (extend) {
case CAIRO_EXTEND_NONE:
pixman_repeat = PIXMAN_REPEAT_NONE;
break;
case CAIRO_EXTEND_REPEAT:
pixman_repeat = PIXMAN_REPEAT_NORMAL;
break;
case CAIRO_EXTEND_REFLECT:
pixman_repeat = PIXMAN_REPEAT_REFLECT;
break;
case CAIRO_EXTEND_PAD:
pixman_repeat = PIXMAN_REPEAT_PAD;
break;
}
pixman_image_set_repeat (surface->pixman_image, pixman_repeat);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_surface_set_component_alpha (cairo_image_surface_t *surface,
cairo_bool_t ca)
{
pixman_image_set_component_alpha (surface->pixman_image, ca);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
cairo_surface_attributes_t *attributes,
@ -874,25 +975,19 @@ _cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
if (unlikely (status))
return status;
switch (attributes->extend) {
case CAIRO_EXTEND_NONE:
pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_NONE);
break;
case CAIRO_EXTEND_REPEAT:
pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_NORMAL);
break;
case CAIRO_EXTEND_REFLECT:
pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_REFLECT);
break;
case CAIRO_EXTEND_PAD:
pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_PAD);
break;
}
status = _cairo_image_surface_set_filter (surface, attributes->filter);
if (unlikely (status))
return status;
status = _cairo_image_surface_set_extend (surface, attributes->extend);
if (unlikely (status))
return status;
status = _cairo_image_surface_set_component_alpha (surface,
attributes->has_component_alpha);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
@ -936,34 +1031,93 @@ _pixman_operator (cairo_operator_t op)
return PIXMAN_OP_ADD;
case CAIRO_OPERATOR_SATURATE:
return PIXMAN_OP_SATURATE;
case CAIRO_OPERATOR_MULTIPLY:
return PIXMAN_OP_MULTIPLY;
case CAIRO_OPERATOR_SCREEN:
return PIXMAN_OP_SCREEN;
case CAIRO_OPERATOR_OVERLAY:
return PIXMAN_OP_OVERLAY;
case CAIRO_OPERATOR_DARKEN:
return PIXMAN_OP_DARKEN;
case CAIRO_OPERATOR_LIGHTEN:
return PIXMAN_OP_LIGHTEN;
case CAIRO_OPERATOR_COLOR_DODGE:
return PIXMAN_OP_COLOR_DODGE;
case CAIRO_OPERATOR_COLOR_BURN:
return PIXMAN_OP_COLOR_BURN;
case CAIRO_OPERATOR_HARD_LIGHT:
return PIXMAN_OP_HARD_LIGHT;
case CAIRO_OPERATOR_SOFT_LIGHT:
return PIXMAN_OP_SOFT_LIGHT;
case CAIRO_OPERATOR_DIFFERENCE:
return PIXMAN_OP_DIFFERENCE;
case CAIRO_OPERATOR_EXCLUSION:
return PIXMAN_OP_EXCLUSION;
case CAIRO_OPERATOR_HSL_HUE:
return PIXMAN_OP_HSL_HUE;
case CAIRO_OPERATOR_HSL_SATURATION:
return PIXMAN_OP_HSL_SATURATION;
case CAIRO_OPERATOR_HSL_COLOR:
return PIXMAN_OP_HSL_COLOR;
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return PIXMAN_OP_HSL_LUMINOSITY;
default:
ASSERT_NOT_REACHED;
return PIXMAN_OP_OVER;
}
}
static cairo_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
cairo_region_t *region)
{
if (region == surface->clip_region)
return CAIRO_STATUS_SUCCESS;
if (cairo_region_equal (surface->clip_region, region))
return CAIRO_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
if (! pixman_image_set_clip_region32 (surface->pixman_image,
region ? &region->rgn : NULL))
{
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t op,
_cairo_image_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_surface_attributes_t src_attr, mask_attr;
cairo_surface_attributes_t src_attr, mask_attr;
cairo_image_surface_t *dst = abstract_dst;
cairo_image_surface_t *src;
cairo_image_surface_t *mask;
cairo_int_status_t status;
cairo_int_status_t status;
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y,
mask_x, mask_y,
width, height,
@ -980,8 +1134,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
if (unlikely (status))
goto CLEANUP_SURFACES;
if (mask)
{
if (mask) {
status = _cairo_image_surface_set_attributes (mask, &mask_attr,
dst_x + width / 2.,
dst_y + height / 2.);
@ -998,9 +1151,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
mask_y + mask_attr.y_offset,
dst_x, dst_y,
width, height);
}
else
{
} else {
pixman_image_composite (_pixman_operator (op),
src->pixman_image,
NULL,
@ -1012,7 +1163,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
width, height);
}
if (! _cairo_operator_bounded_by_source (op))
if (! _cairo_operator_bounded_by_source (op)) {
status = _cairo_surface_composite_fixup_unbounded (&dst->base,
&src_attr, src->width, src->height,
mask ? &mask_attr : NULL,
@ -1020,7 +1171,9 @@ _cairo_image_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
}
CLEANUP_SURFACES:
if (mask)
@ -1045,7 +1198,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rectangle16_t *pixman_rects = stack_rects;
int i;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_int_status_t status;
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -1055,6 +1208,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_color.blue = color->blue_short;
pixman_color.alpha = color->alpha_short;
status = _cairo_image_surface_set_clip_region (surface, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
if (num_rects > ARRAY_LENGTH (stack_rects)) {
pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t));
if (unlikely (pixman_rects == NULL))
@ -1068,7 +1224,8 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rects[i].height = rects[i].height;
}
/* XXX: pixman_fill_rectangles() should be implemented */
/* XXX: pixman_fill_region() should be implemented */
status = CAIRO_STATUS_SUCCESS;
if (! pixman_image_fill_rectangles (_pixman_operator (op),
surface->pixman_image,
&pixman_color,
@ -1132,7 +1289,8 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
int num_traps,
cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_image_surface_t *dst = abstract_dst;
@ -1153,24 +1311,27 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
* contained within the surface is bounded by [dst_x,dst_y,width,height];
* the Cairo core code passes bounds based on the trapezoid extents.
*
* Currently the check surface->has_clip is needed for correct
* Currently the check clip_region == NULL is needed for correct
* functioning, since pixman_add_trapezoids() doesn't obey the
* surface clip, which is a libpixman bug , but there's no harm in
* falling through to the general case when the surface is clipped
* since libpixman would have to generate an intermediate mask anyways.
*/
if (op == CAIRO_OPERATOR_ADD &&
clip_region == NULL &&
_cairo_pattern_is_opaque_solid (pattern) &&
dst->base.content == CAIRO_CONTENT_ALPHA &&
! dst->has_clip &&
antialias != CAIRO_ANTIALIAS_NONE)
{
_pixman_add_trapezoids (dst->pixman_image, 0, 0, traps, num_traps);
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y, width, height,
CAIRO_PATTERN_ACQUIRE_NONE,
(cairo_surface_t **) &src,
@ -1205,14 +1366,16 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
pixman_image_unref (mask);
if (! _cairo_operator_bounded_by_mask (op))
if (! _cairo_operator_bounded_by_mask (op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
&attributes,
src->width, src->height,
width, height,
src_x, src_y,
0, 0,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
}
CLEANUP_SOURCE:
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
@ -1227,11 +1390,13 @@ typedef struct _cairo_image_surface_span_renderer {
const cairo_pattern_t *pattern;
cairo_antialias_t antialias;
uint8_t *mask_data;
uint32_t mask_stride;
cairo_image_surface_t *src;
cairo_surface_attributes_t src_attributes;
cairo_image_surface_t *mask;
cairo_image_surface_t *dst;
cairo_composite_rectangles_t composite_rectangles;
} cairo_image_surface_span_renderer_t;
@ -1240,66 +1405,46 @@ _cairo_image_surface_span_render_row (
int y,
const cairo_half_open_span_t *spans,
unsigned num_spans,
cairo_image_surface_t *mask,
const cairo_composite_rectangles_t *rects)
uint8_t *data,
uint32_t stride)
{
int xmin = rects->mask.x;
int xmax = xmin + rects->width;
uint8_t *row;
int prev_x = xmin;
int prev_alpha = 0;
unsigned i;
/* Make sure we're within y-range. */
y -= rects->mask.y;
if (y < 0 || y >= rects->height)
if (num_spans == 0)
return;
row = (uint8_t*)(mask->data) + y*(size_t)mask->stride - xmin;
row = data + y * stride;
for (i = 0; i < num_spans - 1; i++) {
if (! spans[i].coverage)
continue;
/* Find the first span within x-range. */
for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
if (i>0)
prev_alpha = spans[i-1].coverage;
/* Set the intermediate spans. */
for (; i < num_spans; i++) {
int x = spans[i].x;
if (x >= xmax)
break;
if (prev_alpha != 0) {
/* We implement setting rendering the most common single
* pixel wide span case to avoid the overhead of a memset
* call. Open coding setting longer spans didn't show a
* noticeable improvement over memset. */
if (x == prev_x + 1) {
row[prev_x] = prev_alpha;
}
else {
memset(row + prev_x, prev_alpha, x - prev_x);
}
/* We implement setting the most common single pixel wide
* span case to avoid the overhead of a memset call.
* Open coding setting longer spans didn't show a
* noticeable improvement over memset.
*/
if (spans[i+1].x == spans[i].x + 1) {
row[spans[i].x] = spans[i].coverage;
} else {
memset (row + spans[i].x,
spans[i].coverage,
spans[i+1].x - spans[i].x);
}
prev_x = x;
prev_alpha = spans[i].coverage;
}
if (prev_alpha != 0 && prev_x < xmax) {
memset(row + prev_x, prev_alpha, xmax - prev_x);
}
}
static cairo_status_t
_cairo_image_surface_span_renderer_render_row (
_cairo_image_surface_span_renderer_render_rows (
void *abstract_renderer,
int y,
int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
_cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
while (height--)
_cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
return CAIRO_STATUS_SUCCESS;
}
@ -1349,16 +1494,18 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
rects->dst.x, rects->dst.y,
width, height);
if (! _cairo_operator_bounded_by_mask (renderer->op))
if (! _cairo_operator_bounded_by_mask (renderer->op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (
&dst->base,
src_attributes,
src->width, src->height,
rects->width, rects->height,
width, height,
rects->src.x, rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
rects->width, rects->height);
width, height,
dst->clip_region);
}
}
if (status != CAIRO_STATUS_SUCCESS)
return _cairo_span_renderer_set_error (abstract_renderer,
@ -1370,15 +1517,13 @@ static cairo_bool_t
_cairo_image_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
cairo_antialias_t antialias)
{
return TRUE;
(void) op;
(void) pattern;
(void) abstract_dst;
(void) antialias;
(void) rects;
return TRUE;
}
static cairo_span_renderer_t *
@ -1386,22 +1531,25 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
cairo_image_surface_span_renderer_t *renderer
= calloc(1, sizeof(*renderer));
cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
cairo_status_t status;
int width = rects->width;
int height = rects->height;
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return _cairo_span_renderer_create_in_error (status);
if (renderer == NULL)
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
renderer->base.finish = _cairo_image_surface_span_renderer_finish;
renderer->base.render_row =
_cairo_image_surface_span_renderer_render_row;
renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
renderer->op = op;
renderer->pattern = pattern;
renderer->antialias = antialias;
@ -1411,7 +1559,6 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
status = _cairo_pattern_acquire_surface (
renderer->pattern, &renderer->dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
rects->src.x, rects->src.y,
width, height,
CAIRO_PATTERN_ACQUIRE_NONE,
@ -1439,24 +1586,13 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
_cairo_image_surface_span_renderer_destroy (renderer);
return _cairo_span_renderer_create_in_error (status);
}
renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
renderer->mask_stride = renderer->mask->stride;
return &renderer->base;
}
cairo_int_status_t
_cairo_image_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
if (! pixman_image_set_clip_region32 (surface->pixman_image, region? &region->rgn : NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
surface->has_clip = region != NULL;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1467,7 +1603,7 @@ _cairo_image_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static void
@ -1479,18 +1615,6 @@ _cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
}
static cairo_status_t
_cairo_image_surface_reset (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_image_surface_set_clip_region (surface, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@ -1521,13 +1645,11 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
_cairo_image_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
_cairo_image_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_image_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_image_surface_get_font_options,
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* mark dirty */
NULL, /* font_fini */
NULL, /* glyph_fini */
@ -1538,8 +1660,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
NULL, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
_cairo_image_surface_reset
};
/* A convenience function for when one needs to coerce an image
@ -1567,7 +1687,8 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface,
_cairo_pattern_init_for_surface (&pattern, &surface->base);
status = _cairo_surface_paint (&clone->base,
CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL);
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
if (unlikely (status)) {

View File

@ -371,37 +371,39 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double min_x, max_x;
double min_y, max_y;
if (_cairo_matrix_is_identity (matrix)) {
if (is_tight)
*is_tight = TRUE;
return;
}
if (matrix->xy == 0. && matrix->yx == 0.) {
/* non-rotation/skew matrix, just map the two extreme points */
quad_x[0] = *x1;
quad_y[0] = *y1;
cairo_matrix_transform_distance (matrix, &quad_x[0], &quad_y[0]);
quad_x[1] = *x2;
quad_y[1] = *y2;
cairo_matrix_transform_distance (matrix, &quad_x[1], &quad_y[1]);
if (quad_x[0] < quad_x[1]) {
*x1 = quad_x[0] + matrix->x0;
*x2 = quad_x[1] + matrix->x0;
} else {
*x1 = quad_x[1] + matrix->x0;
*x2 = quad_x[0] + matrix->x0;
if (matrix->xx != 1.) {
quad_x[0] = *x1 * matrix->xx;
quad_x[1] = *x2 * matrix->xx;
if (quad_x[0] < quad_x[1]) {
*x1 = quad_x[0];
*x2 = quad_x[1];
} else {
*x1 = quad_x[1];
*x2 = quad_x[0];
}
}
if (matrix->x0 != 0.) {
*x1 += matrix->x0;
*x2 += matrix->x0;
}
if (quad_y[0] < quad_y[1]) {
*y1 = quad_y[0] + matrix->y0;
*y2 = quad_y[1] + matrix->y0;
} else {
*y1 = quad_y[1] + matrix->y0;
*y2 = quad_y[0] + matrix->y0;
if (matrix->yy != 1.) {
quad_y[0] = *y1 * matrix->yy;
quad_y[1] = *y2 * matrix->yy;
if (quad_y[0] < quad_y[1]) {
*y1 = quad_y[0];
*y2 = quad_y[1];
} else {
*y1 = quad_y[1];
*y2 = quad_y[0];
}
}
if (matrix->y0 != 0.) {
*y1 += matrix->y0;
*y2 += matrix->y0;
}
if (is_tight)
@ -624,7 +626,7 @@ _cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
double major, minor;
cairo_matrix_transform_distance (matrix, &x, &y);
major = sqrt(x*x + y*y);
major = hypot (x, y);
/*
* ignore mirroring
*/
@ -688,16 +690,9 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
return FALSE;
}
/* By pixel exact here, we mean a matrix that is composed only of
* 90 degree rotations, flips, and integer translations and produces a 1:1
* mapping between source and destination pixels. If we transform an image
* with a pixel-exact matrix, filtering is not useful.
*/
cairo_private cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
cairo_bool_t
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix)
{
cairo_fixed_t x0_fixed, y0_fixed;
if (matrix->xy == 0.0 && matrix->yx == 0.0) {
if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
return FALSE;
@ -711,6 +706,22 @@ _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
} else
return FALSE;
return TRUE;
}
/* By pixel exact here, we mean a matrix that is composed only of
* 90 degree rotations, flips, and integer translations and produces a 1:1
* mapping between source and destination pixels. If we transform an image
* with a pixel-exact matrix, filtering is not useful.
*/
cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
{
cairo_fixed_t x0_fixed, y0_fixed;
if (! _cairo_matrix_has_unity_scale (matrix))
return FALSE;
x0_fixed = _cairo_fixed_from_double (matrix->x0);
y0_fixed = _cairo_fixed_from_double (matrix->y0);
@ -856,7 +867,7 @@ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
g = 0.5 * (i - j);
h = a*c + b*d;
return radius * sqrt (f + sqrt (g*g+h*h));
return radius * sqrt (f + hypot (g, h));
/*
* we don't need the minor axis length, which is

File diff suppressed because it is too large Load Diff

View File

@ -334,6 +334,21 @@ _cairo_operator_bounded_by_mask (cairo_operator_t op)
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return TRUE;
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
@ -372,6 +387,21 @@ _cairo_operator_bounded_by_source (cairo_operator_t op)
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return TRUE;
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:

View File

@ -168,30 +168,16 @@
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif HAVE_PTHREAD_H /*******************************************************/
#elif defined(_WIN32) /******************************************************/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_PTHREAD 1
#if HAVE_LOCKDEP
/* expose all mutexes to the validator */
# define CAIRO_MUTEX_IMPL_INIT(mutex) pthread_mutex_init (&(mutex), NULL)
#define WIN32_LEAN_AND_MEAN
/* We require Windows 2000 features such as ETO_PDY */
#if !defined(WINVER) || (WINVER < 0x0500)
# define WINVER 0x0500
#endif
# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
#if HAVE_LOCKDEP
# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex))
# define CAIRO_MUTEX_IS_UNLOCKED(mutex) LOCKDEP_IS_UNLOCKED (&(mutex))
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
# define _WIN32_WINNT 0x0500
#endif
# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
#if ! HAVE_LOCKDEP
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
#endif
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif defined(HAVE_WINDOWS_H) || defined(_MSC_VER) /*************************/
# include <windows.h>
@ -230,6 +216,30 @@
# define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
#elif CAIRO_HAS_PTHREAD /* and finally if there are no native mutexes ********/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_PTHREAD 1
#if HAVE_LOCKDEP
/* expose all mutexes to the validator */
# define CAIRO_MUTEX_IMPL_INIT(mutex) pthread_mutex_init (&(mutex), NULL)
#endif
# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
#if HAVE_LOCKDEP
# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex))
# define CAIRO_MUTEX_IS_UNLOCKED(mutex) LOCKDEP_IS_UNLOCKED (&(mutex))
#endif
# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
#if ! HAVE_LOCKDEP
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
#endif
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."

View File

@ -52,9 +52,16 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
#endif
#if CAIRO_HAS_GL_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
#endif
#if !defined (HAS_ATOMIC_OPS) || defined (ATOMIC_OP_NEEDS_MEMORY_BARRIER)
CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex)
#endif
#if CAIRO_HAS_DRM_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_drm_device_mutex)
#endif
/* Undefine, to err on unintended inclusion */
#undef CAIRO_MUTEX_DECLARE

View File

@ -0,0 +1,12 @@
/* Generated by configure. Do not edit */
#ifndef CAIRO_NO_FEATURES_H
#define CAIRO_NO_FEATURES_H
#include <cairo-features.h>
/* This is a dummy header, to trick gtk-doc only */
#define CAIRO_HAS_WIN32_FONT 1
#define CAIRO_HAS_WIN32_SURFACE 1
#endif

View File

@ -716,26 +716,18 @@ _cairo_os2_surface_release_dest_image (void *abstract_surface
DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
}
static cairo_int_status_t
static cairo_bool_t
_cairo_os2_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_os2_surface_t *local_os2_surface;
local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
if ((!local_os2_surface) ||
(local_os2_surface->base.backend != &cairo_os2_surface_backend))
{
/* Invalid parameter (wrong surface)! */
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
}
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = local_os2_surface->bitmap_info.cx;
rectangle->height = local_os2_surface->bitmap_info.cy;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
/**
@ -1327,8 +1319,6 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_os2_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */

View File

@ -184,6 +184,10 @@ _cairo_null_stream_create (void);
cairo_private cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output);
/* cairo-base64-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output);
/* cairo-deflate-stream.c */
cairo_private cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output);

View File

@ -41,7 +41,6 @@
#include <stdio.h>
#include <locale.h>
#include <ctype.h>
#include <errno.h>
/* Numbers printed with %f are printed with this number of significant
@ -341,7 +340,7 @@ _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precisi
if (*p == '+' || *p == '-')
p++;
while (isdigit (*p))
while (_cairo_isdigit (*p))
p++;
if (strncmp (p, decimal_point, decimal_point_len) == 0)
@ -362,7 +361,7 @@ _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precisi
if (*p == '+' || *p == '-')
p++;
while (isdigit (*p))
while (_cairo_isdigit (*p))
p++;
if (strncmp (p, decimal_point, decimal_point_len) == 0) {
@ -434,7 +433,7 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
f++;
}
while (isdigit (*f))
while (_cairo_isdigit (*f))
f++;
length_modifier = 0;

View File

@ -98,7 +98,7 @@ struct _cairo_paginated_surface_backend {
* to follow.
*
* What the paginated surface does is first save all drawing
* operations for a page into a meta-surface. Then when the user calls
* operations for a page into a recording-surface. Then when the user calls
* cairo_show_page(), the paginated surface performs the following
* sequence of operations (using the backend functions passed to
* cairo_paginated_surface_create()):
@ -109,7 +109,7 @@ struct _cairo_paginated_surface_backend {
*
* 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE
*
* 3. Replays the meta-surface to the target surface, (with an
* 3. Replays the recording-surface to the target surface, (with an
* analysis surface inserted between which watches the return value
* from each operation). This analysis stage is used to decide which
* operations will require fallbacks.
@ -119,7 +119,7 @@ struct _cairo_paginated_surface_backend {
*
* 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER
*
* 6. Replays a subset of the meta-surface operations to the target surface
* 6. Replays a subset of the recording-surface operations to the target surface
*
* 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK
*
@ -149,8 +149,6 @@ struct _cairo_paginated_surface_backend {
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height,
const cairo_paginated_surface_backend_t *backend);
cairo_private cairo_surface_t *

View File

@ -48,25 +48,16 @@ typedef struct _cairo_paginated_surface {
cairo_content_t content;
/* XXX: These shouldn't actually exist. We inherit this ugliness
* from _cairo_meta_surface_create. The width/height parameters
* from that function also should not exist. The fix that will
* allow us to remove all of these is to fix acquire_source_image
* to pass an interest rectangle. */
int width;
int height;
/* Paginated-surface specific functions for the target */
const cairo_paginated_surface_backend_t *backend;
/* A cairo_meta_surface to record all operations. To be replayed
/* A cairo_recording_surface to record all operations. To be replayed
* against target, and also against image surface as necessary for
* fallbacks. */
cairo_surface_t *meta;
cairo_surface_t *recording_surface;
int page_num;
cairo_bool_t page_is_blank;
} cairo_paginated_surface_t;
#endif /* CAIRO_PAGINATED_SURFACE_H */

View File

@ -46,7 +46,7 @@
#include "cairo-paginated-private.h"
#include "cairo-paginated-surface-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
static const cairo_surface_backend_t cairo_paginated_surface_backend;
@ -60,17 +60,36 @@ _cairo_paginated_surface_create_similar (void *abstract_surface,
int width,
int height)
{
cairo_paginated_surface_t *surface = abstract_surface;
return cairo_surface_create_similar (surface->target, content,
width, height);
cairo_rectangle_t rect;
rect.x = rect.y = 0.;
rect.width = width;
rect.height = height;
return cairo_recording_surface_create (content, &rect);
}
static cairo_surface_t *
_create_recording_surface_for_target (cairo_surface_t *target,
cairo_content_t content)
{
cairo_rectangle_int_t rect;
if (_cairo_surface_get_extents (target, &rect)) {
cairo_rectangle_t recording_extents;
recording_extents.x = rect.x;
recording_extents.y = rect.y;
recording_extents.width = rect.width;
recording_extents.height = rect.height;
return cairo_recording_surface_create (content, &recording_extents);
} else {
return cairo_recording_surface_create (content, NULL);
}
}
/* XXX The integer width,height here should be doubles and all uses updated */
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height,
const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
@ -87,18 +106,15 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
/* Override surface->base.type with target's type so we don't leak
* evidence of the paginated wrapper out to the user. */
surface->base.type = cairo_surface_get_type (target);
surface->base.type = target->type;
surface->target = cairo_surface_reference (target);
surface->content = content;
surface->width = width;
surface->height = height;
surface->backend = backend;
surface->meta = cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
surface->recording_surface = _create_recording_surface_for_target (target, content);
status = surface->recording_surface->status;
if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
@ -132,31 +148,6 @@ _cairo_paginated_surface_get_target (cairo_surface_t *surface)
return paginated_surface->target;
}
cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width,
int height)
{
cairo_paginated_surface_t *paginated_surface;
cairo_status_t status;
assert (_cairo_surface_is_paginated (surface));
paginated_surface = (cairo_paginated_surface_t *) surface;
paginated_surface->width = width;
paginated_surface->height = height;
cairo_surface_destroy (paginated_surface->meta);
paginated_surface->meta = cairo_meta_surface_create (paginated_surface->content,
width, height);
status = cairo_surface_status (paginated_surface->meta);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
@ -168,19 +159,22 @@ _cairo_paginated_surface_finish (void *abstract_surface)
status = cairo_surface_status (abstract_surface);
}
if (status == CAIRO_STATUS_SUCCESS) {
/* XXX We want to propagate any errors from destroy(), but those are not
* returned via the api. So we need to explicitly finish the target,
* and check the status afterwards. However, we can only call finish()
* on the target, if we own it.
*/
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) {
cairo_surface_finish (surface->target);
status = cairo_surface_status (surface->target);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->target);
}
if (status == CAIRO_STATUS_SUCCESS) {
cairo_surface_finish (surface->meta);
status = cairo_surface_status (surface->meta);
}
cairo_surface_destroy (surface->target);
cairo_surface_destroy (surface->meta);
cairo_surface_finish (surface->recording_surface);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->recording_surface);
cairo_surface_destroy (surface->recording_surface);
return status;
}
@ -210,19 +204,20 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
void **image_extra)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_bool_t is_bounded;
cairo_surface_t *image;
cairo_status_t status;
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (surface->target, &extents);
if (unlikely (status))
return status;
is_bounded = _cairo_surface_get_extents (surface->target, &extents);
if (! is_bounded)
return CAIRO_INT_STATUS_UNSUPPORTED;
image = _cairo_paginated_surface_create_image_surface (surface,
extents.width,
extents.height);
status = cairo_meta_surface_replay (surface->meta, image);
status = _cairo_recording_surface_replay (surface->recording_surface, image);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
@ -248,11 +243,11 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
{
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
cairo_matrix_t matrix;
int x, y, width, height;
cairo_status_t status;
cairo_surface_t *image;
cairo_surface_pattern_t pattern;
cairo_clip_t clip;
x = rect->x;
y = rect->y;
@ -266,20 +261,26 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
* so we have to do the scaling manually. */
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
status = cairo_meta_surface_replay (surface->meta, image);
status = _cairo_recording_surface_replay (surface->recording_surface, image);
if (unlikely (status))
goto CLEANUP_IMAGE;
_cairo_pattern_init_for_surface (&pattern, image);
cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
cairo_pattern_set_matrix (&pattern.base, &matrix);
cairo_matrix_init (&pattern.base.matrix,
x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
/* the fallback should be rendered at native resolution, so disable
* filtering (if possible) to avoid introducing potential artifacts. */
pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_clip_init_rectangle (&clip, rect);
if (unlikely (status))
goto CLEANUP_IMAGE;
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL);
&pattern.base, &clip);
_cairo_clip_reset (&clip);
_cairo_pattern_fini (&pattern.base);
CLEANUP_IMAGE:
@ -295,18 +296,17 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
if (surface->target->status)
if (unlikely (surface->target->status))
return surface->target->status;
analysis = _cairo_analysis_surface_create (surface->target,
surface->width, surface->height);
if (analysis->status)
analysis = _cairo_analysis_surface_create (surface->target);
if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_ANALYZE);
status = _cairo_meta_surface_replay_and_create_regions (surface->meta,
analysis);
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
analysis);
if (status || analysis->status) {
if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status;
@ -356,25 +356,28 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_RENDER);
status = _cairo_meta_surface_replay_region (surface->meta,
surface->target,
CAIRO_META_REGION_NATIVE);
status = _cairo_recording_surface_replay_region (surface->recording_surface,
surface->target,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (unlikely (status))
goto FAIL;
}
if (has_page_fallback) {
cairo_rectangle_int_t rect;
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
rect.x = 0;
rect.y = 0;
rect.width = surface->width;
rect.height = surface->height;
status = _paint_fallback_image (surface, &rect);
is_bounded = _cairo_surface_get_extents (surface->target, &extents);
if (! is_bounded) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto FAIL;
}
status = _paint_fallback_image (surface, &extents);
if (unlikely (status))
goto FAIL;
}
@ -386,15 +389,6 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
/* Reset clip region before drawing the fall back images */
status = _cairo_surface_intersect_clip_path (surface->target,
NULL,
CAIRO_FILL_RULE_WINDING,
CAIRO_GSTATE_TOLERANCE_DEFAULT,
CAIRO_ANTIALIAS_DEFAULT);
if (unlikely (status))
goto FAIL;
region = _cairo_analysis_surface_get_unsupported (analysis);
num_rects = cairo_region_num_rectangles (region);
@ -402,9 +396,7 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
status = _paint_fallback_image (surface, &rect);
if (unlikely (status))
goto FAIL;
}
@ -445,12 +437,12 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
surface->page_num++;
/* XXX: It might make sense to add some suport here for calling
/* XXX: It might make sense to add some support here for calling
* cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
* show_page and we implement the copying by simply not destroying
* the meta-surface. */
* the recording-surface. */
cairo_surface_show_page (surface->target);
return cairo_surface_status (surface->target);
@ -471,20 +463,19 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return status;
cairo_surface_show_page (surface->target);
status = cairo_surface_status (surface->target);
status = surface->target->status;
if (unlikely (status))
return status;
status = cairo_surface_status (surface->meta);
status = surface->recording_surface->status;
if (unlikely (status))
return status;
cairo_surface_destroy (surface->meta);
cairo_surface_destroy (surface->recording_surface);
surface->meta = cairo_meta_surface_create (surface->content,
surface->width,
surface->height);
status = cairo_surface_status (surface->meta);
surface->recording_surface = _create_recording_surface_for_target (surface->target,
surface->content);
status = surface->recording_surface->status;
if (unlikely (status))
return status;
@ -494,21 +485,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_paginated_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_intersect_clip_path (surface->meta,
path, fill_rule,
tolerance, antialias);
}
static cairo_int_status_t
static cairo_bool_t
_cairo_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -530,7 +507,7 @@ static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@ -540,7 +517,7 @@ _cairo_paginated_surface_paint (void *abstract_surface,
surface->page_is_blank = FALSE;
return _cairo_surface_paint (surface->meta, op, source, NULL);
return _cairo_surface_paint (surface->recording_surface, op, source, clip);
}
static cairo_int_status_t
@ -548,11 +525,17 @@ _cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_mask (surface->meta, op, source, mask, NULL);
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
}
static cairo_int_status_t
@ -565,7 +548,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@ -575,10 +558,11 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
surface->page_is_blank = FALSE;
return _cairo_surface_stroke (surface->meta, op, source,
return _cairo_surface_stroke (surface->recording_surface, op, source,
path, style,
ctm, ctm_inverse,
tolerance, antialias, NULL);
tolerance, antialias,
clip);
}
static cairo_int_status_t
@ -589,7 +573,7 @@ _cairo_paginated_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@ -599,9 +583,10 @@ _cairo_paginated_surface_fill (void *abstract_surface,
surface->page_is_blank = FALSE;
return _cairo_surface_fill (surface->meta, op, source,
return _cairo_surface_fill (surface->recording_surface, op, source,
path, fill_rule,
tolerance, antialias, NULL);
tolerance, antialias,
clip);
}
static cairo_bool_t
@ -613,21 +598,20 @@ _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
}
static cairo_int_status_t
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
@ -635,24 +619,13 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
/* Since this is a "wrapping" surface, we're calling back into
* _cairo_surface_show_text_glyphs from within a call to the same.
* Since _cairo_surface_show_text_glyphs acquires a mutex, we release
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
* adding locking code to all 18 surface-backend-specific
* show_glyphs functions, (which would get less testing and likely
* lead to bugs).
*/
status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font, NULL);
return status;
return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
}
static cairo_surface_t *
@ -660,7 +633,7 @@ _cairo_paginated_surface_snapshot (void *abstract_other)
{
cairo_paginated_surface_t *other = abstract_other;
return _cairo_surface_snapshot (other->meta);
return _cairo_surface_snapshot (other->recording_surface);
}
static const cairo_surface_backend_t cairo_paginated_surface_backend = {
@ -679,8 +652,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* check_span_renderer */
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
NULL, /* set_clip_region */
_cairo_paginated_surface_intersect_clip_path,
_cairo_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
@ -695,7 +666,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View File

@ -51,13 +51,6 @@ _cairo_path_bounder_init (cairo_path_bounder_t *bounder)
bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_fini (cairo_path_bounder_t *bounder)
{
bounder->has_initial_point = FALSE;
bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder,
const cairo_point_t *point)
@ -79,7 +72,6 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder,
bounder->extents.p1.y = point->y;
bounder->extents.p2.x = point->x;
bounder->extents.p2.y = point->y;
bounder->has_point = TRUE;
}
}
@ -173,7 +165,7 @@ _cairo_path_bounder_close_path (void *closure)
* the control points of the curves, not the flattened path).
*/
void
_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@ -195,15 +187,13 @@ _cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
/* A slightly better approximation than above - we actually decompose the
* Bezier, but we continue to ignore winding.
*/
void
_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@ -225,13 +215,37 @@ _cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
_cairo_path_bounder_fini (&bounder);
void
_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
/* Adjusts the fill extents (above) by the device-space pen. */
void
_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
@ -259,17 +273,57 @@ _cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
bounder.extents.p1.y -= _cairo_fixed_from_double (dy);
bounder.extents.p2.y += _cairo_fixed_from_double (dy);
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else if (bounder.has_initial_point) {
double dx, dy;
/* accommodate capping of degenerate paths */
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
bounder.extents.p1.x = bounder.current_point.x - _cairo_fixed_from_double (dx);
bounder.extents.p2.x = bounder.current_point.x + _cairo_fixed_from_double (dx);
bounder.extents.p1.y = bounder.current_point.y - _cairo_fixed_from_double (dy);
bounder.extents.p2.y = bounder.current_point.y + _cairo_fixed_from_double (dy);
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
_cairo_path_bounder_fini (&bounder);
cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_traps_t traps;
cairo_box_t bbox;
cairo_status_t status;
_cairo_traps_init (&traps);
status = _cairo_path_fixed_stroke_to_traps (path,
stroke_style,
ctm,
ctm_inverse,
tolerance,
&traps);
_cairo_traps_extents (&traps, &bbox);
_cairo_traps_fini (&traps);
_cairo_box_round_to_rectangle (&bbox, extents);
return status;
}
void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
@ -297,6 +351,4 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
*x2 = 0.0;
*y2 = 0.0;
}
_cairo_path_bounder_fini (&bounder);
}

View File

@ -36,32 +36,25 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
typedef struct cairo_filler {
double tolerance;
cairo_traps_t *traps;
cairo_point_t current_point;
cairo_polygon_t polygon;
cairo_polygon_t *polygon;
} cairo_filler_t;
static void
_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps)
_cairo_filler_init (cairo_filler_t *filler,
double tolerance,
cairo_polygon_t *polygon)
{
filler->tolerance = tolerance;
filler->traps = traps;
filler->current_point.x = 0;
filler->current_point.y = 0;
_cairo_polygon_init (&filler->polygon);
filler->polygon = polygon;
}
static void
_cairo_filler_fini (cairo_filler_t *filler)
{
_cairo_polygon_fini (&filler->polygon);
}
static cairo_status_t
@ -69,14 +62,10 @@ _cairo_filler_move_to (void *closure,
const cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
cairo_polygon_t *polygon = filler->polygon;
_cairo_polygon_close (polygon);
_cairo_polygon_move_to (polygon, point);
filler->current_point = *point;
return _cairo_polygon_status (&filler->polygon);
return _cairo_polygon_close (polygon) ||
_cairo_polygon_move_to (polygon, point);
}
static cairo_status_t
@ -84,13 +73,7 @@ _cairo_filler_line_to (void *closure,
const cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_line_to (polygon, point);
filler->current_point = *point;
return _cairo_polygon_status (&filler->polygon);
return _cairo_polygon_line_to (filler->polygon, point);
}
static cairo_status_t
@ -103,11 +86,10 @@ _cairo_filler_curve_to (void *closure,
cairo_spline_t spline;
if (! _cairo_spline_init (&spline,
_cairo_filler_line_to,
filler,
&filler->current_point, b, c, d))
_cairo_filler_line_to, filler,
&filler->polygon->current_point, b, c, d))
{
return CAIRO_STATUS_SUCCESS;
return _cairo_filler_line_to (closure, d);
}
return _cairo_spline_decompose (&spline, filler->tolerance);
@ -117,34 +99,18 @@ static cairo_status_t
_cairo_filler_close_path (void *closure)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_close (polygon);
return _cairo_polygon_status (polygon);
return _cairo_polygon_close (filler->polygon);
}
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
cairo_polygon_t *polygon)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
cairo_status_t status;
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_filler_init (&filler, tolerance, traps);
_cairo_filler_init (&filler, tolerance, polygon);
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
@ -154,67 +120,154 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
_cairo_filler_close_path,
&filler);
if (unlikely (status))
goto BAIL;
return status;
_cairo_polygon_close (&filler.polygon);
status = _cairo_polygon_status (&filler.polygon);
if (unlikely (status))
goto BAIL;
status = _cairo_bentley_ottmann_tessellate_polygon (filler.traps,
&filler.polygon,
fill_rule);
if (unlikely (status))
goto BAIL;
BAIL:
status = _cairo_polygon_close (polygon);
_cairo_filler_fini (&filler);
return status;
}
cairo_status_t
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
{
cairo_polygon_t polygon;
cairo_status_t status;
if (path->is_empty_fill)
return CAIRO_STATUS_SUCCESS;
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_fill_to_polygon (path,
tolerance,
&polygon);
if (unlikely (status || polygon.num_edges == 0))
goto CLEANUP;
if (path->is_rectilinear) {
status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
&polygon,
fill_rule);
} else {
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&polygon,
fill_rule);
}
CLEANUP:
_cairo_polygon_fini (&polygon);
return status;
}
static cairo_region_t *
_cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents)
{
cairo_box_t box;
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_status_t status;
cairo_region_t *region;
/* first try to bypass fill-to-polygon */
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
fill_rule,
&traps);
if (_cairo_status_is_error (status))
goto CLEANUP_TRAPS;
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_traps_extract_region (&traps, &region);
goto CLEANUP_TRAPS;
}
/* path is not rectangular, try extracting clipped rectilinear edges */
_cairo_polygon_init (&polygon);
if (extents != NULL) {
_cairo_box_from_rectangle (&box, extents);
_cairo_polygon_limit (&polygon, &box, 1);
}
/* tolerance will be ignored as the path is rectilinear */
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
if (unlikely (status))
goto CLEANUP_POLYGON;
if (polygon.num_edges == 0) {
region = cairo_region_create ();
} else {
status =
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
&polygon,
fill_rule);
if (likely (status == CAIRO_STATUS_SUCCESS))
status = _cairo_traps_extract_region (&traps, &region);
}
CLEANUP_POLYGON:
_cairo_polygon_fini (&polygon);
CLEANUP_TRAPS:
_cairo_traps_fini (&traps);
if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */
region = cairo_region_create ();
if (likely (region->status) == CAIRO_STATUS_SUCCESS)
region->status = status;
}
return region;
}
/* This special-case filler supports only a path that describes a
* device-axis aligned rectangle. It exists to avoid the overhead of
* the general tessellator when drawing very common rectangles.
*
* If the path described anything but a device-axis aligned rectangle,
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
* this function will abort.
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents)
{
cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_box_t box;
cairo_region_t *region = NULL;
assert (path->maybe_fill_region);
assert (! path->is_empty_fill);
if (_cairo_path_fixed_is_box (path, &box)) {
if (box.p1.x > box.p2.x) {
cairo_fixed_t t;
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
}
return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
rectangle_stack[0].x;
rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
rectangle_stack[0].y;
if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
region = cairo_region_create ();
else
region = cairo_region_create_rectangle (&rectangle_stack[0]);
} else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
cairo_rectangle_int_t *rects = rectangle_stack;
cairo_path_fixed_iter_t iter;
int last_cw = -1;
int size = ARRAY_LENGTH (rectangle_stack);
int count = 0;
/* Support a series of rectangles as can be expected to describe a
* GdkRegion clip region during exposes.
*/
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
cairo_status_t status;
int cw = 0;
if (box.p1.x > box.p2.x) {
@ -237,23 +290,104 @@ _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cw = ! cw;
}
if (last_cw < 0) {
if (last_cw < 0)
last_cw = cw;
} else if (last_cw != cw) {
_cairo_traps_clear (traps);
return CAIRO_INT_STATUS_UNSUPPORTED;
else if (last_cw != cw)
goto TESSELLATE;
if (count == size) {
cairo_rectangle_int_t *new_rects;
size *= 4;
if (rects == rectangle_stack) {
new_rects = _cairo_malloc_ab (size,
sizeof (cairo_rectangle_int_t));
if (unlikely (new_rects == NULL)) {
/* XXX _cairo_region_nil */
break;
}
memcpy (new_rects, rects, sizeof (rectangle_stack));
} else {
new_rects = _cairo_realloc_ab (rects, size,
sizeof (cairo_rectangle_int_t));
if (unlikely (new_rects == NULL)) {
/* XXX _cairo_region_nil */
break;
}
}
rects = new_rects;
}
rects[count].x = _cairo_fixed_integer_part (box.p1.x);
rects[count].y = _cairo_fixed_integer_part (box.p1.y);
rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
if (_cairo_rectangle_intersect (&rects[count], extents))
count++;
}
if (_cairo_path_fixed_iter_at_end (&iter))
region = cairo_region_create_rectangles (rects, count);
TESSELLATE:
if (rects != rectangle_stack)
free (rects);
}
if (region == NULL) {
/* Hmm, complex polygon */
region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
fill_rule,
extents);
}
return region;
}
cairo_int_status_t
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_box_t box;
cairo_status_t status;
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
if (_cairo_path_fixed_is_box (path, &box)) {
return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
} else {
cairo_path_fixed_iter_t iter;
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
status = _cairo_traps_tessellate_rectangle (traps,
&box.p1, &box.p2);
if (unlikely (status))
if (unlikely (status)) {
_cairo_traps_clear (traps);
return status;
}
}
if (_cairo_path_fixed_iter_at_end (&iter))
return CAIRO_STATUS_SUCCESS;
return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
_cairo_traps_clear (traps);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}

View File

@ -81,12 +81,26 @@ struct _cairo_path_fixed {
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_curve_to : 1;
unsigned int is_box : 1;
unsigned int is_region : 1;
unsigned int is_rectilinear : 1;
unsigned int maybe_fill_region : 1;
unsigned int is_empty_fill : 1;
cairo_path_buf_fixed_t buf;
};
cairo_private void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy);
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir,
cairo_fixed_t tx,
cairo_fixed_t ty);
cairo_private unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path);
@ -98,14 +112,15 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b);
typedef struct _cairo_path_fixed_iter {
cairo_path_buf_t *buf;
const cairo_path_buf_t *first;
const cairo_path_buf_t *buf;
unsigned int n_op;
unsigned int n_point;
} cairo_path_fixed_iter_t;
cairo_private void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
cairo_path_fixed_t *path);
const cairo_path_fixed_t *path);
cairo_private cairo_bool_t
_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
@ -115,13 +130,33 @@ cairo_private cairo_bool_t
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
static inline cairo_bool_t
_cairo_path_fixed_is_region (cairo_path_fixed_t *path)
_cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path)
{
return path->is_empty_fill;
}
static inline cairo_bool_t
_cairo_path_fixed_is_rectilinear_fill (const cairo_path_fixed_t *path)
{
if (! path->is_rectilinear)
return 0;
if (! path->has_current_point)
return 1;
/* check whether the implicit close preserves the rectilinear property */
return path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
}
static inline cairo_bool_t
_cairo_path_fixed_maybe_fill_region (const cairo_path_fixed_t *path)
{
#if WATCH_PATH
fprintf (stderr, "_cairo_path_fixed_is_region () = %s\n",
path->is_region ? "true" : "false");
fprintf (stderr, "_cairo_path_fixed_maybe_fill_region () = %s\n",
path->maybe_fill_region ? "true" : "false");
#endif
return path->is_region;
return path->maybe_fill_region;
}
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */

View File

@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
@ -96,25 +97,32 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->last_move_point = path->current_point;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->is_region = TRUE;
path->is_box = TRUE;
path->is_rectilinear = TRUE;
path->maybe_fill_region = TRUE;
path->is_empty_fill = TRUE;
}
cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
const cairo_path_fixed_t *other)
{
cairo_path_buf_t *buf, *other_buf;
unsigned int num_points, num_ops, buf_size;
_cairo_path_fixed_init (path);
VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
cairo_list_init (&path->buf.base.link);
path->buf.base.op = path->buf.op;
path->buf.base.points = path->buf.points;
path->current_point = other->current_point;
path->has_current_point = other->has_current_point;
path->last_move_point = other->last_move_point;
path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
path->is_box = other->is_box;
path->is_region = other->is_region;
path->is_rectilinear = other->is_rectilinear;
path->maybe_fill_region = other->maybe_fill_region;
path->is_empty_fill = other->is_empty_fill;
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
@ -214,9 +222,10 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
return TRUE;
/* use the flags to quickly differentiate based on contents */
if (a->has_curve_to != b->has_curve_to ||
a->is_region != b->is_region ||
a->is_box != b->is_box)
if (a->is_empty_fill != b->is_empty_fill ||
a->has_curve_to != b->has_curve_to ||
a->maybe_fill_region != b->maybe_fill_region ||
a->is_rectilinear != b->is_rectilinear)
{
return FALSE;
}
@ -378,15 +387,16 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
if (unlikely (status))
return status;
if (path->has_current_point && path->is_box) {
if (path->has_current_point && path->is_rectilinear) {
/* a move-to is first an implicit close */
path->is_box = path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
path->is_region &= path->is_box;
path->is_rectilinear = path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->is_region) {
path->is_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
if (path->maybe_fill_region) {
path->maybe_fill_region =
_cairo_fixed_is_integer (path->last_move_point.x) &&
_cairo_fixed_is_integer (path->last_move_point.y);
}
}
@ -433,25 +443,74 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
* explicitly calling into _cairo_path_fixed_move_to to ensure
* that the last_move_point state is updated properly.
*/
if (! path->has_current_point) {
status = _cairo_path_fixed_move_to (path, point.x, point.y);
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (path->is_box) {
path->is_box = path->current_point.x == x ||
path->current_point.y == y;
path->is_region &= path->is_box;
if (! path->has_current_point)
return _cairo_path_fixed_move_to (path, point.x, point.y);
/* If the previous op was but the initial MOVE_TO and this segment
* is degenerate, then we can simply skip this point. Note that
* a move-to followed by a degenerate line-to is a valid path for
* stroking, but at all other times is simply a degenerate segment.
*/
if (_cairo_path_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
if (x == path->current_point.x && y == path->current_point.y)
return CAIRO_STATUS_SUCCESS;
}
/* If the previous op was also a LINE_TO with the same gradient,
* then just change its end-point rather than adding a new op.
*/
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
cairo_path_buf_t *buf;
const cairo_point_t *p;
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
if (path->is_region) {
path->is_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
if (p->x == path->current_point.x && p->y == path->current_point.y) {
/* previous line element was degenerate, replace */
buf->points[buf->num_points - 1] = point;
goto FLAGS;
} else {
cairo_slope_t prev, self;
_cairo_slope_init (&prev, p, &path->current_point);
_cairo_slope_init (&self, &path->current_point, &point);
if (_cairo_slope_equal (&prev, &self) &&
/* cannot trim anti-parallel segments whilst stroking */
! _cairo_slope_backwards (&prev, &self))
{
buf->points[buf->num_points - 1] = point;
goto FLAGS;
}
}
}
path->current_point = point;
path->has_current_point = TRUE;
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (unlikely (status))
return status;
return status;
FLAGS:
if (path->is_rectilinear) {
path->is_rectilinear = path->current_point.x == x ||
path->current_point.y == y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->maybe_fill_region) {
path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
}
if (path->is_empty_fill) {
path->is_empty_fill = path->current_point.x == x &&
path->current_point.y == y;
}
path->current_point = point;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@ -483,9 +542,6 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
return status;
}
if (x2 == path->current_point.x && y2 == path->current_point.y)
return _cairo_path_fixed_line_to (path, x2, y2);
point[0].x = x0; point[0].y = y0;
point[1].x = x1; point[1].y = y1;
point[2].x = x2; point[2].y = y2;
@ -495,9 +551,10 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
path->current_point = point[2];
path->has_current_point = TRUE;
path->is_empty_fill = FALSE;
path->has_curve_to = TRUE;
path->is_box = FALSE;
path->is_region = FALSE;
path->is_rectilinear = FALSE;
path->maybe_fill_region = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@ -511,12 +568,6 @@ _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
if (unlikely (! path->has_current_point))
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
if (dx2 == 0 && dy2 == 0) {
return _cairo_path_fixed_line_to (path,
path->current_point.x,
path->current_point.y);
}
return _cairo_path_fixed_curve_to (path,
path->current_point.x + dx0,
path->current_point.y + dy0,
@ -536,6 +587,28 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path)
if (! path->has_current_point)
return CAIRO_STATUS_SUCCESS;
/* If the previous op was also a LINE_TO back to the start, discard it */
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
if (path->current_point.x == path->last_move_point.x &&
path->current_point.y == path->last_move_point.y)
{
cairo_path_buf_t *buf;
cairo_point_t *p;
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
path->current_point = *p;
buf->num_ops--;
buf->num_points--;
}
}
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
if (unlikely (status))
return status;
@ -732,49 +805,77 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
typedef struct _cairo_path_fixed_append_closure {
cairo_point_t offset;
cairo_path_fixed_t *path;
} cairo_path_fixed_append_closure_t;
static cairo_status_t
_append_move_to (void *closure,
_append_move_to (void *abstract_closure,
const cairo_point_t *point)
{
return _cairo_path_fixed_move_to (closure, point->x, point->y);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_move_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_append_line_to (void *closure,
_append_line_to (void *abstract_closure,
const cairo_point_t *point)
{
return _cairo_path_fixed_line_to (closure, point->x, point->y);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_line_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_append_curve_to (void *closure,
_append_curve_to (void *abstract_closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
return _cairo_path_fixed_curve_to (closure,
p0->x, p0->y,
p1->x, p1->y,
p2->x, p2->y);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_curve_to (closure->path,
p0->x + closure->offset.x,
p0->y + closure->offset.y,
p1->x + closure->offset.x,
p1->y + closure->offset.y,
p2->x + closure->offset.x,
p2->y + closure->offset.y);
}
static cairo_status_t
_append_close_path (void *closure)
_append_close_path (void *abstract_closure)
{
return _cairo_path_fixed_close_path (closure);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_close_path (closure->path);
}
cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir)
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir,
cairo_fixed_t tx,
cairo_fixed_t ty)
{
cairo_path_fixed_append_closure_t closure;
closure.path = path;
closure.offset.x = tx;
closure.offset.y = ty;
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
path);
&closure);
}
static void
@ -787,6 +888,13 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_path_buf_t *buf;
unsigned int i;
if (path->maybe_fill_region) {
path->maybe_fill_region = _cairo_fixed_is_integer (offx) &&
_cairo_fixed_is_integer (offy) &&
_cairo_fixed_is_integer (scalex) &&
_cairo_fixed_is_integer (scaley);
}
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
if (scalex != CAIRO_FIXED_ONE)
@ -800,6 +908,36 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
} cairo_path_foreach_buf_end (buf, path);
}
void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy)
{
cairo_path_buf_t *buf;
unsigned int i;
if (offx == 0 && offy == 0)
return;
if (path->maybe_fill_region &&
! (_cairo_fixed_is_integer (offx) && _cairo_fixed_is_integer (offy)))
{
path->maybe_fill_region = FALSE;
}
path->last_move_point.x += offx;
path->last_move_point.y += offx;
path->current_point.x += offx;
path->current_point.y += offx;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
buf->points[i].x += offx;
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
}
/**
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
@ -811,12 +949,14 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
**/
void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix)
const cairo_matrix_t *matrix)
{
cairo_path_buf_t *buf;
unsigned int i;
double dx, dy;
/* XXX current_point, last_move_to */
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
@ -827,6 +967,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
return;
}
path->maybe_fill_region = FALSE;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
@ -841,20 +982,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
}
cairo_bool_t
_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
const cairo_path_fixed_t *other)
{
cairo_path_buf_t *path_buf, *other_buf;
const cairo_path_buf_t *path_buf, *other_buf;
if (path->current_point.x != other->current_point.x ||
path->current_point.y != other->current_point.y ||
path->has_current_point != other->has_current_point ||
path->has_curve_to != other->has_curve_to ||
path->is_box != other->is_box ||
path->is_region != other->is_region ||
path->is_rectilinear != other->is_rectilinear ||
path->maybe_fill_region != other->maybe_fill_region ||
path->last_move_point.x != other->last_move_point.x ||
path->last_move_point.y != other->last_move_point.y)
{
return FALSE;
}
other_buf = cairo_path_head (other);
cairo_path_foreach_buf_start (path_buf, path) {
@ -970,29 +1113,42 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
&flattener);
}
cairo_bool_t
_cairo_path_fixed_is_empty (cairo_path_fixed_t *path)
static inline void
_canonical_box (cairo_box_t *box,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
if (cairo_path_head (path)->num_ops == 0)
return TRUE;
if (p1->x <= p2->x) {
box->p1.x = p1->x;
box->p2.x = p2->x;
} else {
box->p1.x = p2->x;
box->p2.x = p1->x;
}
return FALSE;
if (p1->y <= p2->y) {
box->p1.y = p1->y;
box->p2.y = p2->y;
} else {
box->p1.y = p2->y;
box->p2.y = p1->y;
}
}
/*
* Check whether the given path contains a single rectangle.
*/
cairo_bool_t
_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf = cairo_path_head (path);
const cairo_path_buf_t *buf = cairo_path_head (path);
if (! path->is_box)
if (! path->is_rectilinear)
return FALSE;
/* Do we have the right number of ops? */
if (buf->num_ops != 5 && buf->num_ops != 6)
if (buf->num_ops < 4 || buf->num_ops > 6)
return FALSE;
/* Check whether the ops are those that would be used for a rectangle */
@ -1004,22 +1160,25 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
return FALSE;
}
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
/* we accept an implicit close for filled paths */
if (buf->num_ops > 4) {
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
return FALSE;
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return FALSE;
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return FALSE;
}
}
if (buf->num_ops == 6) {
/* A trailing CLOSE_PATH or MOVE_TO is ok */
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
return FALSE;
if (buf->num_ops == 6) {
/* A trailing CLOSE_PATH or MOVE_TO is ok */
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
return FALSE;
}
}
/* Ok, we may have a box, if the points line up */
@ -1028,8 +1187,7 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
box->p1 = buf->points[0];
box->p2 = buf->points[2];
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
@ -1038,8 +1196,7 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
box->p1 = buf->points[0];
box->p2 = buf->points[2];
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
@ -1058,12 +1215,12 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
* </programlisting></informalexample>
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf;
const cairo_path_buf_t *buf;
if (!_cairo_path_fixed_is_box (path, box))
if (! _cairo_path_fixed_is_box (path, box))
return FALSE;
buf = cairo_path_head (path);
@ -1075,9 +1232,9 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
cairo_path_fixed_t *path)
const cairo_path_fixed_t *path)
{
iter->buf = cairo_path_head (path);
iter->first = iter->buf = cairo_path_head (path);
iter->n_op = 0;
iter->n_point = 0;
}
@ -1087,11 +1244,16 @@ _cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
{
if (++iter->n_op >= iter->buf->num_ops) {
iter->buf = cairo_path_buf_next (iter->buf);
if (iter->buf == iter->first) {
iter->buf = NULL;
return FALSE;
}
iter->n_op = 0;
iter->n_point = 0;
}
return iter->buf != NULL;
return TRUE;
}
cairo_bool_t
@ -1171,8 +1333,8 @@ _cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
points[2].x == points[3].x &&
points[3].y == points[0].y)
{
box->p1 = points[0];
box->p2 = points[2];
box->p1 = points[1];
box->p2 = points[3];
*_iter = iter;
return TRUE;
}

View File

@ -38,10 +38,10 @@
typedef struct cairo_in_fill {
double tolerance;
cairo_bool_t on_edge;
int winding;
cairo_fixed_t x, y;
cairo_bool_t on_edge;
cairo_bool_t has_current_point;
cairo_point_t current_point;
@ -54,12 +54,12 @@ _cairo_in_fill_init (cairo_in_fill_t *in_fill,
double x,
double y)
{
in_fill->on_edge = FALSE;
in_fill->winding = 0;
in_fill->tolerance = tolerance;
in_fill->x = _cairo_fixed_from_double (x);
in_fill->y = _cairo_fixed_from_double (y);
in_fill->on_edge = FALSE;
in_fill->has_current_point = FALSE;
in_fill->current_point.x = 0;
@ -142,7 +142,7 @@ _cairo_in_fill_add_edge (cairo_in_fill_t *in_fill,
return;
if ((p1->x <= in_fill->x && p2->x <= in_fill->x) ||
edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0)
edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) < 0)
{
in_fill->winding += dir;
}
@ -243,16 +243,19 @@ _cairo_in_fill_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
cairo_bool_t
_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
double y,
cairo_bool_t *is_inside)
double y)
{
cairo_in_fill_t in_fill;
cairo_status_t status;
cairo_bool_t is_inside;
if (path->is_empty_fill)
return FALSE;
_cairo_in_fill_init (&in_fill, tolerance, x, y);
@ -268,19 +271,21 @@ _cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
_cairo_in_fill_close_path (&in_fill);
if (in_fill.on_edge) {
*is_inside = TRUE;
is_inside = TRUE;
} else switch (fill_rule) {
case CAIRO_FILL_RULE_EVEN_ODD:
*is_inside = in_fill.winding & 1;
is_inside = in_fill.winding & 1;
break;
case CAIRO_FILL_RULE_WINDING:
*is_inside = in_fill.winding != 0;
is_inside = in_fill.winding != 0;
break;
default:
ASSERT_NOT_REACHED;
*is_inside = FALSE;
is_inside = FALSE;
break;
}
_cairo_in_fill_fini (&in_fill);
return is_inside;
}

File diff suppressed because it is too large Load Diff

View File

@ -129,6 +129,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->filter = CAIRO_FILTER_DEFAULT;
pattern->has_component_alpha = FALSE;
cairo_matrix_init_identity (&pattern->matrix);
}
@ -331,7 +333,7 @@ void
_cairo_pattern_fini_snapshot (cairo_pattern_t *pattern)
{
/* XXX this is quite ugly, but currently necessary to break the circular
* references with snapshot-cow and the meta-surface.
* references with snapshot-cow and the recording-surface.
* This operation remains safe only whilst _cairo_surface_snapshot() is
* not public...
*/
@ -486,7 +488,7 @@ _freed_pattern_get (freed_pool_t *pool)
i = 0;
pattern = _atomic_fetch (&pool->pool[i]);
if (pattern != NULL) {
if (likely (pattern != NULL)) {
pool->top = i;
return pattern;
}
@ -511,7 +513,9 @@ _freed_pattern_put (freed_pool_t *pool,
{
int i = pool->top;
if (_atomic_store (&pool->pool[i], pattern)) {
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], pattern)))
{
pool->top = i + 1;
return;
}
@ -547,7 +551,7 @@ cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color,
cairo_content_t content)
{
cairo_solid_pattern_t *pattern = NULL;
cairo_solid_pattern_t *pattern;
pattern =
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
@ -868,7 +872,6 @@ cairo_pattern_status (cairo_pattern_t *pattern)
{
return pattern->status;
}
slim_hidden_def (cairo_pattern_status);
/**
* cairo_pattern_destroy:
@ -1521,6 +1524,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
attr->matrix = matrix;
attr->extend = pattern->base.extend;
attr->filter = CAIRO_FILTER_NEAREST;
attr->has_component_alpha = pattern->base.has_component_alpha;
*out = &image->base;
@ -1602,9 +1606,6 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
_cairo_debug_check_image_surface_is_defined (&image->base);
status = _cairo_surface_clone_similar (dst, &image->base,
opaque ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA,
0, 0, width, height,
&clone_offset_x,
&clone_offset_y,
@ -1617,6 +1618,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
cairo_matrix_init_identity (&attr->matrix);
attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
attr->filter = CAIRO_FILTER_NEAREST;
attr->has_component_alpha = pattern->base.has_component_alpha;
return status;
}
@ -1686,10 +1688,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
pattern,
dst))
{
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (unlikely (status))
goto UNLOCK;
goto DONE;
}
@ -1698,10 +1696,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
pattern,
dst))
{
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (unlikely (status))
goto UNLOCK;
goto DONE;
}
}
@ -1717,11 +1711,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
dst))
{
/* Reuse the surface instead of evicting */
status = _cairo_surface_reset (surface);
if (unlikely (status))
goto EVICT;
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
if (unlikely (status))
goto EVICT;
@ -1738,14 +1727,21 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
if (surface == NULL) {
/* Not cached, need to create new */
surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
if (surface->status) {
if (surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto UNLOCK;
}
if (unlikely (surface->status)) {
status = surface->status;
goto UNLOCK;
}
if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
/* in the rare event of a substitute surface being returned (e.g.
* malloc failure) don't cache the fallback surface */
if (unlikely (! _cairo_surface_is_similar (surface,
dst, pattern->content)))
{
/* In the rare event of a substitute surface being returned,
* don't cache the fallback.
*/
*out = surface;
goto NOCACHE;
}
@ -1767,6 +1763,7 @@ NOCACHE:
cairo_matrix_init_identity (&attribs->matrix);
attribs->extend = CAIRO_EXTEND_REPEAT;
attribs->filter = CAIRO_FILTER_NEAREST;
attribs->has_component_alpha = pattern->base.has_component_alpha;
status = CAIRO_STATUS_SUCCESS;
@ -1853,6 +1850,9 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
{
const cairo_pattern_union_t *pattern;
if (abstract_pattern->has_component_alpha)
return FALSE;
pattern = (cairo_pattern_union_t *) abstract_pattern;
switch (pattern->base.type) {
case CAIRO_PATTERN_TYPE_SOLID:
@ -1883,13 +1883,13 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
* backends do currently (see bug #10508)
*/
static cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
double *pad_out)
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
double *pad_out)
{
double pad;
cairo_filter_t optimized_filter;
switch (pattern->base.filter) {
switch (pattern->filter) {
case CAIRO_FILTER_GOOD:
case CAIRO_FILTER_BEST:
case CAIRO_FILTER_BILINEAR:
@ -1897,7 +1897,7 @@ _cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
* not need to filter (and do not want to filter, since it
* will cause blurriness)
*/
if (_cairo_matrix_is_pixel_exact (&pattern->base.matrix)) {
if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
pad = 0.;
optimized_filter = CAIRO_FILTER_NEAREST;
} else {
@ -1907,7 +1907,7 @@ _cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
* more would be defensive...
*/
pad = 0.5;
optimized_filter = pattern->base.filter;
optimized_filter = pattern->filter;
}
break;
@ -1916,7 +1916,7 @@ _cairo_pattern_analyze_filter (const cairo_surface_pattern_t *pattern,
case CAIRO_FILTER_GAUSSIAN:
default:
pad = 0.;
optimized_filter = pattern->base.filter;
optimized_filter = pattern->filter;
break;
}
@ -1936,7 +1936,6 @@ _pixman_nearest_sample (double d)
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern,
cairo_surface_t *dst,
cairo_content_t content,
int x,
int y,
unsigned int width,
@ -1953,6 +1952,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
double pad;
cairo_bool_t is_identity;
cairo_bool_t is_empty;
cairo_bool_t is_bounded;
cairo_int_status_t status;
surface = cairo_surface_reference (pattern->surface);
@ -1960,7 +1960,8 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
is_identity = FALSE;
attr->matrix = pattern->base.matrix;
attr->extend = pattern->base.extend;
attr->filter = _cairo_pattern_analyze_filter (pattern, &pad);
attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
attr->has_component_alpha = pattern->base.has_component_alpha;
attr->x_offset = attr->y_offset = tx = ty = 0;
if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
@ -2010,11 +2011,10 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
cairo_surface_t *src;
int w, h;
status = _cairo_surface_get_extents (surface, &extents);
if (unlikely (status))
goto BAIL;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded);
status = _cairo_surface_clone_similar (dst, surface, content,
status = _cairo_surface_clone_similar (dst, surface,
extents.x, extents.y,
extents.width, extents.height,
&extents.x, &extents.y, &src);
@ -2045,8 +2045,13 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
}
cairo_surface_destroy (surface);
surface = cairo_surface_create_similar (dst, dst->content, w, h);
if (surface->status) {
surface = _cairo_surface_create_similar_solid (dst,
dst->content, w, h,
CAIRO_COLOR_TRANSPARENT,
FALSE);
if (surface == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (surface->status)) {
cairo_surface_destroy (src);
return surface->status;
}
@ -2092,10 +2097,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
attr->extend = CAIRO_EXTEND_REPEAT;
}
status = _cairo_surface_get_extents (surface, &extents);
if (unlikely (status))
goto BAIL;
/* We first transform the rectangle to the coordinate space of the
* source surface so that we only need to clone that portion of the
* surface that will be read.
@ -2118,41 +2119,43 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
sampled_area.x += tx;
sampled_area.y += ty;
if (attr->extend != CAIRO_EXTEND_REPEAT) {
/* Never acquire a larger area than the source itself */
is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
} else {
int trim = 0;
if ( _cairo_surface_get_extents (surface, &extents)) {
if (attr->extend == CAIRO_EXTEND_NONE) {
/* Never acquire a larger area than the source itself */
is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
} else {
int trim = 0;
if (sampled_area.x >= extents.x &&
sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
{
/* source is horizontally contained within extents, trim */
extents.x = sampled_area.x;
extents.width = sampled_area.width;
trim |= 0x1;
if (sampled_area.x >= extents.x &&
sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
{
/* source is horizontally contained within extents, trim */
extents.x = sampled_area.x;
extents.width = sampled_area.width;
trim |= 0x1;
}
if (sampled_area.y >= extents.y &&
sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
{
/* source is vertically contained within extents, trim */
extents.y = sampled_area.y;
extents.height = sampled_area.height;
trim |= 0x2;
}
if (trim == 0x3) {
/* source is wholly contained within extents, drop the REPEAT */
attr->extend = CAIRO_EXTEND_NONE;
}
is_empty = extents.width == 0 || extents.height == 0;
}
if (sampled_area.y >= extents.y &&
sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
{
/* source is vertically contained within extents, trim */
extents.y = sampled_area.y;
extents.height = sampled_area.height;
trim |= 0x2;
}
if (trim == 0x3) {
/* source is wholly contained within extents, drop the REPEAT */
attr->extend = CAIRO_EXTEND_NONE;
}
is_empty = extents.width == 0 || extents.height == 0;
}
/* XXX can we use is_empty? */
status = _cairo_surface_clone_similar (dst, surface, content,
status = _cairo_surface_clone_similar (dst, surface,
extents.x, extents.y,
extents.width, extents.height,
&x, &y, out);
@ -2203,6 +2206,21 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
return status;
}
static void
_init_solid_for_color_stop (cairo_solid_pattern_t *solid,
const cairo_color_t *color)
{
cairo_color_t premult;
/* Color stops aren't premultiplied, so fix that here */
_cairo_color_init_rgba (&premult,
color->red,
color->green,
color->blue,
color->alpha);
_cairo_pattern_init_solid (solid, &premult, CAIRO_CONTENT_COLOR_ALPHA);
}
/**
* _cairo_pattern_acquire_surface:
* @pattern: a #cairo_pattern_t
@ -2226,7 +2244,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
cairo_int_status_t
_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_content_t content,
int x,
int y,
unsigned int width,
@ -2237,7 +2254,7 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
{
cairo_status_t status;
if (pattern->status) {
if (unlikely (pattern->status)) {
*surface_out = NULL;
return pattern->status;
}
@ -2255,28 +2272,16 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
/* XXX The gradient->solid conversion code should now be redundant. */
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2)
{
cairo_solid_pattern_t solid;
if (src->n_stops)
{
cairo_color_t color;
/* multiply by alpha */
_cairo_color_init_rgba (&color,
src->stops->color.red,
src->stops->color.green,
src->stops->color.blue,
src->stops->color.alpha);
_cairo_pattern_init_solid (&solid,
&color,
CAIRO_CONTENT_COLOR_ALPHA);
}
else
{
if (src->n_stops) {
_init_solid_for_color_stop (&solid, &src->stops->color);
} else {
_cairo_pattern_init_solid (&solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_ALPHA);
@ -2304,18 +2309,8 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
}
if (i == src->n_stops) {
cairo_solid_pattern_t solid;
cairo_color_t color;
/* multiply by alpha */
_cairo_color_init_rgba (&color,
src->stops->color.red,
src->stops->color.green,
src->stops->color.blue,
src->stops->color.alpha);
_cairo_pattern_init_solid (&solid,
&color,
CAIRO_CONTENT_COLOR_ALPHA);
_init_solid_for_color_stop (&solid, &src->stops->color);
status =
_cairo_pattern_acquire_surface_for_solid (&solid, dst,
@ -2337,7 +2332,6 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
status = _cairo_pattern_acquire_surface_for_surface (src, dst,
content,
x, y,
width, height,
flags,
@ -2372,7 +2366,6 @@ cairo_int_status_t
_cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
cairo_content_t src_content,
int src_x,
int src_y,
int mask_x,
@ -2388,19 +2381,18 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
cairo_int_status_t status;
cairo_pattern_union_t src_tmp;
if (src->status)
if (unlikely (src->status))
return src->status;
if (mask && mask->status)
if (unlikely (mask != NULL && mask->status))
return mask->status;
/* If src and mask are both solid, then the mask alpha can be
* combined into src and mask can be ignored. */
/* XXX: This optimization assumes that there is no color
* information in mask, so this will need to change when we
* support RENDER-style 4-channel masks. */
if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
mask && mask->type == CAIRO_PATTERN_TYPE_SOLID)
mask &&
! mask->has_component_alpha &&
mask->type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_color_t combined;
cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
@ -2410,14 +2402,13 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&src_tmp.solid, &combined,
(src_solid->content | mask_solid->content) & src_content);
src_solid->content | mask_solid->content);
src = &src_tmp.base;
mask = NULL;
}
status = _cairo_pattern_acquire_surface (src, dst,
src_content,
src_x, src_y,
width, height,
flags,
@ -2431,7 +2422,6 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
}
status = _cairo_pattern_acquire_surface (mask, dst,
CAIRO_CONTENT_ALPHA,
mask_x, mask_y,
width, height,
flags,
@ -2458,79 +2448,156 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
* "infinite" extents, though it would be possible to optimize these
* with a little more work.
**/
cairo_status_t
void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
{
if (pattern->extend == CAIRO_EXTEND_NONE &&
pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
{
cairo_status_t status;
cairo_rectangle_int_t surface_extents;
const cairo_surface_pattern_t *surface_pattern =
(const cairo_surface_pattern_t *) pattern;
cairo_surface_t *surface = surface_pattern->surface;
cairo_matrix_t imatrix;
double x1, y1, x2, y2;
double pad;
cairo_matrix_t imatrix;
double x1, y1, x2, y2;
cairo_status_t status;
status = _cairo_surface_get_extents (surface, &surface_extents);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
goto UNBOUNDED;
if (unlikely (status))
return status;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
goto UNBOUNDED;
/* The filter can effectively enlarge the extents of the
* pattern, so extend as necessary.
*/
_cairo_pattern_analyze_filter (surface_pattern, &pad);
x1 = surface_extents.x - pad;
y1 = surface_extents.y - pad;
x2 = surface_extents.x + (int) surface_extents.width + pad;
y2 = surface_extents.y + (int) surface_extents.height + pad;
case CAIRO_PATTERN_TYPE_SURFACE:
{
cairo_rectangle_int_t surface_extents;
const cairo_surface_pattern_t *surface_pattern =
(const cairo_surface_pattern_t *) pattern;
cairo_surface_t *surface = surface_pattern->surface;
double pad;
imatrix = pattern->matrix;
status = cairo_matrix_invert (&imatrix);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
if (! _cairo_surface_get_extents (surface, &surface_extents))
goto UNBOUNDED;
_cairo_matrix_transform_bounding_box (&imatrix,
&x1, &y1, &x2, &y2,
NULL);
if (surface_extents.width == 0 || surface_extents.height == 0)
goto EMPTY;
x1 = floor (x1);
if (x1 < CAIRO_RECT_INT_MIN)
x1 = CAIRO_RECT_INT_MIN;
y1 = floor (y1);
if (y1 < CAIRO_RECT_INT_MIN)
y1 = CAIRO_RECT_INT_MIN;
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
x2 = ceil (x2);
if (x2 > CAIRO_RECT_INT_MAX)
x2 = CAIRO_RECT_INT_MAX;
y2 = ceil (y2);
if (y2 > CAIRO_RECT_INT_MAX)
y2 = CAIRO_RECT_INT_MAX;
/* The filter can effectively enlarge the extents of the
* pattern, so extend as necessary.
*/
_cairo_pattern_analyze_filter (&surface_pattern->base, &pad);
x1 = surface_extents.x - pad;
y1 = surface_extents.y - pad;
x2 = surface_extents.x + (int) surface_extents.width + pad;
y2 = surface_extents.y + (int) surface_extents.height + pad;
}
break;
extents->x = x1; extents->width = x2 - x1;
extents->y = y1; extents->height = y2 - y1;
case CAIRO_PATTERN_TYPE_RADIAL:
{
const cairo_radial_pattern_t *radial =
(const cairo_radial_pattern_t *) pattern;
double cx1, cy1;
double cx2, cy2;
double r, D;
return CAIRO_STATUS_SUCCESS;
if (radial->r1 == 0 && radial->r2 == 0)
goto EMPTY;
cx1 = _cairo_fixed_to_double (radial->c1.x);
cy1 = _cairo_fixed_to_double (radial->c1.y);
r = _cairo_fixed_to_double (radial->r1);
x1 = cx1 - r; x2 = cx1 + r;
y1 = cy1 - r; y2 = cy1 + r;
cx2 = _cairo_fixed_to_double (radial->c2.x);
cy2 = _cairo_fixed_to_double (radial->c2.y);
r = fabs (_cairo_fixed_to_double (radial->r2));
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
/* We need to be careful, as if the circles are not
* self-contained, then the solution is actually unbounded.
*/
D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2);
if (D > r*r - 1e-5)
goto UNBOUNDED;
if (cx2 - r < x1)
x1 = cx2 - r;
if (cx2 + r > x2)
x2 = cx2 + r;
if (cy2 - r < y1)
y1 = cy2 - r;
if (cy2 + r > y2)
y2 = cy2 + r;
}
break;
case CAIRO_PATTERN_TYPE_LINEAR:
{
const cairo_linear_pattern_t *linear =
(const cairo_linear_pattern_t *) pattern;
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
goto UNBOUNDED;
if (linear->p1.x == linear->p2.x) {
x1 = -HUGE_VAL;
x2 = HUGE_VAL;
y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
} else if (linear->p1.y == linear->p2.y) {
x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
y1 = -HUGE_VAL;
y2 = HUGE_VAL;
} else {
goto UNBOUNDED;
}
}
break;
default:
ASSERT_NOT_REACHED;
}
/* XXX: We could optimize gradients with pattern->extend of NONE
* here in some cases, (eg. radial gradients and 1 axis of
* horizontal/vertical linear gradients).
*/
imatrix = pattern->matrix;
status = cairo_matrix_invert (&imatrix);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
_cairo_matrix_transform_bounding_box (&imatrix,
&x1, &y1, &x2, &y2,
NULL);
x1 = floor (x1);
if (x1 < CAIRO_RECT_INT_MIN)
x1 = CAIRO_RECT_INT_MIN;
y1 = floor (y1);
if (y1 < CAIRO_RECT_INT_MIN)
y1 = CAIRO_RECT_INT_MIN;
x2 = ceil (x2);
if (x2 > CAIRO_RECT_INT_MAX)
x2 = CAIRO_RECT_INT_MAX;
y2 = ceil (y2);
if (y2 > CAIRO_RECT_INT_MAX)
y2 = CAIRO_RECT_INT_MAX;
extents->x = x1; extents->width = x2 - x1;
extents->y = y1; extents->height = y2 - y1;
return;
UNBOUNDED:
/* unbounded patterns -> 'infinite' extents */
extents->x = CAIRO_RECT_INT_MIN;
extents->y = CAIRO_RECT_INT_MIN;
extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
_cairo_unbounded_rectangle_init (extents);
return;
return CAIRO_STATUS_SUCCESS;
EMPTY:
extents->x = extents->y = 0;
extents->width = extents->height = 0;
return;
}
@ -2613,9 +2680,17 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
return 0;
hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
hash = _cairo_hash_bytes (hash, &pattern->matrix, sizeof (pattern->matrix));
hash = _cairo_hash_bytes (hash, &pattern->filter, sizeof (pattern->filter));
hash = _cairo_hash_bytes (hash, &pattern->extend, sizeof (pattern->extend));
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
hash = _cairo_hash_bytes (hash,
&pattern->matrix, sizeof (pattern->matrix));
hash = _cairo_hash_bytes (hash,
&pattern->filter, sizeof (pattern->filter));
hash = _cairo_hash_bytes (hash,
&pattern->extend, sizeof (pattern->extend));
hash = _cairo_hash_bytes (hash,
&pattern->has_component_alpha,
sizeof (pattern->has_component_alpha));
}
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
@ -2766,17 +2841,25 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
if (a->status || b->status)
return FALSE;
if (a == b)
return TRUE;
if (a->type != b->type)
return FALSE;
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
if (a->has_component_alpha != b->has_component_alpha)
return FALSE;
if (a->filter != b->filter)
return FALSE;
if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
return FALSE;
if (a->extend != b->extend)
return FALSE;
if (a->filter != b->filter)
return FALSE;
if (a->extend != b->extend)
return FALSE;
}
switch (a->type) {
case CAIRO_PATTERN_TYPE_SOLID:

View File

@ -48,8 +48,6 @@
#include "cairo-output-stream-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include <ctype.h>
static cairo_status_t
_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators);
@ -180,7 +178,7 @@ _count_word_up_to (const unsigned char *s, int length)
int word = 0;
while (length--) {
if (! (isspace (*s) || *s == '<')) {
if (! (_cairo_isspace (*s) || *s == '<')) {
s++;
word++;
} else {
@ -239,7 +237,7 @@ _word_wrap_stream_write (cairo_output_stream_t *base,
length--;
_cairo_output_stream_printf (stream->output, ">");
stream->column++;
} else if (isspace (*data)) {
} else if (_cairo_isspace (*data)) {
newline = (*data == '\n' || *data == '\r');
if (! newline && stream->column >= stream->max_column) {
_cairo_output_stream_printf (stream->output, "\n");

View File

@ -45,6 +45,7 @@
#include "cairo-pdf.h"
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
@ -52,7 +53,10 @@ typedef struct _cairo_pdf_resource {
unsigned int id;
} cairo_pdf_resource_t;
#define CAIRO_NUM_OPERATORS (CAIRO_OPERATOR_HSL_LUMINOSITY + 1)
typedef struct _cairo_pdf_group_resources {
cairo_bool_t operators[CAIRO_NUM_OPERATORS];
cairo_array_t alphas;
cairo_array_t smasks;
cairo_array_t patterns;
@ -171,12 +175,15 @@ struct _cairo_pdf_surface {
cairo_bool_t is_knockout;
} group_stream;
cairo_surface_clipper_t clipper;
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t select_pattern_gstate_saved;
cairo_bool_t force_fallbacks;
cairo_operator_t current_operator;
cairo_bool_t current_pattern_is_solid_color;
cairo_bool_t current_color_is_stroke;
double current_color_red;

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
static int
_cairo_pen_vertices_needed (double tolerance,
double radius,
@ -393,194 +395,3 @@ _cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
return i;
}
static int
_cairo_pen_stroke_spline_add_convolved_point (cairo_pen_stroke_spline_t *stroker,
const cairo_point_t *last_point,
const cairo_slope_t *slope,
cairo_point_t *last_hull_point,
int active,
int step)
{
do {
cairo_point_t hull_point;
hull_point.x = last_point->x + stroker->pen.vertices[active].point.x;
hull_point.y = last_point->y + stroker->pen.vertices[active].point.y;
_cairo_polygon_add_edge (&stroker->polygon,
last_hull_point, &hull_point,
step);
*last_hull_point = hull_point;
/* The strict inequalities here ensure that if a spline slope
* compares identically with either of the slopes of the
* active vertex, then it remains the active vertex. This is
* very important since otherwise we can trigger an infinite
* loop in the case of a degenerate pen, (a line), where
* neither vertex considers itself active for the slope---one
* will consider it as equal and reject, and the other will
* consider it unequal and reject. This is due to the inherent
* ambiguity when comparing slopes that differ by exactly
* pi. */
if (_cairo_slope_compare (slope,
&stroker->pen.vertices[active].slope_ccw) > 0)
{
if (++active == stroker->pen.num_vertices)
active = 0;
}
else if (_cairo_slope_compare (slope,
&stroker->pen.vertices[active].slope_cw) < 0)
{
if (--active == -1)
active = stroker->pen.num_vertices - 1;
}
else
{
return active;
}
} while (TRUE);
}
/* Compute outline of a given spline using the pen.
* The trapezoids needed to fill that outline will be added to traps
*/
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_slope_t slope;
/* If the line width is so small that the pen is reduced to a
single point, then we have nothing to do. */
if (stroker->pen.num_vertices <= 1)
return CAIRO_STATUS_SUCCESS;
/* open the polygon */
slope = stroker->spline.initial_slope;
stroker->forward_vertex =
_cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
stroker->forward_hull_point.x = stroker->last_point.x +
stroker->pen.vertices[stroker->forward_vertex].point.x;
stroker->forward_hull_point.y = stroker->last_point.y +
stroker->pen.vertices[stroker->forward_vertex].point.y;
slope.dx = -slope.dx;
slope.dy = -slope.dy;
stroker->backward_vertex =
_cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
stroker->backward_hull_point.x = stroker->last_point.x +
stroker->pen.vertices[stroker->backward_vertex].point.x;
stroker->backward_hull_point.y = stroker->last_point.y +
stroker->pen.vertices[stroker->backward_vertex].point.y;
_cairo_polygon_add_edge (&stroker->polygon,
&stroker->backward_hull_point,
&stroker->forward_hull_point,
1);
status = _cairo_spline_decompose (&stroker->spline, tolerance);
if (unlikely (status))
return status;
/* close the polygon */
slope = stroker->spline.final_slope;
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->forward_hull_point,
stroker->forward_vertex,
1);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->backward_hull_point,
stroker->backward_vertex,
-1);
_cairo_polygon_add_edge (&stroker->polygon,
&stroker->forward_hull_point,
&stroker->backward_hull_point,
1);
status = _cairo_polygon_status (&stroker->polygon);
if (unlikely (status))
return status;
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&stroker->polygon,
CAIRO_FILL_RULE_WINDING);
return status;
}
static cairo_status_t
_cairo_pen_stroke_spline_add_point (void *closure,
const cairo_point_t *point)
{
cairo_pen_stroke_spline_t *stroker = closure;
cairo_slope_t slope;
_cairo_slope_init (&slope, &stroker->last_point, point);
stroker->forward_vertex =
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->forward_hull_point,
stroker->forward_vertex,
1);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
stroker->backward_vertex =
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->backward_hull_point,
stroker->backward_vertex,
-1);
stroker->last_point = *point;
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker,
const cairo_pen_t *pen,
const cairo_point_t *a,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_int_status_t status;
if (! _cairo_spline_init (&stroker->spline,
_cairo_pen_stroke_spline_add_point,
stroker,
a, b, c, d))
{
return CAIRO_INT_STATUS_DEGENERATE;
}
status = _cairo_pen_init_copy (&stroker->pen, pen);
if (unlikely (status))
return status;
_cairo_polygon_init (&stroker->polygon);
stroker->last_point = *a;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker)
{
_cairo_polygon_fini (&stroker->polygon);
_cairo_pen_fini (&stroker->pen);
}

View File

@ -36,6 +36,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
@ -49,6 +51,39 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
polygon->has_current_point = FALSE;
polygon->has_current_edge = FALSE;
polygon->num_limits = 0;
polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;
}
void
_cairo_polygon_limit (cairo_polygon_t *polygon,
const cairo_box_t *limits,
int num_limits)
{
int n;
polygon->limits = limits;
polygon->num_limits = num_limits;
if (polygon->num_limits) {
polygon->limit = limits[0];
for (n = 1; n < num_limits; n++) {
if (limits[n].p1.x < polygon->limit.p1.x)
polygon->limit.p1.x = limits[n].p1.x;
if (limits[n].p1.y < polygon->limit.p1.y)
polygon->limit.p1.y = limits[n].p1.y;
if (limits[n].p2.x > polygon->limit.p2.x)
polygon->limit.p2.x = limits[n].p2.x;
if (limits[n].p2.y > polygon->limit.p2.y)
polygon->limit.p2.y = limits[n].p2.y;
}
}
}
void
@ -93,17 +128,16 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
return TRUE;
}
void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
int dir)
static void
_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
cairo_edge_t *edge;
/* drop horizontal edges */
if (p1->y == p2->y)
return;
assert (top < bottom);
if (polygon->num_edges == polygon->edges_size) {
if (! _cairo_polygon_grow (polygon))
@ -111,47 +145,350 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon,
}
edge = &polygon->edges[polygon->num_edges++];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
edge->dir = dir;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
edge->dir = -dir;
edge->line.p1 = *p1;
edge->line.p2 = *p2;
edge->top = top;
edge->bottom = bottom;
edge->dir = dir;
if (top < polygon->extents.p1.y)
polygon->extents.p1.y = top;
if (bottom > polygon->extents.p2.y)
polygon->extents.p2.y = bottom;
if (p1->x < polygon->extents.p1.x || p1->x > polygon->extents.p2.x) {
cairo_fixed_t x = p1->x;
if (top != p1->y)
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, top);
if (x < polygon->extents.p1.x)
polygon->extents.p1.x = x;
if (x > polygon->extents.p2.x)
polygon->extents.p2.x = x;
}
if (p2->x < polygon->extents.p1.x || p2->x > polygon->extents.p2.x) {
cairo_fixed_t x = p2->x;
if (bottom != p2->y)
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, bottom);
if (x < polygon->extents.p1.x)
polygon->extents.p1.x = x;
if (x > polygon->extents.p2.x)
polygon->extents.p2.x = x;
}
}
void
static void
_add_clipped_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
const int top, const int bottom,
const int dir)
{
cairo_point_t p[2];
int top_y, bot_y;
int n;
for (n = 0; n < polygon->num_limits; n++) {
const cairo_box_t *limits = &polygon->limits[n];
if (top >= limits->p2.y)
continue;
if (bottom <= limits->p1.y)
continue;
if (p1->x <= limits->p1.x && p2->x <= limits->p1.x)
{
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = top;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = bottom;
if (bot_y > p[1].y)
bot_y = p[1].y;
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
}
else if (p1->x >= limits->p2.x && p2->x >= limits->p2.x)
{
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = top;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = bottom;
if (bot_y > p[1].y)
bot_y = p[1].y;
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
}
else if (p1->x >= limits->p1.x && p2->x >= limits->p1.x &&
p1->x <= limits->p2.x && p2->x <= limits->p2.x)
{
top_y = top;
if (top_y < limits->p1.y)
top_y = limits->p1.y;
bot_y = bottom;
if (bot_y > limits->p2.y)
bot_y = limits->p2.y;
_add_edge (polygon, p1, p2, top_y, bot_y, dir);
}
else
{
int left_y, right_y;
int p1_y, p2_y;
left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p1.x);
right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p2.x);
if (left_y == right_y) /* horizontal within bounds */
continue;
p1_y = top;
p2_y = bottom;
if (left_y < right_y) {
if (p1->x < limits->p1.x && left_y > limits->p1.y) {
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = p1_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = left_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p1_y = bot_y;
}
if (p2->x > limits->p2.x && right_y < limits->p2.y) {
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = right_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = p2_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p2_y = top_y;
}
} else {
if (p1->x > limits->p2.x && right_y > limits->p1.y) {
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = p1_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = right_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p1_y = bot_y;
}
if (p2->x < limits->p1.x && left_y < limits->p2.y) {
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = left_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = p2_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p2_y = top_y;
}
}
if (p1_y < limits->p1.y)
p1_y = limits->p1.y;
if (p2_y > limits->p2.y)
p2_y = limits->p2.y;
if (p2_y > p1_y)
_add_edge (polygon, p1, p2, p1_y, p2_y, dir);
}
}
}
static void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
int dir;
/* drop horizontal edges */
if (p1->y == p2->y)
return;
if (p1->y < p2->y) {
dir = 1;
} else {
const cairo_point_t *t;
t = p1, p1 = p2, p2 = t;
dir = -1;
}
if (polygon->num_limits) {
if (p2->y <= polygon->limit.p1.y)
return;
if (p1->y >= polygon->limit.p2.y)
return;
_add_clipped_edge (polygon, p1, p2, p1->y, p2->y, dir);
} else
_add_edge (polygon, p1, p2, p1->y, p2->y, dir);
}
cairo_status_t
_cairo_polygon_add_external_edge (void *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
_cairo_polygon_add_edge (polygon, p1, p2);
return _cairo_polygon_status (polygon);
}
cairo_status_t
_cairo_polygon_add_line (cairo_polygon_t *polygon,
const cairo_line_t *line,
int top, int bottom,
int dir)
{
/* drop horizontal edges */
if (line->p1.y == line->p2.y)
return CAIRO_STATUS_SUCCESS;
if (bottom <= top)
return CAIRO_STATUS_SUCCESS;
if (polygon->num_limits) {
if (line->p2.y <= polygon->limit.p1.y)
return CAIRO_STATUS_SUCCESS;
if (line->p1.y >= polygon->limit.p2.y)
return CAIRO_STATUS_SUCCESS;
_add_clipped_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
} else
_add_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
return polygon->status;
}
/* flattened path operations */
cairo_status_t
_cairo_polygon_move_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (! polygon->has_current_point)
if (polygon->has_current_edge) {
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->has_current_edge = FALSE;
}
if (! polygon->has_current_point) {
polygon->first_point = *point;
polygon->has_current_point = TRUE;
}
polygon->current_point = *point;
polygon->has_current_point = TRUE;
return polygon->status;
}
void
cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (polygon->has_current_point)
_cairo_polygon_add_edge (polygon, &polygon->current_point, point, 1);
/* squash collinear edges */
if (polygon->has_current_edge) {
if (polygon->current_point.x != point->x ||
polygon->current_point.y != point->y)
{
cairo_slope_t this;
_cairo_polygon_move_to (polygon, point);
_cairo_slope_init (&this, &polygon->current_point, point);
if (_cairo_slope_equal (&polygon->current_edge, &this)) {
polygon->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->last_point = polygon->current_point;
polygon->current_edge = this;
}
} else if (polygon->has_current_point) {
if (polygon->current_point.x != point->x ||
polygon->current_point.y != point->y)
{
polygon->last_point = polygon->current_point;
_cairo_slope_init (&polygon->current_edge,
&polygon->last_point,
point);
polygon->has_current_edge = TRUE;
}
} else {
polygon->first_point = *point;
polygon->has_current_point = TRUE;
}
polygon->current_point = *point;
return polygon->status;
}
void
cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon)
{
if (polygon->has_current_point) {
_cairo_polygon_add_edge (polygon,
&polygon->current_point,
&polygon->first_point,
1);
cairo_status_t status;
if (polygon->has_current_point) {
status = _cairo_polygon_line_to (polygon, &polygon->first_point);
polygon->has_current_point = FALSE;
}
if (polygon->has_current_edge) {
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->has_current_edge = FALSE;
}
return polygon->status;
}

View File

@ -44,6 +44,7 @@
#include "cairo-ps.h"
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include <time.h>
@ -65,6 +66,7 @@ typedef struct cairo_ps_surface {
cairo_content_t content;
double width;
double height;
cairo_rectangle_int_t page_bbox;
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
cairo_matrix_t cairo_to_ps;
@ -88,6 +90,7 @@ typedef struct cairo_ps_surface {
cairo_scaled_font_subsets_t *font_subsets;
cairo_list_t document_media;
cairo_array_t dsc_header_comments;
cairo_array_t dsc_setup_comments;
cairo_array_t dsc_page_setup_comments;
@ -97,6 +100,8 @@ typedef struct cairo_ps_surface {
cairo_ps_level_t ps_level;
cairo_ps_level_t ps_level_used;
cairo_surface_clipper_t clipper;
cairo_pdf_operators_t pdf_operators;
cairo_surface_t *paginated_surface;
} cairo_ps_surface_t;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_QT_H
#define CAIRO_QT_H
#include "cairo.h"
#if CAIRO_HAS_QT_SURFACE
#if defined(__cplusplus)
class QPainter;
class QImage;
cairo_public cairo_surface_t *
cairo_qt_surface_create (QPainter *painter);
cairo_public cairo_surface_t *
cairo_qt_surface_create_with_qimage (cairo_format_t format,
int width,
int height);
cairo_public cairo_surface_t *
cairo_qt_surface_create_with_qpixmap (cairo_content_t content,
int width,
int height);
cairo_public QPainter *
cairo_qt_surface_get_qpainter (cairo_surface_t *surface);
/* XXX needs hooking to generic surface layer, my vote is for
cairo_public cairo_surface_t *
cairo_surface_map_image (cairo_surface_t *surface);
cairo_public void
cairo_surface_unmap_image (cairo_surface_t *surface, cairo_surface_t *image);
*/
cairo_public cairo_surface_t *
cairo_qt_surface_get_image (cairo_surface_t *surface);
cairo_public QImage *
cairo_qt_surface_get_qimage (cairo_surface_t *surface);
#else /* ! __cplusplus */
# warning cairo-qt only exports a C++ interface
#endif /* __cplusplus */
#else /* CAIRO_HAS_QT_SURFACE */
# error Cairo was not compiled with support for the Qt backend
#endif /* CAIRO_HAS_QT_SURFACE */
#endif /* CAIRO_QT_H */

View File

@ -345,10 +345,8 @@ static cairo_quartz_font_face_t *
_cairo_quartz_scaled_to_face (void *abstract_font)
{
cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font;
cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (&sfont->base);
if (!font_face || font_face->backend->type != CAIRO_FONT_TYPE_QUARTZ)
return NULL;
cairo_font_face_t *font_face = sfont->base.font_face;
assert (font_face->backend->type == CAIRO_FONT_TYPE_QUARTZ);
return (cairo_quartz_font_face_t*) font_face;
}

View File

@ -58,9 +58,8 @@ _cairo_quartz_image_surface_create_similar (void *asurface,
int height)
{
cairo_surface_t *result;
cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content),
width,
height);
cairo_surface_t *isurf =
_cairo_image_surface_create_with_content (content, width, height);
if (cairo_surface_status(isurf))
return isurf;
@ -108,18 +107,16 @@ _cairo_quartz_image_surface_acquire_dest_image (void *asurface,
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_quartz_image_surface_get_extents (void *asurface,
cairo_rectangle_int_t *extents)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
*extents = surface->extents;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
/* we assume some drawing happened to the image buffer; make sure it's
@ -168,8 +165,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_quartz_image_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -185,7 +180,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
NULL, /* surface_show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL /* fill_stroke */
};

View File

@ -42,6 +42,7 @@
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-quartz.h"
#include "cairo-surface-clipper-private.h"
typedef struct cairo_quartz_surface {
cairo_surface_t base;
@ -52,6 +53,7 @@ typedef struct cairo_quartz_surface {
void *imageData;
cairo_surface_t *imageSurfaceEquiv;
cairo_surface_clipper_t clipper;
cairo_rectangle_int_t extents;
/* These are stored while drawing operations are in place, set up

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,171 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
#ifndef CAIRO_RECORDING_SURFACE_H
#define CAIRO_RECORDING_SURFACE_H
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-clip-private.h"
typedef enum {
/* The 5 basic drawing operations. */
CAIRO_COMMAND_PAINT,
CAIRO_COMMAND_MASK,
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
} cairo_command_type_t;
typedef enum {
CAIRO_RECORDING_REGION_ALL,
CAIRO_RECORDING_REGION_NATIVE,
CAIRO_RECORDING_REGION_IMAGE_FALLBACK
} cairo_recording_region_type_t;
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_recording_region_type_t region;
cairo_operator_t op;
cairo_clip_t clip;
} cairo_command_header_t;
typedef struct _cairo_command_paint {
cairo_command_header_t header;
cairo_pattern_union_t source;
} cairo_command_paint_t;
typedef struct _cairo_command_mask {
cairo_command_header_t header;
cairo_pattern_union_t source;
cairo_pattern_union_t mask;
} cairo_command_mask_t;
typedef struct _cairo_command_stroke {
cairo_command_header_t header;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_stroke_style_t style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_stroke_t;
typedef struct _cairo_command_fill {
cairo_command_header_t header;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_fill_t;
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
unsigned int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_text_cluster_flags_t cluster_flags;
cairo_scaled_font_t *scaled_font;
} cairo_command_show_text_glyphs_t;
typedef union _cairo_command {
cairo_command_header_t header;
cairo_command_paint_t paint;
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_text_glyphs_t show_text_glyphs;
} cairo_command_t;
typedef struct _cairo_recording_surface {
cairo_surface_t base;
cairo_content_t content;
/* A recording-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
cairo_rectangle_t extents_pixels;
cairo_rectangle_int_t extents;
cairo_bool_t unbounded;
cairo_clip_t clip;
cairo_array_t commands;
cairo_surface_t *commands_owner;
int replay_start_idx;
} cairo_recording_surface_t;
slim_hidden_proto (cairo_recording_surface_create);
cairo_private cairo_int_status_t
_cairo_recording_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_analyze_recording_pattern (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
cairo_surface_t *target,
cairo_recording_region_type_t region);
cairo_private cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording,
cairo_box_t *bbox,
const cairo_matrix_t *transform);
cairo_private cairo_bool_t
_cairo_surface_is_recording (const cairo_surface_t *surface);
#endif /* CAIRO_RECORDING_SURFACE_H */

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,29 @@ _cairo_box_from_rectangle (cairo_box_t *box,
box->p2.y = _cairo_fixed_from_int (rect->y + rect->height);
}
void
_cairo_boxes_get_extents (const cairo_box_t *boxes,
int num_boxes,
cairo_box_t *extents)
{
int n;
assert (num_boxes > 0);
*extents = *boxes;
for (n = 1; n < num_boxes; n++) {
if (boxes[n].p1.x < extents->p1.x)
extents->p1.x = boxes[n].p1.x;
if (boxes[n].p2.x > extents->p2.x)
extents->p2.x = boxes[n].p2.x;
if (boxes[n].p1.y < extents->p1.y)
extents->p1.y = boxes[n].p1.y;
if (boxes[n].p2.y > extents->p2.y)
extents->p2.y = boxes[n].p2.y;
}
}
/* XXX We currently have a confusing mix of boxes and rectangles as
* exemplified by this function. A #cairo_box_t is a rectangular area
* represented by the coordinates of the upper left and lower right

View File

@ -1,7 +1,7 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -28,25 +28,28 @@
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Owen Taylor <otaylor@redhat.com>
* Vladimir Vukicevic <vladimir@pobox.com>
* Søren Sandmann <sandmann@daimi.au.dk>
*/
#ifndef CAIRO_REGION_PRIVATE_H
#define CAIRO_REGION_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
#include "cairo-reference-count-private.h"
#include <pixman.h>
CAIRO_BEGIN_DECLS
/* #cairo_region_t is defined in cairoint.h */
struct _cairo_region {
cairo_reference_count_t ref_count;
cairo_status_t status;
pixman_region32_t rgn;
};
@ -54,60 +57,12 @@ cairo_private void
_cairo_region_init (cairo_region_t *region);
cairo_private void
_cairo_region_init_rect (cairo_region_t *region,
cairo_rectangle_int_t *rect);
cairo_private cairo_int_status_t
_cairo_region_init_boxes (cairo_region_t *region,
cairo_box_int_t *boxes,
int count);
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
cairo_private void
_cairo_region_fini (cairo_region_t *region);
cairo_private cairo_int_status_t
_cairo_region_copy (cairo_region_t *dst,
cairo_region_t *src);
cairo_private int
_cairo_region_num_boxes (cairo_region_t *region);
cairo_private void
_cairo_region_get_box (cairo_region_t *region,
int nth_box,
cairo_box_int_t *box);
cairo_private void
_cairo_region_get_extents (cairo_region_t *region,
cairo_rectangle_int_t *extents);
cairo_private cairo_int_status_t
_cairo_region_subtract (cairo_region_t *dst,
cairo_region_t *a,
cairo_region_t *b);
cairo_private cairo_int_status_t
_cairo_region_intersect (cairo_region_t *dst,
cairo_region_t *a,
cairo_region_t *b);
cairo_private cairo_int_status_t
_cairo_region_union_rect (cairo_region_t *dst,
cairo_region_t *src,
cairo_rectangle_int_t *rect);
cairo_private cairo_bool_t
_cairo_region_not_empty (cairo_region_t *region);
cairo_private void
_cairo_region_translate (cairo_region_t *region,
int x, int y);
cairo_private pixman_region_overlap_t
_cairo_region_contains_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *box);
CAIRO_END_DECLS
#endif /* CAIRO_REGION_PRIVATE_H */

View File

@ -38,7 +38,13 @@
#include "cairoint.h"
#include "cairo-region-private.h"
/* XXX need to update pixman headers to be const as appropriate */
#define CONST_CAST (pixman_region32_t *)
static const cairo_region_t _cairo_region_nil = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
};
@ -82,6 +88,7 @@ _cairo_region_init (cairo_region_t *region)
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init (&region->rgn);
}
@ -92,6 +99,7 @@ _cairo_region_init_rectangle (cairo_region_t *region,
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
@ -100,6 +108,7 @@ _cairo_region_init_rectangle (cairo_region_t *region,
void
_cairo_region_fini (cairo_region_t *region)
{
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
pixman_region32_fini (&region->rgn);
VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
}
@ -127,6 +136,7 @@ cairo_region_create (void)
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
pixman_region32_init (&region->rgn);
@ -135,7 +145,7 @@ cairo_region_create (void)
slim_hidden_def (cairo_region_create);
cairo_region_t *
cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count)
{
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
@ -144,18 +154,17 @@ cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
int i;
region = _cairo_malloc (sizeof (cairo_region_t));
if (!region)
return (cairo_region_t *)&_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
if (unlikely (region == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
if (unlikely (pboxes == NULL)) {
free (region);
return (cairo_region_t *)&_cairo_region_nil;
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
}
@ -166,15 +175,19 @@ cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
pboxes[i].y2 = rects[i].y + rects[i].height;
}
if (! pixman_region32_init_rects (&region->rgn, pboxes, count)) {
free (region);
region = (cairo_region_t *)&_cairo_region_nil;
}
i = pixman_region32_init_rects (&region->rgn, pboxes, count);
if (pboxes != stack_pboxes)
free (pboxes);
if (unlikely (i == 0)) {
free (region);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
region->status = CAIRO_STATUS_SUCCESS;
return region;
}
slim_hidden_def (cairo_region_create_rectangles);
@ -199,10 +212,11 @@ cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
cairo_region_t *region;
region = _cairo_malloc (sizeof (cairo_region_t));
if (region == NULL)
if (unlikely (region == NULL))
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
@ -227,18 +241,20 @@ slim_hidden_def (cairo_region_create_rectangle);
* Since: 1.10
**/
cairo_region_t *
cairo_region_copy (cairo_region_t *original)
cairo_region_copy (const cairo_region_t *original)
{
cairo_region_t *copy;
if (original->status)
if (original != NULL && original->status)
return (cairo_region_t *) &_cairo_region_nil;
copy = cairo_region_create ();
if (copy->status)
if (unlikely (copy->status))
return copy;
if (! pixman_region32_copy (&copy->rgn, &original->rgn)) {
if (original != NULL &&
! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
{
cairo_region_destroy (copy);
return (cairo_region_t *) &_cairo_region_nil;
}
@ -247,6 +263,31 @@ cairo_region_copy (cairo_region_t *original)
}
slim_hidden_def (cairo_region_copy);
/**
* cairo_region_reference:
* @region: a #cairo_region_t
*
* Increases the reference count on @region by one. This prevents
* @region from being destroyed until a matching call to
* cairo_region_destroy() is made.
*
* Return value: the referenced #cairo_region_t.
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_reference (cairo_region_t *region)
{
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
_cairo_reference_count_inc (&region->ref_count);
return region;
}
slim_hidden_def (cairo_region_reference);
/**
* cairo_region_destroy:
* @region: a #cairo_region_t
@ -260,10 +301,15 @@ slim_hidden_def (cairo_region_copy);
void
cairo_region_destroy (cairo_region_t *region)
{
if (region == (cairo_region_t *) &_cairo_region_nil)
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return;
pixman_region32_fini (&region->rgn);
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
if (! _cairo_reference_count_dec_and_test (&region->ref_count))
return;
_cairo_region_fini (region);
free (region);
}
slim_hidden_def (cairo_region_destroy);
@ -279,12 +325,12 @@ slim_hidden_def (cairo_region_destroy);
* Since: 1.10
**/
int
cairo_region_num_rectangles (cairo_region_t *region)
cairo_region_num_rectangles (const cairo_region_t *region)
{
if (region->status)
return 0;
return pixman_region32_n_rects (&region->rgn);
return pixman_region32_n_rects (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_num_rectangles);
@ -299,7 +345,7 @@ slim_hidden_def (cairo_region_num_rectangles);
* Since: 1.10
**/
void
cairo_region_get_rectangle (cairo_region_t *region,
cairo_region_get_rectangle (const cairo_region_t *region,
int nth,
cairo_rectangle_int_t *rectangle)
{
@ -311,7 +357,7 @@ cairo_region_get_rectangle (cairo_region_t *region,
return;
}
pbox = pixman_region32_rectangles (&region->rgn, NULL) + nth;
pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
rectangle->x = pbox->x1;
rectangle->y = pbox->y1;
@ -330,7 +376,7 @@ slim_hidden_def (cairo_region_get_rectangle);
* Since: 1.10
**/
void
cairo_region_get_extents (cairo_region_t *region,
cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents)
{
pixman_box32_t *pextents;
@ -341,7 +387,7 @@ cairo_region_get_extents (cairo_region_t *region,
return;
}
pextents = pixman_region32_extents (&region->rgn);
pextents = pixman_region32_extents (CONST_CAST &region->rgn);
extents->x = pextents->x1;
extents->y = pextents->y1;
@ -362,7 +408,7 @@ slim_hidden_def (cairo_region_get_extents);
* Since: 1.10
**/
cairo_status_t
cairo_region_status (cairo_region_t *region)
cairo_region_status (const cairo_region_t *region)
{
return region->status;
}
@ -380,7 +426,7 @@ slim_hidden_def (cairo_region_status);
* Since: 1.10
**/
cairo_status_t
cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other)
cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
{
if (dst->status)
return dst->status;
@ -388,8 +434,12 @@ cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other)
if (other->status)
return _cairo_region_set_error (dst, other->status);
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &other->rgn))
if (! pixman_region32_subtract (&dst->rgn,
&dst->rgn,
CONST_CAST &other->rgn))
{
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
}
return CAIRO_STATUS_SUCCESS;
}
@ -564,12 +614,12 @@ slim_hidden_def (cairo_region_union_rectangle);
* Since: 1.10
**/
cairo_bool_t
cairo_region_is_empty (cairo_region_t *region)
cairo_region_is_empty (const cairo_region_t *region)
{
if (region->status)
return TRUE;
return ! pixman_region32_not_empty (&region->rgn);
return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_is_empty);
@ -610,7 +660,7 @@ slim_hidden_def (cairo_region_translate);
* Since: 1.10
**/
cairo_region_overlap_t
cairo_region_contains_rectangle (cairo_region_t *region,
cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
pixman_box32_t pbox;
@ -624,7 +674,8 @@ cairo_region_contains_rectangle (cairo_region_t *region,
pbox.x2 = rectangle->x + rectangle->width;
pbox.y2 = rectangle->y + rectangle->height;
poverlap = pixman_region32_contains_rectangle (&region->rgn, &pbox);
poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
&pbox);
switch (poverlap) {
default:
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
@ -647,14 +698,44 @@ slim_hidden_def (cairo_region_contains_rectangle);
* Since: 1.10
**/
cairo_bool_t
cairo_region_contains_point (cairo_region_t *region,
cairo_region_contains_point (const cairo_region_t *region,
int x, int y)
{
pixman_box32_t box;
if (region->status)
return FALSE;
return pixman_region32_contains_point (&region->rgn, x, y, &box);
return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
}
slim_hidden_def (cairo_region_contains_point);
/**
* cairo_region_equal:
* @region_a: a #cairo_region_t
* @region_b: a #cairo_region_t
*
* Compares whether region_a is equivalent to region_b.
*
* Return value: %TRUE if both regions contained the same coverage,
* %FALSE if it is not.
*
* Since: 1.10
**/
cairo_bool_t
cairo_region_equal (const cairo_region_t *a,
const cairo_region_t *b)
{
/* error objects are never equal */
if ((a != NULL && a->status) || (b != NULL && b->status))
return FALSE;
if (a == b)
return TRUE;
if (a == NULL || b == NULL)
return FALSE;
return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
}
slim_hidden_def (cairo_region_equal);

View File

@ -0,0 +1,128 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*
*/
#ifndef CAIRO_RTREE_PRIVATE_H
#define CAIRO_RTREE_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
#include "cairo-freelist-private.h"
#include "cairo-list-private.h"
enum {
CAIRO_RTREE_NODE_AVAILABLE,
CAIRO_RTREE_NODE_DIVIDED,
CAIRO_RTREE_NODE_OCCUPIED,
};
typedef struct _cairo_rtree_node {
struct _cairo_rtree_node *children[4], *parent;
void **owner;
cairo_list_t link;
uint16_t pinned;
uint16_t state;
uint16_t x, y;
uint16_t width, height;
} cairo_rtree_node_t;
typedef struct _cairo_rtree {
cairo_rtree_node_t root;
int min_size;
void (*evict) (void *node);
cairo_list_t pinned;
cairo_list_t available;
cairo_list_t evictable;
cairo_freepool_t node_freepool;
} cairo_rtree_t;
cairo_private cairo_rtree_node_t *
_cairo_rtree_node_create (cairo_rtree_t *rtree,
cairo_rtree_node_t *parent,
int x,
int y,
int width,
int height);
cairo_private cairo_status_t
_cairo_rtree_node_insert (cairo_rtree_t *rtree,
cairo_rtree_node_t *node,
int width,
int height,
cairo_rtree_node_t **out);
cairo_private void
_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
cairo_private void
_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
cairo_private void
_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
cairo_private void
_cairo_rtree_init (cairo_rtree_t *rtree,
int width,
int height,
int min_size,
int node_size,
void (*evict) (void *node));
cairo_private cairo_int_status_t
_cairo_rtree_insert (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out);
cairo_private cairo_int_status_t
_cairo_rtree_evict_random (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out);
cairo_private void *
_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
cairo_private void
_cairo_rtree_unpin (cairo_rtree_t *rtree);
cairo_private void
_cairo_rtree_reset (cairo_rtree_t *rtree);
cairo_private void
_cairo_rtree_fini (cairo_rtree_t *rtree);
#endif /* CAIRO_RTREE_PRIVATE_H */

View File

@ -0,0 +1,408 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*
*/
#include "cairoint.h"
#include "cairo-rtree-private.h"
cairo_rtree_node_t *
_cairo_rtree_node_create (cairo_rtree_t *rtree,
cairo_rtree_node_t *parent,
int x,
int y,
int width,
int height)
{
cairo_rtree_node_t *node;
node = _cairo_freepool_alloc (&rtree->node_freepool);
if (node == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
node->children[0] = NULL;
node->parent = parent;
node->owner = NULL;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
node->pinned = FALSE;
node->x = x;
node->y = y;
node->width = width;
node->height = height;
cairo_list_add (&node->link, &rtree->available);
return node;
}
void
_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
int i;
cairo_list_del (&node->link);
if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
if (node->owner != NULL)
*node->owner = NULL;
if (rtree->evict != NULL)
rtree->evict (node);
} else {
for (i = 0; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
}
_cairo_freepool_free (&rtree->node_freepool, node);
}
void
_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
int i;
assert (node->pinned == FALSE);
do {
assert (node->state == CAIRO_RTREE_NODE_DIVIDED);
for (i = 0; i < 4 && node->children[i] != NULL; i++)
if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE)
return;
for (i = 0; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
node->children[0] = NULL;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
node = node->parent;
} while (node != NULL && ! node->pinned);
}
cairo_status_t
_cairo_rtree_node_insert (cairo_rtree_t *rtree,
cairo_rtree_node_t *node,
int width,
int height,
cairo_rtree_node_t **out)
{
int w, h, i;
assert (node->state == CAIRO_RTREE_NODE_AVAILABLE);
assert (node->pinned == FALSE);
if (node->width - width > rtree->min_size ||
node->height - height > rtree->min_size)
{
w = node->width - width;
h = node->height - height;
i = 0;
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x, node->y,
width, height);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
if (w > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x + width,
node->y,
w, height);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
}
if (h > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x,
node->y + height,
width, h);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
if (w > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x + width,
node->y + height,
w, h);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
}
}
if (i < 4)
node->children[i] = NULL;
node->state = CAIRO_RTREE_NODE_DIVIDED;
cairo_list_move (&node->link, &rtree->evictable);
node = node->children[0];
}
node->state = CAIRO_RTREE_NODE_OCCUPIED;
cairo_list_move (&node->link, &rtree->evictable);
*out = node;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
assert (node->state == CAIRO_RTREE_NODE_OCCUPIED);
assert (node->pinned == FALSE);
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
if (! node->parent->pinned)
_cairo_rtree_node_collapse (rtree, node->parent);
}
cairo_int_status_t
_cairo_rtree_insert (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out)
{
cairo_rtree_node_t *node;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->available, link)
{
if (node->width >= width && node->height >= height)
return _cairo_rtree_node_insert (rtree, node, width, height, out);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static uint32_t
hars_petruska_f54_1_random (void)
{
#define rol(x,k) ((x << k) | (x >> (32-k)))
static uint32_t x;
return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
#undef rol
}
cairo_int_status_t
_cairo_rtree_evict_random (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out)
{
cairo_rtree_node_t *node;
int i, cnt;
cnt = 0;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->evictable, link)
{
if (node->width >= width && node->height >= height)
cnt++;
}
if (cnt == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
cnt = hars_petruska_f54_1_random () % cnt;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->evictable, link)
{
if (node->width >= width && node->height >= height && cnt-- == 0) {
if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
if (node->owner != NULL)
*node->owner = NULL;
if (rtree->evict != NULL)
rtree->evict (node);
} else {
for (i = 0; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
node->children[0] = NULL;
}
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
*out = node;
return CAIRO_STATUS_SUCCESS;
}
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}
void *
_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
void *ptr = node;
while (node->pinned == FALSE) {
cairo_list_move (&node->link, &rtree->pinned);
node->pinned = TRUE;
node = node->parent;
if (node == NULL)
break;
}
return ptr;
}
void
_cairo_rtree_unpin (cairo_rtree_t *rtree)
{
cairo_rtree_node_t *node, *next;
cairo_list_t can_collapse;
if (cairo_list_is_empty (&rtree->pinned))
return;
cairo_list_init (&can_collapse);
cairo_list_foreach_entry_safe (node, next,
cairo_rtree_node_t,
&rtree->pinned,
link)
{
node->pinned = FALSE;
if (node->state == CAIRO_RTREE_NODE_OCCUPIED && node->owner == NULL) {
cairo_bool_t all_available;
int i;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
all_available = TRUE;
node = node->parent;
for (i = 0; i < 4 && node->children[i] != NULL && all_available; i++)
all_available &= node->children[i]->state == CAIRO_RTREE_NODE_AVAILABLE;
if (all_available) {
cairo_list_move (&node->link, &can_collapse);
for (i = 0; i < 4 && node->children[i] != NULL; i++)
cairo_list_del (&node->children[i]->link);
}
}
else
{
cairo_list_move (&node->link, &rtree->evictable);
}
}
cairo_list_foreach_entry_safe (node, next,
cairo_rtree_node_t,
&can_collapse,
link)
{
_cairo_rtree_node_collapse (rtree, node);
}
}
void
_cairo_rtree_init (cairo_rtree_t *rtree,
int width,
int height,
int min_size,
int node_size,
void (*evict) (void *node))
{
rtree->evict = evict;
assert (node_size >= (int) sizeof (cairo_rtree_node_t));
_cairo_freepool_init (&rtree->node_freepool, node_size);
cairo_list_init (&rtree->available);
cairo_list_init (&rtree->pinned);
cairo_list_init (&rtree->evictable);
rtree->min_size = min_size;
memset (&rtree->root, 0, sizeof (rtree->root));
rtree->root.width = width;
rtree->root.height = height;
rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_add (&rtree->root.link, &rtree->available);
}
void
_cairo_rtree_reset (cairo_rtree_t *rtree)
{
int i;
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
if (rtree->root.owner != NULL)
*rtree->root.owner = NULL;
if (rtree->evict != NULL)
rtree->evict (&rtree->root);
} else {
for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
rtree->root.children[0] = NULL;
}
cairo_list_init (&rtree->available);
cairo_list_init (&rtree->evictable);
cairo_list_init (&rtree->pinned);
rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
rtree->root.pinned = FALSE;
cairo_list_add (&rtree->root.link, &rtree->available);
}
void
_cairo_rtree_fini (cairo_rtree_t *rtree)
{
int i;
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
if (rtree->root.owner != NULL)
*rtree->root.owner = NULL;
if (rtree->evict != NULL)
rtree->evict (&rtree->root);
} else {
for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
}
_cairo_freepool_fini (&rtree->node_freepool);
}

View File

@ -123,4 +123,7 @@ struct _cairo_scaled_font {
const cairo_scaled_font_backend_t *backend;
};
cairo_private void
_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font);
#endif /* CAIRO_SCALED_FONT_PRIVATE_H */

View File

@ -294,7 +294,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
/* Reserve first glyph in subset for the .notdef glyph except for
* Type 3 fonts */
if (! _cairo_font_face_is_user (scaled_font->font_face)) {
if (! is_scaled) {
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
if (unlikely (status)) {
_cairo_hash_table_destroy (sub_font->sub_font_glyphs);
@ -570,6 +570,7 @@ _cairo_sub_font_collect (void *entry, void *closure)
subset.scaled_font = sub_font->scaled_font;
subset.is_composite = sub_font->is_composite;
subset.is_scaled = sub_font->is_scaled;
subset.font_id = sub_font->font_id;
subset.subset_id = i;
subset.glyphs = collection->glyphs;
@ -1008,7 +1009,7 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
}
i = 0;
if (! _cairo_font_face_is_user (subset->scaled_font->font_face)) {
if (! subset->is_scaled) {
subset->glyph_names[0] = strdup (".notdef");
if (unlikely (subset->glyph_names[0] == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);

View File

@ -199,8 +199,8 @@ _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (scaled_glyph->meta_surface);
if (scaled_glyph->recording_surface != NULL)
cairo_surface_destroy (scaled_glyph->recording_surface);
}
#define ZOMBIE 0
@ -838,6 +838,22 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
_cairo_user_data_array_fini (&scaled_font->user_data);
}
/* XXX: allow multiple backends to share the font */
void
_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font)
{
if (scaled_font->surface_backend == NULL)
return;
_cairo_scaled_font_reset_cache (scaled_font);
if (scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
scaled_font->surface_backend = NULL;
scaled_font->surface_private = NULL;
}
void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
@ -931,6 +947,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
ctm,
options);
}
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
}
else
{
@ -998,6 +1017,8 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_map_unlock ();
cairo_scaled_font_destroy (old);
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
return scaled_font;
}
@ -1015,12 +1036,18 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
/* Did we leave the backend in an error state? */
if (unlikely (status)) {
_cairo_scaled_font_map_unlock ();
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
status = _cairo_font_face_set_error (font_face, status);
return _cairo_scaled_font_create_in_error (status);
}
/* Or did we encounter an error whilst constructing the scaled font? */
if (unlikely (scaled_font->status)) {
_cairo_scaled_font_map_unlock ();
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
return scaled_font;
}
@ -1033,7 +1060,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
scaled_font->original_font_face =
cairo_font_face_reference (original_font_face);
assert (scaled_font->hash_entry.hash == key.hash_entry.hash);
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
@ -1044,6 +1070,10 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_map_unlock ();
cairo_scaled_font_destroy (old);
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
if (unlikely (status)) {
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
@ -1053,11 +1083,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
return _cairo_scaled_font_create_in_error (status);
}
cairo_scaled_font_destroy (old);
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_create);
@ -1428,22 +1453,22 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
extents->x_advance = 0.0;
extents->y_advance = 0.0;
if (scaled_font->status)
return;
if (unlikely (scaled_font->status))
goto ZERO_EXTENTS;
if (num_glyphs == 0)
return;
goto ZERO_EXTENTS;
if (num_glyphs < 0) {
if (unlikely (num_glyphs < 0)) {
_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
/* XXX Can't propagate error */
return;
goto ZERO_EXTENTS;
}
if (glyphs == NULL) {
if (unlikely (glyphs == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
/* XXX Can't propagate error */
return;
goto ZERO_EXTENTS;
}
_cairo_scaled_font_freeze_cache (scaled_font);
@ -1514,6 +1539,15 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
UNLOCK:
_cairo_scaled_font_thaw_cache (scaled_font);
return;
ZERO_EXTENTS:
extents->x_bearing = 0.0;
extents->y_bearing = 0.0;
extents->width = 0.0;
extents->height = 0.0;
extents->x_advance = 0.0;
extents->y_advance = 0.0;
}
slim_hidden_def (cairo_scaled_font_glyph_extents);
@ -1578,11 +1612,11 @@ slim_hidden_def (cairo_scaled_font_glyph_extents);
* if (status == CAIRO_STATUS_SUCCESS) {
* cairo_show_text_glyphs (cr,
* utf8, utf8_len,
* *glyphs, *num_glyphs,
* *clusters, *num_clusters, *cluster_flags);
* glyphs, num_glyphs,
* clusters, num_clusters, cluster_flags);
*
* cairo_glyph_free (*glyphs);
* cairo_text_cluster_free (*clusters);
* cairo_glyph_free (glyphs);
* cairo_text_cluster_free (clusters);
* }
* </programlisting></informalexample>
*
@ -1601,8 +1635,8 @@ slim_hidden_def (cairo_scaled_font_glyph_extents);
* NULL);
*
* if (status == CAIRO_STATUS_SUCCESS) {
* cairo_show_glyphs (cr, *glyphs, *num_glyphs);
* cairo_glyph_free (*glyphs);
* cairo_show_glyphs (cr, glyphs, num_glyphs);
* cairo_glyph_free (glyphs);
* }
* </programlisting></informalexample>
*
@ -1628,13 +1662,13 @@ slim_hidden_def (cairo_scaled_font_glyph_extents);
* if (status == CAIRO_STATUS_SUCCESS) {
* cairo_show_text_glyphs (cr,
* utf8, utf8_len,
* *glyphs, *num_glyphs,
* *clusters, *num_clusters, *cluster_flags);
* glyphs, num_glyphs,
* clusters, num_clusters, cluster_flags);
*
* if (glyphs != stack_glyphs)
* cairo_glyph_free (*glyphs);
* cairo_glyph_free (glyphs);
* if (clusters != stack_clusters)
* cairo_text_cluster_free (*clusters);
* cairo_text_cluster_free (clusters);
* }
* </programlisting></informalexample>
*
@ -1893,6 +1927,15 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
}
slim_hidden_def (cairo_scaled_font_text_to_glyphs);
static inline cairo_bool_t
_range_contains_glyph (const cairo_point_int_t *min,
const cairo_point_int_t *max,
int left, int top,
int right, int bottom)
{
return right > min->x && left < max->x && bottom > min->y && top < max->y;
}
/*
* Compute a device-space bounding box for the glyphs.
*/
@ -1900,13 +1943,15 @@ cairo_status_t
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_rectangle_int_t *extents)
cairo_rectangle_int_t *extents,
cairo_bool_t *overlap_out)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
int i;
cairo_point_int_t min = { CAIRO_RECT_INT_MAX, CAIRO_RECT_INT_MAX };
cairo_point_int_t max = { CAIRO_RECT_INT_MIN, CAIRO_RECT_INT_MIN };
cairo_scaled_glyph_t *glyph_cache[64];
cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
int i;
if (unlikely (scaled_font->status))
return scaled_font->status;
@ -1945,6 +1990,11 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
right = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
bottom = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
if (overlap == FALSE) {
overlap = _range_contains_glyph (&min, &max,
left, top, right, bottom);
}
if (left < min.x) min.x = left;
if (right > max.x) max.x = right;
if (top < min.y) min.y = top;
@ -1965,22 +2015,62 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
extents->width = extents->height = 0;
}
if (overlap_out != NULL)
*overlap_out = overlap;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_rectangle_int_t *extents)
{
double x0 = HUGE_VAL, x1 = -HUGE_VAL;
double y0 = HUGE_VAL, y1 = -HUGE_VAL;
int i;
for (i = 0; i < num_glyphs; i++) {
double g;
g = glyphs[i].x;
if (g < x0) x0 = g;
if (g > x1) x1 = g;
g = glyphs[i].y;
if (g < y0) y0 = g;
if (g > y1) y1 = g;
}
if (x0 <= x1 && y0 <= y1) {
extents->x = floor (x0 - scaled_font->extents.max_x_advance);
extents->width = ceil (x1 + scaled_font->extents.max_x_advance);
extents->width -= extents->x;
extents->y = floor (y0 - scaled_font->extents.ascent);
extents->height = ceil (y1 + scaled_font->extents.descent);
extents->height -= extents->y;
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
}
cairo_status_t
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs)
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_surface_t *mask = NULL;
@ -2008,7 +2098,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs, &remaining_glyphs);
glyphs, num_glyphs,
clip_region,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@ -2025,7 +2117,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
for (i = 0; i < num_glyphs; i++) {
int x, y;
cairo_surface_pattern_t glyph_pattern;
cairo_image_surface_t *glyph_surface;
cairo_scaled_glyph_t *scaled_glyph;
@ -2043,8 +2134,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
* glyph. Later we'll deal with different formats. */
if (mask == NULL) {
mask_format = glyph_surface->format;
mask = cairo_image_surface_create (mask_format,
width, height);
mask = cairo_image_surface_create (mask_format, width, height);
status = mask->status;
if (unlikely (status))
goto CLEANUP_MASK;
@ -2071,24 +2161,26 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
break;
}
new_mask = cairo_image_surface_create (mask_format,
width, height);
if (new_mask->status) {
status = new_mask->status;
new_mask = cairo_image_surface_create (mask_format, width, height);
status = new_mask->status;
if (unlikely (status)) {
cairo_surface_destroy (new_mask);
goto CLEANUP_MASK;
}
_cairo_pattern_init_for_surface (&mask_pattern, mask);
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
/* Note that we only upgrade masks, i.e. A1 -> A8 -> ARGB32, so there is
* never any component alpha here.
*/
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
&white_pattern.base,
&mask_pattern.base,
new_mask,
0, 0,
0, 0,
0, 0,
width, height);
width, height,
NULL);
_cairo_pattern_fini (&mask_pattern.base);
@ -2101,40 +2193,50 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
mask = new_mask;
}
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
x = _cairo_lround (glyphs[i].x - glyph_surface->base.device_transform.x0);
y = _cairo_lround (glyphs[i].y - glyph_surface->base.device_transform.y0);
if (glyph_surface->width && glyph_surface->height) {
cairo_surface_pattern_t glyph_pattern;
_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
/* round glyph locations to the nearest pixel */
/* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
x = _cairo_lround (glyphs[i].x -
glyph_surface->base.device_transform.x0);
y = _cairo_lround (glyphs[i].y -
glyph_surface->base.device_transform.y0);
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
&white_pattern.base,
&glyph_pattern.base,
mask,
0, 0,
0, 0,
x - dest_x, y - dest_y,
glyph_surface->width,
glyph_surface->height);
_cairo_pattern_init_for_surface (&glyph_pattern,
&glyph_surface->base);
if (mask_format == CAIRO_FORMAT_ARGB32)
glyph_pattern.base.has_component_alpha = TRUE;
_cairo_pattern_fini (&glyph_pattern.base);
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
&white_pattern.base,
&glyph_pattern.base,
mask,
0, 0,
0, 0,
x - dest_x, y - dest_y,
glyph_surface->width,
glyph_surface->height,
NULL);
if (unlikely (status))
goto CLEANUP_MASK;
_cairo_pattern_fini (&glyph_pattern.base);
if (unlikely (status))
goto CLEANUP_MASK;
}
}
if (mask_format == CAIRO_FORMAT_ARGB32)
pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
pixman_image, TRUE);
_cairo_pattern_init_for_surface (&mask_pattern, mask);
if (mask_format == CAIRO_FORMAT_ARGB32)
mask_pattern.base.has_component_alpha = TRUE;
status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
surface,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height);
width, height,
clip_region);
_cairo_pattern_fini (&mask_pattern.base);
@ -2148,67 +2250,15 @@ CLEANUP_MASK:
return _cairo_scaled_font_set_error (scaled_font, status);
}
typedef struct _cairo_scaled_glyph_path_closure {
cairo_point_t offset;
cairo_path_fixed_t *path;
} cairo_scaled_glyph_path_closure_t;
static cairo_status_t
_scaled_glyph_path_move_to (void *abstract_closure,
const cairo_point_t *point)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_move_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_line_to (void *abstract_closure,
const cairo_point_t *point)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_line_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_curve_to (void *abstract_closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_curve_to (closure->path,
p0->x + closure->offset.x,
p0->y + closure->offset.y,
p1->x + closure->offset.x,
p1->y + closure->offset.y,
p2->x + closure->offset.x,
p2->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_close_path (void *abstract_closure)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_close_path (closure->path);
}
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
_add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
_add_unit_rectangle_to_path (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y)
{
cairo_status_t status;
status = _cairo_path_fixed_move_to (path,
_cairo_fixed_from_int (x),
_cairo_fixed_from_int (y));
status = _cairo_path_fixed_move_to (path, x, y);
if (unlikely (status))
return status;
@ -2230,11 +2280,7 @@ _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
if (unlikely (status))
return status;
status = _cairo_path_fixed_close_path (path);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
return _cairo_path_fixed_close_path (path);
}
/**
@ -2256,12 +2302,15 @@ _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
**/
static cairo_status_t
_trace_mask_to_path (cairo_image_surface_t *mask,
cairo_path_fixed_t *path)
cairo_path_fixed_t *path,
double tx, double ty)
{
const uint8_t *row;
int rows, cols, bytes_per_row;
int x, y, bit;
double xoff, yoff;
cairo_fixed_t x0, y0;
cairo_fixed_t px, py;
cairo_status_t status;
mask = _cairo_image_surface_coerce (mask, CAIRO_FORMAT_A1);
@ -2270,12 +2319,15 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
return status;
cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
x0 = _cairo_fixed_from_double (tx - xoff);
y0 = _cairo_fixed_from_double (ty - yoff);
bytes_per_row = (mask->width + 7) / 8;
row = mask->data;
for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
const uint8_t *byte_ptr = row;
x = 0;
py = _cairo_fixed_from_int (y);
for (cols = bytes_per_row; cols--; ) {
uint8_t byte = *byte_ptr++;
if (byte == 0) {
@ -2286,8 +2338,10 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
if (byte & bit) {
px = _cairo_fixed_from_int (x);
status = _add_unit_rectangle_to_path (path,
x - xoff, y - yoff);
px + x0,
py + y0);
if (unlikely (status))
goto BAIL;
}
@ -2309,14 +2363,11 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
{
cairo_status_t status;
int i;
cairo_scaled_glyph_path_closure_t closure;
cairo_path_fixed_t *glyph_path;
status = scaled_font->status;
if (unlikely (status))
return status;
closure.path = path;
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
@ -2325,14 +2376,16 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
if (status == CAIRO_STATUS_SUCCESS)
glyph_path = scaled_glyph->path;
else if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto BAIL;
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_path_fixed_append (path,
scaled_glyph->path, CAIRO_DIRECTION_FORWARD,
_cairo_fixed_from_double (glyphs[i].x),
_cairo_fixed_from_double (glyphs[i].y));
/* If the font is incapable of providing a path, then we'll
* have to trace our own from a surface. */
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
/* If the font is incapable of providing a path, then we'll
* have to trace our own from a surface.
*/
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
@ -2340,32 +2393,10 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
if (unlikely (status))
goto BAIL;
glyph_path = _cairo_path_fixed_create ();
if (unlikely (glyph_path == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
if (unlikely (status)) {
_cairo_path_fixed_destroy (glyph_path);
goto BAIL;
}
status = _trace_mask_to_path (scaled_glyph->surface, path,
glyphs[i].x, glyphs[i].y);
}
closure.offset.x = _cairo_fixed_from_double (glyphs[i].x);
closure.offset.y = _cairo_fixed_from_double (glyphs[i].y);
status = _cairo_path_fixed_interpret (glyph_path,
CAIRO_DIRECTION_FORWARD,
_scaled_glyph_path_move_to,
_scaled_glyph_path_line_to,
_scaled_glyph_path_curve_to,
_scaled_glyph_path_close_path,
&closure);
if (glyph_path != scaled_glyph->path)
_cairo_path_fixed_destroy (glyph_path);
if (unlikely (status))
goto BAIL;
}
@ -2485,13 +2516,13 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
}
void
_cairo_scaled_glyph_set_meta_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *meta_surface)
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface)
{
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (meta_surface);
scaled_glyph->meta_surface = meta_surface;
if (scaled_glyph->recording_surface != NULL)
cairo_surface_destroy (recording_surface);
scaled_glyph->recording_surface = recording_surface;
}
static cairo_bool_t
@ -2672,10 +2703,10 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
need_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
scaled_glyph->meta_surface == NULL)
if ((info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0 &&
scaled_glyph->recording_surface == NULL)
{
need_info |= CAIRO_SCALED_GLYPH_INFO_META_SURFACE;
need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
}
if (need_info) {
@ -2687,7 +2718,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
/* Don't trust the scaled_glyph_init() return value, the font
* backend may not even know about some of the info. For example,
* no backend other than the user-fonts knows about meta-surface
* no backend other than the user-fonts knows about recording-surface
* glyph info. */
if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 &&
@ -2704,8 +2735,8 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
scaled_glyph->meta_surface == NULL)
if ((info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0 &&
scaled_glyph->recording_surface == NULL)
{
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
@ -2737,8 +2768,7 @@ _cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
* @scaled_font: a #cairo_scaled_font_t
*
* Gets the font face that this scaled font uses. This is the
* font face passed to cairo_scaled_font_create() if that font face
* was not of type %CAIRO_FONT_TYPE_TOY.
* font face passed to cairo_scaled_font_create().
*
* Return value: The #cairo_font_face_t with which @scaled_font was
* created.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_SCRIPT_H
#define CAIRO_SCRIPT_H
#include "cairo.h"
#if CAIRO_HAS_SCRIPT_SURFACE
CAIRO_BEGIN_DECLS
typedef struct _cairo_script_context cairo_script_context_t;
typedef enum {
CAIRO_SCRIPT_MODE_BINARY,
CAIRO_SCRIPT_MODE_ASCII
} cairo_script_mode_t;
cairo_public cairo_script_context_t *
cairo_script_context_create (const char *filename);
cairo_public cairo_script_context_t *
cairo_script_context_create_for_stream (cairo_write_func_t write_func,
void *closure);
cairo_public void
cairo_script_context_write_comment (cairo_script_context_t *context,
const char *comment,
int len);
cairo_public void
cairo_script_context_set_mode (cairo_script_context_t *context,
cairo_script_mode_t mode);
cairo_public cairo_script_mode_t
cairo_script_context_get_mode (cairo_script_context_t *context);
cairo_public void
cairo_script_context_destroy (cairo_script_context_t *context);
cairo_public cairo_surface_t *
cairo_script_surface_create (cairo_script_context_t *context,
cairo_content_t content,
double width,
double height);
cairo_public cairo_surface_t *
cairo_script_surface_create_for_target (cairo_script_context_t *context,
cairo_surface_t *target);
cairo_public cairo_status_t
cairo_script_from_recording_surface (cairo_script_context_t *context,
cairo_surface_t *recording_surface);
CAIRO_END_DECLS
#else /*CAIRO_HAS_SCRIPT_SURFACE*/
# error Cairo was not compiled with support for the CairoScript backend
#endif /*CAIRO_HAS_SCRIPT_SURFACE*/
#endif /*CAIRO_SCRIPT_H*/

View File

@ -0,0 +1,84 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_SKIA_H
#define CAIRO_SKIA_H
#include "cairo.h"
#ifdef CAIRO_HAS_SKIA_SURFACE
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_skia_surface_create (cairo_format_t format,
int width,
int height);
cairo_public cairo_surface_t *
cairo_skia_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
int stride);
cairo_public unsigned char *
cairo_skia_surface_get_data (cairo_surface_t *surface);
cairo_public cairo_format_t
cairo_skia_surface_get_format (cairo_surface_t *surface);
cairo_public int
cairo_skia_surface_get_width (cairo_surface_t *surface);
cairo_public int
cairo_skia_surface_get_height (cairo_surface_t *surface);
cairo_public int
cairo_skia_surface_get_stride (cairo_surface_t *surface);
cairo_public cairo_surface_t *
cairo_skia_surface_get_image (cairo_surface_t *surface);
CAIRO_END_DECLS
#else
# error Cairo was not compiled with support for the Skia backend
#endif
#endif

View File

@ -1,118 +0,0 @@
/*
* Copyright © 2006 Keith Packard
* Copyright © 2006 Carl Worth
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef SKIPLIST_H
#define SKIPLIST_H
#include "cairoint.h"
/*
* Skip lists are described in detail here:
*
* http://citeseer.ist.psu.edu/pugh90skip.html
*/
/* Note that random_level() called from alloc_node_for_level() depends on
* this being not more than 16.
*/
#define MAX_LEVEL 15
/* Returns the index of the free-list to use for a node at level 'level' */
#define FREELIST_FOR_LEVEL(level) (((level) - 1) / 2)
/* Returns the maximum level that uses the same free-list as 'level' does */
#define FREELIST_MAX_LEVEL_FOR(level) (((level) + 1) & ~1)
#define MAX_FREELIST_LEVEL (FREELIST_FOR_LEVEL (MAX_LEVEL - 1) + 1)
/*
* Skip list element. In order to use the skip list, the caller must
* generate a structure for list elements that has as its final member
* a skip_elt_t, (which will be allocated with variable size).
*
* The caller must also pass the size of the structure to
* _cairo_skip_list_init.
*/
typedef struct _skip_elt {
int prev_index;
struct _skip_elt *prev;
struct _skip_elt *next[1];
} skip_elt_t;
#define SKIP_LIST_ELT_TO_DATA(type, elt) ((type *) ((char *) (elt) - (sizeof (type) - sizeof (skip_elt_t))))
typedef int
(*cairo_skip_list_compare_t) (void *list, void *a, void *b);
typedef struct _skip_list {
cairo_skip_list_compare_t compare;
size_t elt_size;
size_t data_size;
skip_elt_t *chains[MAX_LEVEL];
skip_elt_t *freelists[MAX_FREELIST_LEVEL];
int max_level;
struct pool *pool;
char pool_embedded[1024];
} cairo_skip_list_t;
/* Initialize a new skip list. The compare function accepts a pointer
* to the list as well as pointers to two elements. The function must
* return a value greater than zero, zero, or less then 0 if the first
* element is considered respectively greater than, equal to, or less
* than the second element. The size of each object, (as computed by
* sizeof) is passed for elt_size. Note that the structure used for
* list elements must have as its final member a skip_elt_t
*/
cairo_private void
_cairo_skip_list_init (cairo_skip_list_t *list,
cairo_skip_list_compare_t compare,
size_t elt_size);
/* Deallocate resources associated with a skip list and all elements
* in it. (XXX: currently this simply deletes all elements.)
*/
cairo_private void
_cairo_skip_list_fini (cairo_skip_list_t *list);
/* Insert a new element into the list at the correct sort order as
* determined by compare. If unique is true, then duplicate elements
* are ignored and the already inserted element is returned.
* Otherwise data will be copied (elt_size bytes from <data> via
* memcpy) and the new element is returned. */
cairo_private void *
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique);
/* Find an element which compare considers equal to <data> */
cairo_private void *
_cairo_skip_list_find (cairo_skip_list_t *list, void *data);
/* Delete an element which compare considers equal to <data> */
cairo_private void
_cairo_skip_list_delete (cairo_skip_list_t *list, void *data);
/* Delete the given element from the list. */
cairo_private void
_cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given);
#endif

View File

@ -1,399 +0,0 @@
/*
* Copyright © 2006 Keith Packard
* Copyright © 2006 Carl Worth
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "cairoint.h"
#include "cairo-skiplist-private.h"
#if HAVE_FFS
#include <strings.h> /* ffs() */
#endif
#define ELT_DATA(elt) (void *) ((char*) (elt) - list->data_size)
#define NEXT_TO_ELT(next) (skip_elt_t *) ((char *) (next) - offsetof (skip_elt_t, next))
static uint32_t
hars_petruska_f54_1_random (void)
{
# define rol(x,k) ((x << k) | (x >> (32-k)))
static uint32_t x = 0;
x = (x ^ rol(x, 5) ^ rol(x, 24)) + 0x37798849;
return x;
# undef rol
}
struct pool {
struct pool *next;
char *ptr;
unsigned int rem;
};
static struct pool *
pool_new (void)
{
struct pool *pool;
pool = malloc (8192 - 8);
if (unlikely (pool == NULL))
return NULL;
pool->next = NULL;
pool->rem = 8192 - 8 - sizeof (struct pool);
pool->ptr = (char *) (pool + 1);
return pool;
}
static void
pools_destroy (struct pool *pool)
{
while (pool->next != NULL) {
struct pool *next = pool->next;
free (pool);
pool = next;
}
}
/*
* Initialize an empty skip list
*/
void
_cairo_skip_list_init (cairo_skip_list_t *list,
cairo_skip_list_compare_t compare,
size_t elt_size)
{
int i;
list->compare = compare;
list->elt_size = elt_size;
list->data_size = elt_size - sizeof (skip_elt_t);
list->pool = (struct pool *) list->pool_embedded;
list->pool->next = NULL;
list->pool->rem = sizeof (list->pool_embedded) - sizeof (struct pool);
list->pool->ptr = list->pool_embedded + sizeof (struct pool);
for (i = 0; i < MAX_LEVEL; i++) {
list->chains[i] = NULL;
}
for (i = 0; i < MAX_FREELIST_LEVEL; i++) {
list->freelists[i] = NULL;
}
list->max_level = 0;
}
void
_cairo_skip_list_fini (cairo_skip_list_t *list)
{
pools_destroy (list->pool);
}
/*
* Generate a random level number, distributed
* so that each level is 1/4 as likely as the one before
*
* Note that level numbers run 1 <= level < MAX_LEVEL
*/
static int
random_level (void)
{
/* tricky bit -- each bit is '1' 75% of the time.
* This works because we only use the lower MAX_LEVEL
* bits, and MAX_LEVEL < 16 */
uint32_t bits = hars_petruska_f54_1_random ();
#if HAVE_FFS
return ffs (-(1<<MAX_LEVEL) | bits | bits >> 16);
#else
int level = 1;
bits |= -(1<<MAX_LEVEL) | bits >> 16;
while ((bits & 1) == 0) {
level++;
bits >>= 1;
}
return level;
#endif
}
static void *
pool_alloc (cairo_skip_list_t *list,
unsigned int level)
{
unsigned int size;
struct pool *pool;
void *ptr;
size = list->elt_size +
(FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *);
pool = list->pool;
if (size > pool->rem) {
pool = pool_new ();
if (unlikely (pool == NULL))
return NULL;
pool->next = list->pool;
list->pool = pool;
}
ptr = pool->ptr;
pool->ptr += size;
pool->rem -= size;
return ptr;
}
static void *
alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
{
int freelist_level = FREELIST_FOR_LEVEL (level);
if (list->freelists[freelist_level]) {
skip_elt_t *elt = list->freelists[freelist_level];
list->freelists[freelist_level] = elt->prev;
return ELT_DATA(elt);
}
return pool_alloc (list, level);
}
static void
free_elt (cairo_skip_list_t *list, skip_elt_t *elt)
{
int level = elt->prev_index + 1;
int freelist_level = FREELIST_FOR_LEVEL (level);
elt->prev = list->freelists[freelist_level];
list->freelists[freelist_level] = elt;
}
/*
* Insert 'data' into the list
*/
void *
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique)
{
skip_elt_t **update[MAX_LEVEL];
skip_elt_t *prev[MAX_LEVEL];
char *data_and_elt;
skip_elt_t *elt, **next;
int i, level, prev_index;
/*
* Find links along each chain
*/
elt = NULL;
next = list->chains;
for (i = list->max_level; --i >= 0; )
{
if (elt != next[i])
{
for (; (elt = next[i]); next = elt->next)
{
int cmp = list->compare (list, ELT_DATA(elt), data);
if (unique && 0 == cmp)
return ELT_DATA(elt);
if (cmp > 0)
break;
}
}
update[i] = next;
if (next != list->chains)
prev[i] = NEXT_TO_ELT (next);
else
prev[i] = NULL;
}
level = random_level ();
prev_index = level - 1;
/*
* Create new list element
*/
if (level > list->max_level)
{
level = list->max_level + 1;
prev_index = level - 1;
prev[prev_index] = NULL;
update[list->max_level] = list->chains;
list->max_level = level;
}
data_and_elt = alloc_node_for_level (list, level);
if (unlikely (data_and_elt == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
memcpy (data_and_elt, data, list->data_size);
elt = (skip_elt_t *) (data_and_elt + list->data_size);
elt->prev_index = prev_index;
elt->prev = prev[prev_index];
/*
* Insert into all chains
*/
for (i = 0; i < level; i++)
{
elt->next[i] = update[i][i];
if (elt->next[i] && elt->next[i]->prev_index == i)
elt->next[i]->prev = elt;
update[i][i] = elt;
}
return data_and_elt;
}
void *
_cairo_skip_list_find (cairo_skip_list_t *list, void *data)
{
int i;
skip_elt_t **next = list->chains;
skip_elt_t *elt;
/*
* Walk chain pointers one level at a time
*/
for (i = list->max_level; --i >= 0;)
while (next[i] && list->compare (list, data, ELT_DATA(next[i])) > 0)
{
next = next[i]->next;
}
/*
* Here we are
*/
elt = next[0];
if (elt && list->compare (list, data, ELT_DATA (elt)) == 0)
return ELT_DATA (elt);
return NULL;
}
void
_cairo_skip_list_delete (cairo_skip_list_t *list, void *data)
{
skip_elt_t **update[MAX_LEVEL], *prev[MAX_LEVEL];
skip_elt_t *elt, **next;
int i;
/*
* Find links along each chain
*/
next = list->chains;
for (i = list->max_level; --i >= 0; )
{
for (; (elt = next[i]); next = elt->next)
{
if (list->compare (list, ELT_DATA (elt), data) >= 0)
break;
}
update[i] = &next[i];
if (next == list->chains)
prev[i] = NULL;
else
prev[i] = NEXT_TO_ELT (next);
}
elt = next[0];
assert (list->compare (list, ELT_DATA (elt), data) == 0);
for (i = 0; i < list->max_level && *update[i] == elt; i++) {
*update[i] = elt->next[i];
if (elt->next[i] && elt->next[i]->prev_index == i)
elt->next[i]->prev = prev[i];
}
while (list->max_level > 0 && list->chains[list->max_level - 1] == NULL)
list->max_level--;
free_elt (list, elt);
}
void
_cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given)
{
skip_elt_t **update[MAX_LEVEL], *prev[MAX_LEVEL];
skip_elt_t *elt, **next;
int i;
/*
* Find links along each chain
*/
if (given->prev)
next = given->prev->next;
else
next = list->chains;
for (i = given->prev_index + 1; --i >= 0; )
{
for (; (elt = next[i]); next = elt->next)
{
if (elt == given)
break;
}
update[i] = &next[i];
if (next == list->chains)
prev[i] = NULL;
else
prev[i] = NEXT_TO_ELT (next);
}
elt = next[0];
assert (elt == given);
for (i = 0; i < (given->prev_index + 1) && *update[i] == elt; i++) {
*update[i] = elt->next[i];
if (elt->next[i] && elt->next[i]->prev_index == i)
elt->next[i]->prev = prev[i];
}
while (list->max_level > 0 && list->chains[list->max_level - 1] == NULL)
list->max_level--;
free_elt (list, elt);
}
#if MAIN
typedef struct {
int n;
skip_elt_t elt;
} test_elt_t;
static int
test_cmp (void *list, void *A, void *B)
{
const test_elt_t *a = A, *b = B;
return a->n - b->n;
}
int
main (void)
{
cairo_skip_list_t list;
test_elt_t elt;
int n;
_cairo_skip_list_init (&list, test_cmp, sizeof (test_elt_t));
for (n = 0; n < 10000000; n++) {
void *elt_and_data;
elt.n = n;
elt_and_data = _cairo_skip_list_insert (&list, &elt, TRUE);
assert (elt_and_data != NULL);
}
_cairo_skip_list_fini (&list);
return 0;
}
/* required supporting stubs */
cairo_status_t _cairo_error (cairo_status_t status) { return status; }
#endif

View File

@ -0,0 +1,72 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef _CAIRO_SLOPE_PRIVATE_H
#define _CAIRO_SLOPE_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-fixed-private.h"
static inline void
_cairo_slope_init (cairo_slope_t *slope,
const cairo_point_t *a,
const cairo_point_t *b)
{
slope->dx = b->x - a->x;
slope->dy = b->y - a->y;
}
static inline cairo_bool_t
_cairo_slope_equal (const cairo_slope_t *a, const cairo_slope_t *b)
{
return _cairo_int64_eq (_cairo_int32x32_64_mul (a->dy, b->dx),
_cairo_int32x32_64_mul (b->dy, a->dx));
}
static inline cairo_bool_t
_cairo_slope_backwards (const cairo_slope_t *a, const cairo_slope_t *b)
{
return _cairo_int64_negative (_cairo_int64_add (_cairo_int32x32_64_mul (a->dx, b->dx),
_cairo_int32x32_64_mul (a->dy, b->dy)));
}
cairo_private int
_cairo_slope_compare (const cairo_slope_t *a,
const cairo_slope_t *b) cairo_pure;
#endif /* _CAIRO_SLOPE_PRIVATE_H */

View File

@ -36,14 +36,7 @@
#include "cairoint.h"
void
_cairo_slope_init (cairo_slope_t *slope,
const cairo_point_t *a,
const cairo_point_t *b)
{
slope->dx = b->x - a->x;
slope->dy = b->y - a->y;
}
#include "cairo-slope-private.h"
/* Compare two slopes. Slope angles begin at 0 in the direction of the
positive X axis and increase in the direction of the positive Y
@ -94,9 +87,7 @@ _cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b)
* of b by an infinitesimally small amount, (that is, 'a' will
* always be considered less than 'b').
*/
if (((a->dx > 0) != (b->dx > 0)) ||
((a->dy > 0) != (b->dy > 0)))
{
if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) {
if (a->dx > 0 || (a->dx == 0 && a->dy > 0))
return +1;
else

View File

@ -47,26 +47,24 @@ typedef struct _cairo_half_open_span {
* surfaces if they want to composite spans instead of trapezoids. */
typedef struct _cairo_span_renderer cairo_span_renderer_t;
struct _cairo_span_renderer {
/* Private status variable. */
cairo_status_t status;
/* Called to destroy the renderer. */
cairo_destroy_func_t destroy;
/* Render the spans on row y of the source by whatever compositing
* method is required. The function should ignore spans outside
* the bounding box set by the init() function. */
cairo_status_t (*render_row)(
void *abstract_renderer,
int y,
const cairo_half_open_span_t *coverages,
unsigned num_coverages);
/* Render the spans on row y of the destination by whatever compositing
* method is required. */
cairo_warn cairo_status_t
(*render_rows) (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *coverages,
unsigned num_coverages);
/* Called after all rows have been rendered to perform whatever
* final rendering step is required. This function is called just
* once before the renderer is destroyed. */
cairo_status_t (*finish)(
void *abstract_renderer);
/* Private status variable. */
cairo_status_t status;
cairo_status_t (*finish) (void *abstract_renderer);
};
/* Scan converter interface. */
@ -75,22 +73,22 @@ struct _cairo_scan_converter {
/* Destroy this scan converter. */
cairo_destroy_func_t destroy;
/* Add an edge to the converter. */
cairo_status_t
(*add_edge)(
void *abstract_converter,
cairo_fixed_t x1,
cairo_fixed_t y1,
cairo_fixed_t x2,
cairo_fixed_t y2);
/* Add a single edge to the converter. */
cairo_status_t (*add_edge) (void *abstract_converter,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir);
/* Add a polygon (set of edges) to the converter. */
cairo_status_t (*add_polygon) (void *abstract_converter,
const cairo_polygon_t *polygon);
/* Generates coverage spans for rows for the added edges and calls
* the renderer function for each row. After generating spans the
* only valid thing to do with the converter is to destroy it. */
cairo_status_t
(*generate)(
void *abstract_converter,
cairo_span_renderer_t *renderer);
cairo_status_t (*generate) (void *abstract_converter,
cairo_span_renderer_t *renderer);
/* Private status. Read with _cairo_scan_converter_status(). */
cairo_status_t status;
@ -99,12 +97,11 @@ struct _cairo_scan_converter {
/* Scan converter constructors. */
cairo_private cairo_scan_converter_t *
_cairo_tor_scan_converter_create(
int xmin,
int ymin,
int xmax,
int ymax,
cairo_fill_rule_t fill_rule);
_cairo_tor_scan_converter_create (int xmin,
int ymin,
int xmax,
int ymax,
cairo_fill_rule_t fill_rule);
/* cairo-spans.c: */
@ -132,13 +129,25 @@ _cairo_span_renderer_set_error (void *abstract_renderer,
cairo_status_t error);
cairo_private cairo_status_t
_cairo_path_fixed_fill_using_spans (
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_path_fixed_t *path,
cairo_surface_t *dst,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects);
_cairo_surface_composite_polygon (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_polygon_t *polygon,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_antialias_t antialias,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *clip_region);
#endif /* CAIRO_SPANS_PRIVATE_H */

View File

@ -26,107 +26,7 @@
*/
#include "cairoint.h"
typedef struct {
cairo_scan_converter_t *converter;
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t has_first_point;
} scan_converter_filler_t;
static void
scan_converter_filler_init (scan_converter_filler_t *filler,
cairo_scan_converter_t *converter)
{
filler->converter = converter;
filler->current_point.x = 0;
filler->current_point.y = 0;
filler->first_point = filler->current_point;
filler->has_first_point = FALSE;
}
static cairo_status_t
scan_converter_filler_close_path (void *closure)
{
scan_converter_filler_t *filler = closure;
cairo_status_t status;
filler->has_first_point = FALSE;
if (filler->first_point.x == filler->current_point.x &&
filler->first_point.y == filler->current_point.y)
{
return CAIRO_STATUS_SUCCESS;
}
status = filler->converter->add_edge (
filler->converter,
filler->current_point.x, filler->current_point.y,
filler->first_point.x, filler->first_point.y);
filler->current_point = filler->first_point;
return status;
}
static cairo_status_t
scan_converter_filler_move_to (void *closure,
const cairo_point_t *p)
{
scan_converter_filler_t *filler = closure;
if (filler->has_first_point) {
cairo_status_t status = scan_converter_filler_close_path (closure);
if (status)
return status;
}
filler->current_point.x = p->x;
filler->current_point.y = p->y;
filler->first_point = filler->current_point;
filler->has_first_point = TRUE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
scan_converter_filler_line_to (void *closure,
const cairo_point_t *p)
{
scan_converter_filler_t *filler = closure;
cairo_status_t status;
cairo_point_t to;
to.x = p->x;
to.y = p->y;
status = filler->converter->add_edge (
filler->converter,
filler->current_point.x, filler->current_point.y,
to.x, to.y);
filler->current_point = to;
return status;
}
static cairo_status_t
_cairo_path_fixed_fill_to_scan_converter (
cairo_path_fixed_t *path,
double tolerance,
cairo_scan_converter_t *converter)
{
scan_converter_filler_t filler;
cairo_status_t status;
scan_converter_filler_init (&filler, converter);
status = _cairo_path_fixed_interpret_flat (
path, CAIRO_DIRECTION_FORWARD,
scan_converter_filler_move_to,
scan_converter_filler_line_to,
scan_converter_filler_close_path,
&filler, tolerance);
if (status)
return status;
return scan_converter_filler_close_path (&filler);
}
#include "cairo-fixed-private.h"
static cairo_scan_converter_t *
_create_scan_converter (cairo_fill_rule_t fill_rule,
@ -135,51 +35,115 @@ _create_scan_converter (cairo_fill_rule_t fill_rule,
{
if (antialias == CAIRO_ANTIALIAS_NONE) {
ASSERT_NOT_REACHED;
return _cairo_scan_converter_create_in_error (
CAIRO_INT_STATUS_UNSUPPORTED);
}
else {
return _cairo_tor_scan_converter_create (
rects->mask.x,
rects->mask.y,
rects->mask.x + rects->width,
rects->mask.y + rects->height,
fill_rule);
return NULL;
}
return _cairo_tor_scan_converter_create (rects->mask.x,
rects->mask.y,
rects->mask.x + rects->width,
rects->mask.y + rects->height,
fill_rule);
}
/* XXX Add me to the compositor interface. Ok, first create the compositor
* interface, and then add this with associated fallback!
*/
cairo_status_t
_cairo_surface_composite_polygon (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_polygon_t *polygon,
cairo_region_t *clip_region)
{
cairo_span_renderer_t *renderer;
cairo_scan_converter_t *converter;
cairo_status_t status;
converter = _create_scan_converter (fill_rule, antialias, rects);
status = converter->add_polygon (converter, polygon);
if (unlikely (status))
goto CLEANUP_CONVERTER;
renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
antialias, rects,
clip_region);
status = converter->generate (converter, renderer);
if (unlikely (status))
goto CLEANUP_RENDERER;
status = renderer->finish (renderer);
CLEANUP_RENDERER:
renderer->destroy (renderer);
CLEANUP_CONVERTER:
converter->destroy (converter);
return status;
}
cairo_status_t
_cairo_path_fixed_fill_using_spans (
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_path_fixed_t *path,
cairo_surface_t *dst,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_antialias_t antialias,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height,
cairo_trapezoid_t *traps,
int num_traps,
cairo_region_t *clip_region)
{
cairo_span_renderer_t *renderer;
cairo_scan_converter_t *converter;
cairo_composite_rectangles_t rects;
cairo_status_t status;
cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer (
op, pattern, dst, antialias, rects);
cairo_scan_converter_t *converter = _create_scan_converter (
fill_rule, antialias, rects);
status = _cairo_path_fixed_fill_to_scan_converter (
path, tolerance, converter);
if (status)
goto BAIL;
rects.src.x = src_x;
rects.src.y = src_y;
rects.dst.x = dst_x;
rects.dst.y = dst_y;
rects.mask.x = dst_x;
rects.mask.y = dst_y;
rects.width = width;
rects.height = height;
converter = _create_scan_converter (CAIRO_FILL_RULE_WINDING,
antialias,
&rects);
status = converter->status;
if (unlikely (status))
goto CLEANUP_CONVERTER;
while (num_traps--) {
status = converter->add_edge (converter,
&traps->left.p1, &traps->left.p2,
traps->top, traps->bottom, 1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
status = converter->add_edge (converter,
&traps->right.p1, &traps->right.p2,
traps->top, traps->bottom, -1);
if (unlikely (status))
goto CLEANUP_CONVERTER;
traps++;
}
renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
antialias, &rects,
clip_region);
status = converter->generate (converter, renderer);
if (status)
goto BAIL;
if (unlikely (status))
goto CLEANUP_RENDERER;
status = renderer->finish (renderer);
if (status)
goto BAIL;
BAIL:
CLEANUP_RENDERER:
renderer->destroy (renderer);
CLEANUP_CONVERTER:
converter->destroy (converter);
return status;
}
@ -191,17 +155,27 @@ _cairo_nil_destroy (void *abstract)
}
static cairo_status_t
_cairo_nil_scan_converter_add_edge (void *abstract_converter,
cairo_fixed_t x1,
cairo_fixed_t y1,
cairo_fixed_t x2,
cairo_fixed_t y2)
_cairo_nil_scan_converter_add_polygon (void *abstract_converter,
const cairo_polygon_t *polygon)
{
(void) abstract_converter;
(void) x1;
(void) y1;
(void) x2;
(void) y2;
(void) polygon;
return _cairo_scan_converter_status (abstract_converter);
}
static cairo_status_t
_cairo_nil_scan_converter_add_edge (void *abstract_converter,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
(void) abstract_converter;
(void) p1;
(void) p2;
(void) top;
(void) bottom;
(void) dir;
return _cairo_scan_converter_status (abstract_converter);
}
@ -229,6 +203,7 @@ _cairo_scan_converter_set_error (void *abstract_converter,
if (error == CAIRO_STATUS_SUCCESS)
ASSERT_NOT_REACHED;
if (converter->status == CAIRO_STATUS_SUCCESS) {
converter->add_polygon = _cairo_nil_scan_converter_add_polygon;
converter->add_edge = _cairo_nil_scan_converter_add_edge;
converter->generate = _cairo_nil_scan_converter_generate;
converter->status = error;
@ -300,13 +275,15 @@ _cairo_scan_converter_create_in_error (cairo_status_t status)
}
static cairo_status_t
_cairo_nil_span_renderer_render_row (
_cairo_nil_span_renderer_render_rows (
void *abstract_renderer,
int y,
int height,
const cairo_half_open_span_t *coverages,
unsigned num_coverages)
{
(void) y;
(void) height;
(void) coverages;
(void) num_coverages;
return _cairo_span_renderer_status (abstract_renderer);
@ -335,7 +312,7 @@ _cairo_span_renderer_set_error (
ASSERT_NOT_REACHED;
}
if (renderer->status == CAIRO_STATUS_SUCCESS) {
renderer->render_row = _cairo_nil_span_renderer_render_row;
renderer->render_rows = _cairo_nil_span_renderer_render_rows;
renderer->finish = _cairo_nil_span_renderer_finish;
renderer->status = error;
}

View File

@ -36,6 +36,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_spline_add_point_func_t add_point_func,
@ -122,12 +124,10 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots)
double bdx, bdy, berr;
double cdx, cdy, cerr;
/* Intersection point (px):
* px = p1 + u(p2 - p1)
* (p - px) (p2 - p1) = 0
* Thus:
* u = ((p - p1) (p2 - p1)) / p2 - p1²;
*/
/* We are going to compute the distance (squared) between each of the the b
* and c control points and the segment a-b. The maximum of these two
* distances will be our approximation error. */
bdx = _cairo_fixed_to_double (knots->b.x - knots->a.x);
bdy = _cairo_fixed_to_double (knots->b.y - knots->a.y);
@ -135,6 +135,13 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots)
cdy = _cairo_fixed_to_double (knots->c.y - knots->a.y);
if (knots->a.x != knots->d.x || knots->a.y != knots->d.y) {
/* Intersection point (px):
* px = p1 + u(p2 - p1)
* (p - px) (p2 - p1) = 0
* Thus:
* u = ((p - p1) (p2 - p1)) / p2 - p1²;
*/
double dx, dy, u, v;
dx = _cairo_fixed_to_double (knots->d.x - knots->a.x);

View File

@ -110,13 +110,132 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
style_expansion = M_SQRT1_2;
if (style->line_join == CAIRO_LINE_JOIN_MITER &&
style_expansion < style->miter_limit)
style_expansion < M_SQRT2 * style->miter_limit)
{
style_expansion = style->miter_limit;
style_expansion = M_SQRT2 * style->miter_limit;
}
style_expansion *= style->line_width;
*dx = style_expansion * (fabs (ctm->xx) + fabs (ctm->xy));
*dy = style_expansion * (fabs (ctm->yy) + fabs (ctm->yx));
*dx = style_expansion * hypot (ctm->xx, ctm->xy);
*dy = style_expansion * hypot (ctm->yy, ctm->yx);
}
/*
* Computes the period of a dashed stroke style.
* Returns 0 for non-dashed styles.
*/
double
_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style)
{
double period;
unsigned int i;
period = 0.0;
for (i = 0; i < style->num_dashes; i++)
period += style->dash[i];
if (style->num_dashes & 1)
period *= 2.0;
return period;
}
/*
* Coefficient of the linear approximation (minimizing square difference)
* of the surface covered by round caps
*/
#define ROUND_MINSQ_APPROXIMATION (9*M_PI/32)
/*
* Computes the length of the "on" part of a dashed stroke style,
* taking into account also line caps.
* Returns 0 for non-dashed styles.
*/
double
_cairo_stroke_style_dash_stroked (const cairo_stroke_style_t *style)
{
double stroked, cap_scale;
unsigned int i;
switch (style->line_cap) {
default: ASSERT_NOT_REACHED;
case CAIRO_LINE_CAP_BUTT: cap_scale = 0.0; break;
case CAIRO_LINE_CAP_ROUND: cap_scale = ROUND_MINSQ_APPROXIMATION; break;
case CAIRO_LINE_CAP_SQUARE: cap_scale = 1.0; break;
}
stroked = 0.0;
if (style->num_dashes & 1) {
/* Each dash element is used both as on and as off. The order in which they are summed is
* irrelevant, so sum the coverage of one dash element, taken both on and off at each iteration */
for (i = 0; i < style->num_dashes; i++)
stroked += style->dash[i] + cap_scale * MIN (style->dash[i], style->line_width);
} else {
/* Even (0, 2, ...) dashes are on and simply counted for the coverage, odd dashes are off, thus
* their coverage is approximated based on the area covered by the caps of adjacent on dases. */
for (i = 0; i < style->num_dashes; i+=2)
stroked += style->dash[i] + cap_scale * MIN (style->dash[i+1], style->line_width);
}
return stroked;
}
/*
* Verifies if _cairo_stroke_style_dash_approximate should be used to generate
* an approximation of the dash pattern in the specified style, when used for
* stroking a path with the given CTM and tolerance.
* Always %FALSE for non-dashed styles.
*/
cairo_bool_t
_cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance)
{
double period;
if (! style->num_dashes)
return FALSE;
period = _cairo_stroke_style_dash_period (style);
return _cairo_matrix_transformed_circle_major_axis (ctm, period) < tolerance;
}
/*
* Create a 2-dashes approximation of a dashed style, by making the "on" and "off"
* parts respect the original ratio.
*/
void
_cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance,
double *dash_offset,
double *dashes,
unsigned int *num_dashes)
{
double coverage, scale, offset;
cairo_bool_t on = TRUE;
unsigned int i = 0;
coverage = _cairo_stroke_style_dash_stroked (style) / _cairo_stroke_style_dash_period (style);
coverage = MIN (coverage, 1.0);
scale = tolerance / _cairo_matrix_transformed_circle_major_axis (ctm, 1.0);
/* We stop searching for a starting point as soon as the
offset reaches zero. Otherwise when an initial dash
segment shrinks to zero it will be skipped over. */
offset = style->dash_offset;
while (offset > 0.0 && offset >= style->dash[i]) {
offset -= style->dash[i];
on = !on;
if (++i == style->num_dashes)
i = 0;
}
*num_dashes = 2;
dashes[0] = scale * coverage;
dashes[1] = scale * (1.0 - coverage);
*dash_offset = on ? 0.0 : dashes[0];
}

View File

@ -0,0 +1,29 @@
/* Generated by configure. Do not edit. */
#ifndef CAIRO_SUPPORTED_FEATURES_H
#define CAIRO_SUPPORTED_FEATURES_H
/* This is a dummy header, to trick gtk-doc only */
#define CAIRO_HAS_XLIB_SURFACE 1
#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1
#define CAIRO_HAS_XCB_SHM_FUNCTIONS 1
#define CAIRO_HAS_QUARTZ_SURFACE 1
#define CAIRO_HAS_QUARTZ_FONT 1
#define CAIRO_HAS_WIN32_SURFACE 1
#define CAIRO_HAS_WIN32_FONT 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
#define CAIRO_HAS_EAGLE_FUNCTIONS 1
#define CAIRO_HAS_EGL_FUNCTIONS 1
#define CAIRO_HAS_GLX_FUNCTIONS 1
#define CAIRO_HAS_FT_FONT 1
#define CAIRO_HAS_FC_FONT 1
#define CAIRO_HAS_PS_SURFACE 1
#define CAIRO_HAS_PDF_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_RECORDING_SURFACE 1
#define CAIRO_HAS_TEE_SURFACE 1
#define CAIRO_HAS_XML_SURFACE 1
#define CAIRO_HAS_USER_FONT 1
#endif

View File

@ -0,0 +1,72 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
#ifndef CAIRO_SURFACE_CLIPPER_PRIVATE_H
#define CAIRO_SURFACE_CLIPPER_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-clip-private.h"
CAIRO_BEGIN_DECLS
typedef struct _cairo_surface_clipper cairo_surface_clipper_t;
typedef cairo_status_t
(*cairo_surface_clipper_intersect_clip_path_func_t) (cairo_surface_clipper_t *,
cairo_path_fixed_t *,
cairo_fill_rule_t,
double,
cairo_antialias_t);
struct _cairo_surface_clipper {
cairo_clip_t clip;
cairo_bool_t is_clipped;
cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path;
};
cairo_private cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
cairo_clip_t *clip);
cairo_private void
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
cairo_surface_clipper_intersect_clip_path_func_t intersect);
cairo_private void
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper);
CAIRO_END_DECLS
#endif /* CAIRO_SURFACE_CLIPPER_PRIVATE_H */

View File

@ -0,0 +1,132 @@
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-surface-clipper-private.h"
/* A collection of routines to facilitate vector surface clipping */
static cairo_status_t
_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper,
cairo_clip_path_t *clip_path)
{
cairo_status_t status;
if (clip_path->prev != NULL) {
status =
_cairo_surface_clipper_intersect_clip_path_recursive (clipper,
clip_path->prev);
if (unlikely (status))
return status;
}
return clipper->intersect_clip_path (clipper,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
}
cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_bool_t clear;
/* XXX as we cache a reference to the path, and compare every time,
* we may in future need to install a notification if the clip->path
* is every modified (e.g. cairo_clip_translate).
*/
if (clip == NULL && clipper->clip.path == NULL)
return CAIRO_STATUS_SUCCESS;
if (clip != NULL && clip->path == clipper->clip.path)
return CAIRO_STATUS_SUCCESS;
/* all clipped out state should never propagate this far */
assert (clip == NULL || clip->path != NULL);
/* Check whether this clip is a continuation of the previous.
* If not, we have to remove the current clip and rebuild.
*/
clear = clip == NULL || clip->path->prev != clipper->clip.path;
_cairo_clip_reset (&clipper->clip);
_cairo_clip_init_copy (&clipper->clip, clip);
if (clear) {
clipper->is_clipped = FALSE;
status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0);
if (unlikely (status))
return status;
if (clip != NULL && clip->path != NULL) {
status =
_cairo_surface_clipper_intersect_clip_path_recursive (clipper,
clip->path);
clipper->is_clipped = TRUE;
}
} else {
cairo_clip_path_t *path = clip->path;
clipper->is_clipped = TRUE;
status = clipper->intersect_clip_path (clipper,
&path->path,
path->fill_rule,
path->tolerance,
path->antialias);
}
return status;
}
void
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
cairo_surface_clipper_intersect_clip_path_func_t func)
{
_cairo_clip_init (&clipper->clip);
clipper->is_clipped = FALSE;
clipper->intersect_clip_path = func;
}
void
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper)
{
_cairo_clip_reset (&clipper->clip);
clipper->is_clipped = FALSE;
}

View File

@ -44,13 +44,15 @@
cairo_private cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source);
const cairo_pattern_t *source,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask);
const cairo_pattern_t *mask,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t *surface,
@ -61,7 +63,8 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias);
cairo_antialias_t antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t *surface,
@ -70,7 +73,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
cairo_antialias_t antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
@ -78,7 +82,8 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_surface_fallback_snapshot (cairo_surface_t *surface);
@ -95,7 +100,8 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
unsigned int height,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
@ -116,12 +122,12 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps);
int num_traps,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
cairo_content_t content,
int src_x,
int src_y,
int width,

Some files were not shown because too many files have changed in this diff Show More