зеркало из https://github.com/mozilla/gecko-dev.git
Bug 542605. Update cairo to 12d521df8acc483b2daa844d4f05dc2fe2765ba6. r=vlad,jwatt,bas
Reland after fixing quartz related clipping bug.
This commit is contained in:
Родитель
cba86403da
Коммит
a6ac7bede6
|
@ -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
|
||||
|
|
|
@ -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 {
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -74,6 +74,9 @@ CSRCS = \
|
|||
cairo-array.c \
|
||||
cairo-atomic.c \
|
||||
cairo-bentley-ottmann.c \
|
||||
cairo-bentley-ottmann-rectilinear.c \
|
||||
cairo-bentley-ottmann-rectangular.c \
|
||||
cairo-base64-stream.c \
|
||||
cairo-cache.c \
|
||||
cairo-clip.c \
|
||||
cairo-color.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 \
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -38,12 +38,11 @@
|
|||
|
||||
#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;
|
||||
|
||||
|
@ -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,56 +92,33 @@ _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,
|
||||
_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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -174,8 +149,14 @@ _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
|
||||
|
@ -195,6 +176,7 @@ _add_operation (cairo_analysis_surface_t *surface,
|
|||
|
||||
_cairo_box_round_to_rectangle (&bbox, rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->first_op) {
|
||||
surface->first_op = FALSE;
|
||||
|
@ -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,47 +260,69 @@ _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;
|
||||
_rectangle_intersect_clip (extents, clip);
|
||||
}
|
||||
|
||||
status = _add_operation (surface, &extents, backend_status);
|
||||
static cairo_int_status_t
|
||||
_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_status_t backend_status;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
return status;
|
||||
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
|
||||
|
@ -353,28 +330,32 @@ _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_clip_t *clip)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_int_status_t status, backend_status;
|
||||
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,
|
||||
} 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);
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
} 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);
|
||||
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,
|
||||
/* 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,
|
||||
if (surface->target->backend->show_glyphs != NULL) {
|
||||
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,
|
||||
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, NULL);
|
||||
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,
|
||||
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, NULL);
|
||||
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_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,
|
||||
backend_status =
|
||||
surface->target->backend->show_glyphs (surface->target, op,
|
||||
source,
|
||||
glyphs, num_glyphs,
|
||||
scaled_font,
|
||||
&remaining_glyphs, NULL);
|
||||
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;
|
||||
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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_init_copy_transformed (cairo_clip_t *clip,
|
||||
cairo_clip_t *other,
|
||||
cairo_surface_t *target);
|
||||
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_private cairo_status_t
|
||||
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
|
||||
cairo_operator_t op,
|
||||
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
|
||||
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);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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); \
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,16 +244,13 @@ _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,
|
||||
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,
|
||||
|
@ -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,
|
||||
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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
@ -79,16 +83,14 @@ 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;
|
||||
|
||||
pixman_format_code_t pixman_format;
|
||||
cairo_bool_t supported_destination;
|
||||
|
||||
IDirectFB *dfb;
|
||||
IDirectFBSurface *dfbsurface;
|
||||
IDirectFBSurface *tmpsurface;
|
||||
|
||||
cairo_bool_t has_clip;
|
||||
DFBRegion *clips;
|
||||
int n_clips;
|
||||
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, ®);\
|
||||
} 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, ®); \
|
||||
}\
|
||||
func;\
|
||||
}\
|
||||
|
@ -150,19 +163,19 @@ static int _directfb_argb_font = 0;
|
|||
}\
|
||||
}
|
||||
|
||||
#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) {\
|
||||
#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) {\
|
||||
#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,
|
||||
pixman_image = pixman_image_create_bits (pixman_format,
|
||||
source_rect.w, source_rect.h,
|
||||
pitch);
|
||||
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_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,9 +553,7 @@ _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),
|
||||
status = _directfb_buffer_surface_create (dfb, format,
|
||||
width, height,
|
||||
&surface->dfbsurface);
|
||||
if (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, ®ion,
|
||||
surface->dfbsurface->SetClip (surface->dfbsurface, ®ion);
|
||||
surface->dfbsurface->Blit (surface->dfbsurface,
|
||||
buffer, NULL,
|
||||
image_rect->x, image_rect->y));
|
||||
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,55 +728,50 @@ _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),
|
||||
_cairo_directfb_surface_create_internal (surface->dfb, format,
|
||||
image_src->base.content,
|
||||
width, height);
|
||||
if (clone == NULL)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
if (clone->base.status)
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
direct_memcpy (dst, src, len);
|
||||
dst += pitch;
|
||||
src += image_src->stride;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -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,7 +1181,7 @@ _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))
|
||||
if (! dst->supported_destination)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (! _directfb_get_operator (op, &sblend, &dblend))
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
|
@ -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 (®ion->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,25 +486,18 @@ _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. */
|
||||
* 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) \
|
||||
(glitz_drawable_get_features (glitz_surface_get_drawable (surface)) & \
|
||||
|
@ -649,7 +654,7 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
|
|||
}
|
||||
|
||||
src = (cairo_glitz_surface_t *)
|
||||
_cairo_surface_create_similar_scratch (&dst->base,
|
||||
_cairo_glitz_surface_create_similar (&dst->base,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
gradient->n_stops, 1);
|
||||
if (src->base.status) {
|
||||
|
@ -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 (®ion->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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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,73 +937,144 @@ _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,
|
||||
status = _cairo_surface_paint (gstate->target,
|
||||
gstate->op,
|
||||
&pattern.base,
|
||||
NULL);
|
||||
_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,
|
||||
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,
|
||||
NULL);
|
||||
_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,
|
||||
status = _cairo_surface_stroke (gstate->target,
|
||||
gstate->op,
|
||||
&source_pattern.base,
|
||||
path,
|
||||
|
@ -945,7 +1083,10 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
&gstate->ctm_inverse,
|
||||
gstate->tolerance,
|
||||
gstate->antialias,
|
||||
NULL);
|
||||
_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;
|
||||
|
||||
if (_cairo_path_fixed_fill_is_empty (path)) {
|
||||
if (_cairo_operator_bounded_by_mask (gstate->op))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_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);
|
||||
|
||||
return _cairo_surface_fill (gstate->target,
|
||||
status = _cairo_surface_fill (gstate->target,
|
||||
gstate->op,
|
||||
&pattern.base,
|
||||
path,
|
||||
gstate->fill_rule,
|
||||
gstate->tolerance,
|
||||
gstate->antialias,
|
||||
NULL);
|
||||
_gstate_get_clip (gstate, &clip));
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_clip_fini (&clip);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
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,
|
||||
return _cairo_path_fixed_in_fill (path,
|
||||
gstate->fill_rule,
|
||||
gstate->tolerance,
|
||||
x, y,
|
||||
inside_ret);
|
||||
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;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
return is_bounded;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
|
||||
#include "cairo-slope-private.h"
|
||||
|
||||
typedef struct cairo_hull {
|
||||
cairo_point_t point;
|
||||
cairo_slope_t slope;
|
||||
|
|
|
@ -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,9 +230,8 @@ _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 ||
|
||||
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)
|
||||
|
@ -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->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,11 +1031,66 @@ _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 ? ®ion->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,
|
||||
const cairo_pattern_t *src_pattern,
|
||||
|
@ -953,7 +1103,8 @@ _cairo_image_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_surface_attributes_t src_attr, mask_attr;
|
||||
cairo_image_surface_t *dst = abstract_dst;
|
||||
|
@ -961,9 +1112,12 @@ _cairo_image_surface_composite (cairo_operator_t op,
|
|||
cairo_image_surface_t *mask;
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
else {
|
||||
memset(row + prev_x, prev_alpha, x - prev_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? ®ion->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)) {
|
||||
|
|
|
@ -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 (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] + matrix->x0;
|
||||
*x2 = quad_x[1] + matrix->x0;
|
||||
*x1 = quad_x[0];
|
||||
*x2 = quad_x[1];
|
||||
} else {
|
||||
*x1 = quad_x[1] + matrix->x0;
|
||||
*x2 = quad_x[0] + matrix->x0;
|
||||
*x1 = quad_x[1];
|
||||
*x2 = quad_x[0];
|
||||
}
|
||||
}
|
||||
if (matrix->x0 != 0.) {
|
||||
*x1 += matrix->x0;
|
||||
*x2 += matrix->x0;
|
||||
}
|
||||
|
||||
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] + matrix->y0;
|
||||
*y2 = quad_y[1] + matrix->y0;
|
||||
*y1 = quad_y[0];
|
||||
*y2 = quad_y[1];
|
||||
} else {
|
||||
*y1 = quad_y[1] + matrix->y0;
|
||||
*y2 = quad_y[0] + matrix->y0;
|
||||
*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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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:
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
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,17 +296,16 @@ _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,
|
||||
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
|
||||
analysis);
|
||||
if (status || analysis->status) {
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
|
@ -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,
|
||||
status = _cairo_recording_surface_replay_region (surface->recording_surface,
|
||||
surface->target,
|
||||
CAIRO_META_REGION_NATIVE);
|
||||
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
|
||||
|
@ -624,10 +609,9 @@ _cairo_paginated_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 *extents)
|
||||
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,
|
||||
return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
|
||||
utf8, utf8_len,
|
||||
glyphs, num_glyphs,
|
||||
clusters, num_clusters,
|
||||
cluster_flags,
|
||||
scaled_font, NULL);
|
||||
|
||||
return status;
|
||||
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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
return _cairo_polygon_close (polygon) ||
|
||||
_cairo_polygon_move_to (polygon, point);
|
||||
|
||||
filler->current_point = *point;
|
||||
|
||||
return _cairo_polygon_status (&filler->polygon);
|
||||
}
|
||||
|
||||
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,
|
||||
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
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, ®ion);
|
||||
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, ®ion);
|
||||
}
|
||||
|
||||
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_region_t *
|
||||
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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->is_rectilinear = 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->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 (path->is_region) {
|
||||
path->is_region = _cairo_fixed_is_integer (x) &&
|
||||
|
||||
/* 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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
|
||||
if (unlikely (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;
|
||||
path->has_current_point = TRUE;
|
||||
|
||||
return status;
|
||||
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_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,6 +1160,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -1021,6 +1179,7 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
|
|||
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok, we may have a box, if the points line up */
|
||||
if (buf->points[0].y == buf->points[1].y &&
|
||||
|
@ -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,10 +1215,10 @@ _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))
|
||||
return FALSE;
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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,
|
||||
_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,7 +2119,8 @@ _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) {
|
||||
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 {
|
||||
|
@ -2149,10 +2151,11 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
|
|||
|
||||
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,36 +2448,119 @@ _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_matrix_t imatrix;
|
||||
double x1, y1, x2, y2;
|
||||
cairo_status_t status;
|
||||
|
||||
switch (pattern->type) {
|
||||
case CAIRO_PATTERN_TYPE_SOLID:
|
||||
goto UNBOUNDED;
|
||||
|
||||
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;
|
||||
cairo_matrix_t imatrix;
|
||||
double x1, y1, x2, y2;
|
||||
double pad;
|
||||
|
||||
status = _cairo_surface_get_extents (surface, &surface_extents);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
if (! _cairo_surface_get_extents (surface, &surface_extents))
|
||||
goto UNBOUNDED;
|
||||
|
||||
if (surface_extents.width == 0 || surface_extents.height == 0)
|
||||
goto EMPTY;
|
||||
|
||||
if (pattern->extend != CAIRO_EXTEND_NONE)
|
||||
goto UNBOUNDED;
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
/* The filter can effectively enlarge the extents of the
|
||||
* pattern, so extend as necessary.
|
||||
*/
|
||||
_cairo_pattern_analyze_filter (surface_pattern, &pad);
|
||||
_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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
imatrix = pattern->matrix;
|
||||
status = cairo_matrix_invert (&imatrix);
|
||||
|
@ -2514,23 +2587,17 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
|
|||
|
||||
extents->x = x1; extents->width = x2 - x1;
|
||||
extents->y = y1; extents->height = y2 - y1;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
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,9 +2841,16 @@ _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 (a->has_component_alpha != b->has_component_alpha)
|
||||
return FALSE;
|
||||
|
||||
if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
|
||||
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
|
||||
return FALSE;
|
||||
|
||||
|
@ -2777,6 +2859,7 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
|
|||
|
||||
if (a->extend != b->extend)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (a->type) {
|
||||
case CAIRO_PATTERN_TYPE_SOLID:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
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->line.p1 = *p1;
|
||||
edge->line.p2 = *p2;
|
||||
edge->top = top;
|
||||
edge->bottom = bottom;
|
||||
edge->dir = dir;
|
||||
} else {
|
||||
edge->edge.p1 = *p2;
|
||||
edge->edge.p2 = *p1;
|
||||
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)
|
||||
polygon->first_point = *point;
|
||||
if (polygon->has_current_edge) {
|
||||
_cairo_polygon_add_edge (polygon,
|
||||
&polygon->last_point,
|
||||
&polygon->current_point);
|
||||
polygon->has_current_edge = FALSE;
|
||||
}
|
||||
|
||||
polygon->current_point = *point;
|
||||
if (! polygon->has_current_point) {
|
||||
polygon->first_point = *point;
|
||||
polygon->has_current_point = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
polygon->current_point = *point;
|
||||
return polygon->status;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
* 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 */
|
||||
|
|
|
@ -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 (®ion->ref_count, 0);
|
||||
pixman_region32_init (®ion->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 (®ion->ref_count, 0);
|
||||
pixman_region32_init_rect (®ion->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 (®ion->ref_count));
|
||||
pixman_region32_fini (®ion->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 (®ion->ref_count, 1);
|
||||
|
||||
pixman_region32_init (®ion->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,17 +154,16 @@ cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
|
|||
int i;
|
||||
|
||||
region = _cairo_malloc (sizeof (cairo_region_t));
|
||||
|
||||
if (!region)
|
||||
if (unlikely (region == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_region_t *) &_cairo_region_nil;
|
||||
|
||||
region->status = CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (count > ARRAY_LENGTH (stack_pboxes)) {
|
||||
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
|
||||
|
||||
if (unlikely (pboxes == NULL)) {
|
||||
free (region);
|
||||
_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 (®ion->rgn, pboxes, count)) {
|
||||
free (region);
|
||||
|
||||
region = (cairo_region_t *)&_cairo_region_nil;
|
||||
}
|
||||
i = pixman_region32_init_rects (®ion->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 (®ion->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 (®ion->ref_count, 1);
|
||||
|
||||
pixman_region32_init_rect (®ion->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 (©->rgn, &original->rgn)) {
|
||||
if (original != NULL &&
|
||||
! pixman_region32_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 (®ion->ref_count))
|
||||
return NULL;
|
||||
|
||||
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
|
||||
|
||||
_cairo_reference_count_inc (®ion->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 (®ion->ref_count))
|
||||
return;
|
||||
|
||||
pixman_region32_fini (®ion->rgn);
|
||||
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
|
||||
|
||||
if (! _cairo_reference_count_dec_and_test (®ion->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 (®ion->rgn);
|
||||
return pixman_region32_n_rects (CONST_CAST ®ion->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 (®ion->rgn, NULL) + nth;
|
||||
pbox = pixman_region32_rectangles (CONST_CAST ®ion->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 (®ion->rgn);
|
||||
pextents = pixman_region32_extents (CONST_CAST ®ion->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 (®ion->rgn);
|
||||
return ! pixman_region32_not_empty (CONST_CAST ®ion->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 (®ion->rgn, &pbox);
|
||||
poverlap = pixman_region32_contains_rectangle (CONST_CAST ®ion->rgn,
|
||||
&pbox);
|
||||
switch (poverlap) {
|
||||
default:
|
||||
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
|
||||
|
@ -647,7 +698,7 @@ 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;
|
||||
|
@ -655,6 +706,36 @@ cairo_region_contains_point (cairo_region_t *region,
|
|||
if (region->status)
|
||||
return FALSE;
|
||||
|
||||
return pixman_region32_contains_point (®ion->rgn, x, y, &box);
|
||||
return pixman_region32_contains_point (CONST_CAST ®ion->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);
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,9 +2015,48 @@ _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,
|
||||
|
@ -1980,7 +2069,8 @@ _cairo_scaled_font_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_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) {
|
||||
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,12 +2193,20 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
|
|||
mask = new_mask;
|
||||
}
|
||||
|
||||
if (glyph_surface->width && glyph_surface->height) {
|
||||
cairo_surface_pattern_t glyph_pattern;
|
||||
|
||||
/* 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);
|
||||
x = _cairo_lround (glyphs[i].x -
|
||||
glyph_surface->base.device_transform.x0);
|
||||
y = _cairo_lround (glyphs[i].y -
|
||||
glyph_surface->base.device_transform.y0);
|
||||
|
||||
_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
|
||||
_cairo_pattern_init_for_surface (&glyph_pattern,
|
||||
&glyph_surface->base);
|
||||
if (mask_format == CAIRO_FORMAT_ARGB32)
|
||||
glyph_pattern.base.has_component_alpha = TRUE;
|
||||
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
|
||||
&white_pattern.base,
|
||||
|
@ -2116,25 +2216,27 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
|
|||
0, 0,
|
||||
x - dest_x, y - dest_y,
|
||||
glyph_surface->width,
|
||||
glyph_surface->height);
|
||||
glyph_surface->height,
|
||||
NULL);
|
||||
|
||||
_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));
|
||||
|
||||
} 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. */
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
* 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, path,
|
||||
glyphs[i].x, glyphs[i].y);
|
||||
}
|
||||
|
||||
status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
|
||||
if (unlikely (status)) {
|
||||
_cairo_path_fixed_destroy (glyph_path);
|
||||
goto BAIL;
|
||||
}
|
||||
}
|
||||
|
||||
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_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
cairo_surface_t *meta_surface)
|
||||
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.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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*/
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
/* 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,21 +73,21 @@ 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_status_t (*generate) (void *abstract_converter,
|
||||
cairo_span_renderer_t *renderer);
|
||||
|
||||
/* Private status. Read with _cairo_scan_converter_status(). */
|
||||
|
@ -99,8 +97,7 @@ struct _cairo_scan_converter {
|
|||
/* Scan converter constructors. */
|
||||
|
||||
cairo_private cairo_scan_converter_t *
|
||||
_cairo_tor_scan_converter_create(
|
||||
int xmin,
|
||||
_cairo_tor_scan_converter_create (int xmin,
|
||||
int ymin,
|
||||
int xmax,
|
||||
int ymax,
|
||||
|
@ -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_surface_composite_polygon (cairo_surface_t *surface,
|
||||
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);
|
||||
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 */
|
||||
|
|
|
@ -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);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return _cairo_tor_scan_converter_create (
|
||||
rects->mask.x,
|
||||
|
||||
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_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface,
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче