summaryrefslogtreecommitdiffstats
path: root/gfx/cairo/cairo/src/cairo-traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/cairo/cairo/src/cairo-traps.c')
-rw-r--r--gfx/cairo/cairo/src/cairo-traps.c605
1 files changed, 605 insertions, 0 deletions
diff --git a/gfx/cairo/cairo/src/cairo-traps.c b/gfx/cairo/cairo/src/cairo-traps.c
new file mode 100644
index 000000000..2fe6684db
--- /dev/null
+++ b/gfx/cairo/cairo/src/cairo-traps.c
@@ -0,0 +1,605 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/*
+ * Copyright © 2002 Keith Packard
+ * Copyright © 2007 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ * Keith R. Packard <keithp@keithp.com>
+ * Carl D. Worth <cworth@cworth.org>
+ *
+ * 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-region-private.h"
+#include "cairo-slope-private.h"
+
+/* private functions */
+
+void
+_cairo_traps_init (cairo_traps_t *traps)
+{
+ VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t)));
+
+ traps->status = CAIRO_STATUS_SUCCESS;
+
+ traps->maybe_region = 1;
+ traps->is_rectilinear = 0;
+ traps->is_rectangular = 0;
+
+ traps->num_traps = 0;
+
+ traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
+ traps->traps = traps->traps_embedded;
+
+ traps->num_limits = 0;
+ traps->has_intersections = FALSE;
+}
+
+void
+_cairo_traps_limit (cairo_traps_t *traps,
+ const cairo_box_t *limits,
+ int num_limits)
+{
+ traps->limits = limits;
+ traps->num_limits = num_limits;
+}
+
+void
+_cairo_traps_clear (cairo_traps_t *traps)
+{
+ traps->status = CAIRO_STATUS_SUCCESS;
+
+ traps->maybe_region = 1;
+ traps->is_rectilinear = 0;
+ traps->is_rectangular = 0;
+
+ traps->num_traps = 0;
+ traps->has_intersections = FALSE;
+}
+
+void
+_cairo_traps_fini (cairo_traps_t *traps)
+{
+ if (traps->traps != traps->traps_embedded)
+ free (traps->traps);
+
+ VG (VALGRIND_MAKE_MEM_NOACCESS (traps, sizeof (cairo_traps_t)));
+}
+
+/* make room for at least one more trap */
+static cairo_bool_t
+_cairo_traps_grow (cairo_traps_t *traps)
+{
+ cairo_trapezoid_t *new_traps;
+ int new_size = 4 * traps->traps_size;
+
+ if (CAIRO_INJECT_FAULT ()) {
+ traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return FALSE;
+ }
+
+ if (traps->traps == traps->traps_embedded) {
+ new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
+ if (new_traps != NULL)
+ memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
+ } else {
+ new_traps = _cairo_realloc_ab (traps->traps,
+ new_size, sizeof (cairo_trapezoid_t));
+ }
+
+ if (unlikely (new_traps == NULL)) {
+ traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return FALSE;
+ }
+
+ traps->traps = new_traps;
+ traps->traps_size = new_size;
+ return TRUE;
+}
+
+void
+_cairo_traps_add_trap (cairo_traps_t *traps,
+ cairo_fixed_t top, cairo_fixed_t bottom,
+ cairo_line_t *left, cairo_line_t *right)
+{
+ cairo_trapezoid_t *trap;
+
+ if (unlikely (traps->num_traps == traps->traps_size)) {
+ if (unlikely (! _cairo_traps_grow (traps)))
+ return;
+ }
+
+ trap = &traps->traps[traps->num_traps++];
+ trap->top = top;
+ trap->bottom = bottom;
+ trap->left = *left;
+ trap->right = *right;
+}
+
+/**
+ * _cairo_traps_init_box:
+ * @traps: a #cairo_traps_t
+ * @box: an array box that will each be converted to a single trapezoid
+ * to store in @traps.
+ *
+ * Initializes a #cairo_traps_t to contain an array of rectangular
+ * trapezoids.
+ **/
+cairo_status_t
+_cairo_traps_init_boxes (cairo_traps_t *traps,
+ const cairo_boxes_t *boxes)
+{
+ cairo_trapezoid_t *trap;
+ const struct _cairo_boxes_chunk *chunk;
+
+ _cairo_traps_init (traps);
+
+ while (traps->traps_size < boxes->num_boxes) {
+ if (unlikely (! _cairo_traps_grow (traps))) {
+ _cairo_traps_fini (traps);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ }
+
+ traps->num_traps = boxes->num_boxes;
+ traps->is_rectilinear = TRUE;
+ traps->is_rectangular = TRUE;
+ traps->maybe_region = boxes->is_pixel_aligned;
+
+ trap = &traps->traps[0];
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box;
+ int i;
+
+ box = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ trap->top = box->p1.y;
+ trap->bottom = box->p2.y;
+
+ trap->left.p1 = box->p1;
+ trap->left.p2.x = box->p1.x;
+ trap->left.p2.y = box->p2.y;
+
+ trap->right.p1.x = box->p2.x;
+ trap->right.p1.y = box->p1.y;
+ trap->right.p2 = box->p2;
+
+ box++, trap++;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
+ const cairo_point_t *top_left,
+ const cairo_point_t *bottom_right)
+{
+ cairo_line_t left;
+ cairo_line_t right;
+ cairo_fixed_t top, bottom;
+
+ if (top_left->y == bottom_right->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (top_left->x == bottom_right->x)
+ return CAIRO_STATUS_SUCCESS;
+
+ left.p1.x = left.p2.x = top_left->x;
+ left.p1.y = right.p1.y = top_left->y;
+ right.p1.x = right.p2.x = bottom_right->x;
+ left.p2.y = right.p2.y = bottom_right->y;
+
+ top = top_left->y;
+ bottom = bottom_right->y;
+
+ if (traps->num_limits) {
+ cairo_bool_t reversed;
+ int n;
+
+ /* support counter-clockwise winding for rectangular tessellation */
+ reversed = top_left->x > bottom_right->x;
+ if (reversed) {
+ right.p1.x = right.p2.x = top_left->x;
+ left.p1.x = left.p2.x = bottom_right->x;
+ }
+
+ for (n = 0; n < traps->num_limits; n++) {
+ const cairo_box_t *limits = &traps->limits[n];
+ cairo_line_t _left, _right;
+ cairo_fixed_t _top, _bottom;
+
+ if (top >= limits->p2.y)
+ continue;
+ if (bottom <= limits->p1.y)
+ continue;
+
+ /* Trivially reject if trapezoid is entirely to the right or
+ * to the left of the limits. */
+ if (left.p1.x >= limits->p2.x)
+ continue;
+ if (right.p1.x <= limits->p1.x)
+ continue;
+
+ /* Otherwise, clip the trapezoid to the limits. */
+ _top = top;
+ if (_top < limits->p1.y)
+ _top = limits->p1.y;
+
+ _bottom = bottom;
+ if (_bottom > limits->p2.y)
+ _bottom = limits->p2.y;
+
+ if (_bottom <= _top)
+ continue;
+
+ _left = left;
+ if (_left.p1.x < limits->p1.x) {
+ _left.p1.x = limits->p1.x;
+ _left.p1.y = limits->p1.y;
+ _left.p2.x = limits->p1.x;
+ _left.p2.y = limits->p2.y;
+ }
+
+ _right = right;
+ if (_right.p1.x > limits->p2.x) {
+ _right.p1.x = limits->p2.x;
+ _right.p1.y = limits->p1.y;
+ _right.p2.x = limits->p2.x;
+ _right.p2.y = limits->p2.y;
+ }
+
+ if (left.p1.x >= right.p1.x)
+ continue;
+
+ if (reversed)
+ _cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
+ else
+ _cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
+ }
+ } else {
+ _cairo_traps_add_trap (traps, top, bottom, &left, &right);
+ }
+
+ return traps->status;
+}
+
+void
+_cairo_traps_translate (cairo_traps_t *traps, int x, int y)
+{
+ cairo_fixed_t xoff, yoff;
+ cairo_trapezoid_t *t;
+ int i;
+
+ /* Ugh. The cairo_composite/(Render) interface doesn't allow
+ an offset for the trapezoids. Need to manually shift all
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+
+ xoff = _cairo_fixed_from_int (x);
+ yoff = _cairo_fixed_from_int (y);
+
+ for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
+ t->top += yoff;
+ t->bottom += yoff;
+ t->left.p1.x += xoff;
+ t->left.p1.y += yoff;
+ t->left.p2.x += xoff;
+ t->left.p2.y += yoff;
+ t->right.p1.x += xoff;
+ t->right.p1.y += yoff;
+ t->right.p2.x += xoff;
+ t->right.p2.y += yoff;
+ }
+}
+
+void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+ cairo_trapezoid_t *src_traps,
+ int num_traps,
+ double tx, double ty,
+ double sx, double sy)
+{
+ int i;
+ cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
+ cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
+
+ if (sx == 1.0 && sy == 1.0) {
+ for (i = 0; i < num_traps; i++) {
+ offset_traps[i].top = src_traps[i].top + yoff;
+ offset_traps[i].bottom = src_traps[i].bottom + yoff;
+ offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
+ offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
+ offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
+ offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
+ offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
+ offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
+ offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
+ offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
+ }
+ } else {
+ cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
+ cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
+
+ for (i = 0; i < num_traps; i++) {
+ offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc);
+ offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc);
+ offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc);
+ offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc);
+ offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc);
+ offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc);
+ offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc);
+ offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc);
+ offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc);
+ offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc);
+ }
+ }
+}
+
+static cairo_bool_t
+_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
+{
+ cairo_slope_t slope_left, slope_pt, slope_right;
+
+ if (t->top > pt->y)
+ return FALSE;
+ if (t->bottom < pt->y)
+ return FALSE;
+
+ _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
+ _cairo_slope_init (&slope_pt, &t->left.p1, pt);
+
+ if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
+ return FALSE;
+
+ _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
+ _cairo_slope_init (&slope_pt, &t->right.p1, pt);
+
+ if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+cairo_bool_t
+_cairo_traps_contain (const cairo_traps_t *traps,
+ double x, double y)
+{
+ int i;
+ cairo_point_t point;
+
+ point.x = _cairo_fixed_from_double (x);
+ point.y = _cairo_fixed_from_double (y);
+
+ for (i = 0; i < traps->num_traps; i++) {
+ if (_cairo_trap_contains (&traps->traps[i], &point))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static cairo_fixed_t
+_line_compute_intersection_x_for_y (const cairo_line_t *line,
+ cairo_fixed_t y)
+{
+ return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
+}
+
+void
+_cairo_traps_extents (const cairo_traps_t *traps,
+ cairo_box_t *extents)
+{
+ int i;
+
+ if (traps->num_traps == 0) {
+ extents->p1.x = extents->p1.y = 0;
+ extents->p2.x = extents->p2.y = 0;
+ return;
+ }
+
+ extents->p1.x = extents->p1.y = INT32_MAX;
+ extents->p2.x = extents->p2.y = INT32_MIN;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ const cairo_trapezoid_t *trap = &traps->traps[i];
+
+ if (trap->top < extents->p1.y)
+ extents->p1.y = trap->top;
+ if (trap->bottom > extents->p2.y)
+ extents->p2.y = trap->bottom;
+
+ if (trap->left.p1.x < extents->p1.x) {
+ cairo_fixed_t x = trap->left.p1.x;
+ if (trap->top != trap->left.p1.y) {
+ x = _line_compute_intersection_x_for_y (&trap->left,
+ trap->top);
+ if (x < extents->p1.x)
+ extents->p1.x = x;
+ } else
+ extents->p1.x = x;
+ }
+ if (trap->left.p2.x < extents->p1.x) {
+ cairo_fixed_t x = trap->left.p2.x;
+ if (trap->bottom != trap->left.p2.y) {
+ x = _line_compute_intersection_x_for_y (&trap->left,
+ trap->bottom);
+ if (x < extents->p1.x)
+ extents->p1.x = x;
+ } else
+ extents->p1.x = x;
+ }
+
+ if (trap->right.p1.x > extents->p2.x) {
+ cairo_fixed_t x = trap->right.p1.x;
+ if (trap->top != trap->right.p1.y) {
+ x = _line_compute_intersection_x_for_y (&trap->right,
+ trap->top);
+ if (x > extents->p2.x)
+ extents->p2.x = x;
+ } else
+ extents->p2.x = x;
+ }
+ if (trap->right.p2.x > extents->p2.x) {
+ cairo_fixed_t x = trap->right.p2.x;
+ if (trap->bottom != trap->right.p2.y) {
+ x = _line_compute_intersection_x_for_y (&trap->right,
+ trap->bottom);
+ if (x > extents->p2.x)
+ extents->p2.x = x;
+ } else
+ extents->p2.x = x;
+ }
+ }
+}
+
+
+/**
+ * _cairo_traps_extract_region:
+ * @traps: a #cairo_traps_t
+ * @region: a #cairo_region_t
+ *
+ * Determines if a set of trapezoids are exactly representable as a
+ * cairo region. If so, the passed-in region is initialized to
+ * the area representing the given traps. It should be finalized
+ * with cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED
+ * is returned.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
+ * or %CAIRO_STATUS_NO_MEMORY
+ **/
+cairo_int_status_t
+_cairo_traps_extract_region (cairo_traps_t *traps,
+ cairo_region_t **region)
+{
+ cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
+ cairo_rectangle_int_t *rects = stack_rects;
+ cairo_int_status_t status;
+ int i, rect_count;
+
+ /* we only treat this a hint... */
+ if (! traps->maybe_region)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
+ traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
+ ! _cairo_fixed_is_integer (traps->traps[i].top) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
+ {
+ traps->maybe_region = FALSE;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t));
+
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ rect_count = 0;
+ for (i = 0; i < traps->num_traps; i++) {
+ int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
+ int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
+ int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
+ int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
+
+ rects[rect_count].x = x1;
+ rects[rect_count].y = y1;
+ rects[rect_count].width = x2 - x1;
+ rects[rect_count].height = y2 - y1;
+
+ rect_count++;
+ }
+
+ *region = cairo_region_create_rectangles (rects, rect_count);
+ status = (*region)->status;
+
+ if (rects != stack_rects)
+ free (rects);
+
+ return status;
+}
+
+/* moves trap points such that they become the actual corners of the trapezoid */
+static void
+_sanitize_trap (cairo_trapezoid_t *t)
+{
+ cairo_trapezoid_t s = *t;
+
+#define FIX(lr, tb, p) \
+ if (t->lr.p.y != t->tb) { \
+ t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \
+ t->lr.p.y = s.tb; \
+ }
+ FIX (left, top, p1);
+ FIX (left, bottom, p2);
+ FIX (right, top, p1);
+ FIX (right, bottom, p2);
+}
+
+cairo_private cairo_status_t
+_cairo_traps_path (const cairo_traps_t *traps,
+ cairo_path_fixed_t *path)
+{
+ int i;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_status_t status;
+ cairo_trapezoid_t trap = traps->traps[i];
+
+ if (trap.top == trap.bottom)
+ continue;
+
+ _sanitize_trap (&trap);
+
+ status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
+ if (unlikely (status)) return status;
+ status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
+ if (unlikely (status)) return status;
+ status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
+ if (unlikely (status)) return status;
+ status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
+ if (unlikely (status)) return status;
+ status = _cairo_path_fixed_close_path (path);
+ if (unlikely (status)) return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}