2007-06-18 16:30:09 -07:00
|
|
|
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
2004-08-02 13:13:28 +00:00
|
|
|
/* cairo - a vector graphics library with display and print output
|
|
|
|
|
*
|
2004-10-21 18:40:50 +00:00
|
|
|
* Copyright © 2002 University of Southern California
|
2005-03-23 14:36:29 +00:00
|
|
|
* Copyright © 2005 Red Hat, Inc.
|
|
|
|
|
*
|
2004-08-02 13:13:28 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
2004-09-04 06:38:34 +00:00
|
|
|
* 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
|
2010-04-27 10:17:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
|
2004-09-04 06:38:34 +00:00
|
|
|
* 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):
|
2005-02-22 11:35:03 +00:00
|
|
|
* Carl D. Worth <cworth@cworth.org>
|
2003-07-18 11:34:19 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "cairoint.h"
|
|
|
|
|
|
2012-04-19 11:59:54 +01:00
|
|
|
#include "cairo-box-inline.h"
|
2010-01-18 16:58:40 +00:00
|
|
|
#include "cairo-error-private.h"
|
2012-04-19 11:59:54 +01:00
|
|
|
#include "cairo-list-inline.h"
|
2005-03-23 13:50:51 +00:00
|
|
|
#include "cairo-path-fixed-private.h"
|
2009-08-11 13:43:32 +01:00
|
|
|
#include "cairo-slope-private.h"
|
2005-03-23 13:50:51 +00:00
|
|
|
|
2003-07-18 11:34:19 +00:00
|
|
|
static cairo_status_t
|
2009-07-05 09:09:42 +01:00
|
|
|
_cairo_path_fixed_add (cairo_path_fixed_t *path,
|
|
|
|
|
cairo_path_op_t op,
|
|
|
|
|
const cairo_point_t *points,
|
|
|
|
|
int num_points);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
|
|
|
|
static void
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
|
|
|
|
|
cairo_path_buf_t *buf);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2007-03-08 16:23:49 -05:00
|
|
|
static cairo_path_buf_t *
|
2010-06-11 09:06:20 +01:00
|
|
|
_cairo_path_buf_create (int size_ops, int size_points);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
|
|
|
|
static void
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
|
|
|
|
static void
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
|
|
|
|
|
cairo_path_op_t op);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
|
|
|
|
static void
|
2009-07-05 09:09:42 +01:00
|
|
|
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
|
|
|
|
|
const cairo_point_t *points,
|
|
|
|
|
int num_points);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
#define cairo_path_head(path__) (&(path__)->buf.base)
|
|
|
|
|
#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
|
|
|
|
|
|
|
|
|
|
#define cairo_path_buf_next(pos__) \
|
|
|
|
|
cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
|
|
|
|
|
#define cairo_path_buf_prev(pos__) \
|
|
|
|
|
cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
|
|
|
|
|
|
|
|
|
|
#define cairo_path_foreach_buf_start(pos__, path__) \
|
|
|
|
|
pos__ = cairo_path_head (path__); do
|
|
|
|
|
#define cairo_path_foreach_buf_end(pos__, path__) \
|
|
|
|
|
while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__))
|
|
|
|
|
|
2003-07-18 11:34:19 +00:00
|
|
|
void
|
2005-03-23 13:52:54 +00:00
|
|
|
_cairo_path_fixed_init (cairo_path_fixed_t *path)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2009-06-04 14:12:20 +01:00
|
|
|
VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
cairo_list_init (&path->buf.base.link);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
path->buf.base.num_ops = 0;
|
|
|
|
|
path->buf.base.num_points = 0;
|
2010-06-11 09:06:20 +01:00
|
|
|
path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
|
|
|
|
|
path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
|
2009-07-05 14:37:02 +01:00
|
|
|
path->buf.base.op = path->buf.op;
|
|
|
|
|
path->buf.base.points = path->buf.points;
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2004-02-12 19:02:33 +00:00
|
|
|
path->current_point.x = 0;
|
|
|
|
|
path->current_point.y = 0;
|
2009-07-05 14:37:02 +01:00
|
|
|
path->last_move_point = path->current_point;
|
2010-10-21 15:14:31 +02:00
|
|
|
|
2006-02-23 22:01:07 -08:00
|
|
|
path->has_current_point = FALSE;
|
2010-10-21 15:14:31 +02:00
|
|
|
path->needs_move_to = TRUE;
|
|
|
|
|
path->has_extents = FALSE;
|
2006-12-19 21:34:16 -08:00
|
|
|
path->has_curve_to = FALSE;
|
2010-10-28 17:56:37 +02:00
|
|
|
path->stroke_is_rectilinear = TRUE;
|
|
|
|
|
path->fill_is_rectilinear = TRUE;
|
2010-10-28 18:02:59 +02:00
|
|
|
path->fill_maybe_region = TRUE;
|
|
|
|
|
path->fill_is_empty = TRUE;
|
2010-01-22 15:54:45 +00:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
path->extents.p1.x = path->extents.p1.y = 0;
|
|
|
|
|
path->extents.p2.x = path->extents.p2.y = 0;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2005-03-23 14:36:29 +00:00
|
|
|
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
const cairo_path_fixed_t *other)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2007-03-08 16:23:49 -05:00
|
|
|
cairo_path_buf_t *buf, *other_buf;
|
2010-06-11 09:06:20 +01:00
|
|
|
unsigned int num_points, num_ops;
|
2003-07-18 11:34:19 +00:00
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
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;
|
2010-06-11 09:06:20 +01:00
|
|
|
path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
|
|
|
|
|
path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
|
2007-11-04 11:55:25 +00:00
|
|
|
|
2003-12-16 07:10:48 +00:00
|
|
|
path->current_point = other->current_point;
|
|
|
|
|
path->last_move_point = other->last_move_point;
|
2010-10-21 15:14:31 +02:00
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
path->has_current_point = other->has_current_point;
|
2010-10-21 15:14:31 +02:00
|
|
|
path->needs_move_to = other->needs_move_to;
|
|
|
|
|
path->has_extents = other->has_extents;
|
2009-07-05 09:09:42 +01:00
|
|
|
path->has_curve_to = other->has_curve_to;
|
2010-10-28 17:56:37 +02:00
|
|
|
path->stroke_is_rectilinear = other->stroke_is_rectilinear;
|
|
|
|
|
path->fill_is_rectilinear = other->fill_is_rectilinear;
|
2010-10-28 18:02:59 +02:00
|
|
|
path->fill_maybe_region = other->fill_maybe_region;
|
|
|
|
|
path->fill_is_empty = other->fill_is_empty;
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2010-01-22 15:54:45 +00:00
|
|
|
path->extents = other->extents;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
path->buf.base.num_ops = other->buf.base.num_ops;
|
|
|
|
|
path->buf.base.num_points = other->buf.base.num_points;
|
|
|
|
|
memcpy (path->buf.op, other->buf.base.op,
|
|
|
|
|
other->buf.base.num_ops * sizeof (other->buf.op[0]));
|
|
|
|
|
memcpy (path->buf.points, other->buf.points,
|
|
|
|
|
other->buf.base.num_points * sizeof (other->buf.points[0]));
|
2007-11-14 00:45:24 +00:00
|
|
|
|
|
|
|
|
num_points = num_ops = 0;
|
2009-07-05 14:37:02 +01:00
|
|
|
for (other_buf = cairo_path_buf_next (cairo_path_head (other));
|
|
|
|
|
other_buf != cairo_path_head (other);
|
|
|
|
|
other_buf = cairo_path_buf_next (other_buf))
|
2005-03-23 14:36:29 +00:00
|
|
|
{
|
2007-11-14 00:45:24 +00:00
|
|
|
num_ops += other_buf->num_ops;
|
|
|
|
|
num_points += other_buf->num_points;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-11 09:06:20 +01:00
|
|
|
if (num_ops) {
|
|
|
|
|
buf = _cairo_path_buf_create (num_ops, num_points);
|
2008-11-18 17:26:55 +00:00
|
|
|
if (unlikely (buf == NULL)) {
|
2005-03-23 13:52:54 +00:00
|
|
|
_cairo_path_fixed_fini (path);
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
2007-11-14 00:45:24 +00:00
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
for (other_buf = cairo_path_buf_next (cairo_path_head (other));
|
|
|
|
|
other_buf != cairo_path_head (other);
|
|
|
|
|
other_buf = cairo_path_buf_next (other_buf))
|
2007-11-14 00:45:24 +00:00
|
|
|
{
|
|
|
|
|
memcpy (buf->op + buf->num_ops, other_buf->op,
|
|
|
|
|
other_buf->num_ops * sizeof (buf->op[0]));
|
|
|
|
|
buf->num_ops += other_buf->num_ops;
|
|
|
|
|
|
|
|
|
|
memcpy (buf->points + buf->num_points, other_buf->points,
|
|
|
|
|
other_buf->num_points * sizeof (buf->points[0]));
|
|
|
|
|
buf->num_points += other_buf->num_points;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_fixed_add_buf (path, buf);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-04 10:45:34 +00:00
|
|
|
unsigned long
|
|
|
|
|
_cairo_path_fixed_hash (const cairo_path_fixed_t *path)
|
|
|
|
|
{
|
2009-07-05 14:43:50 +01:00
|
|
|
unsigned long hash = _CAIRO_HASH_INIT_VALUE;
|
2008-11-04 10:45:34 +00:00
|
|
|
const cairo_path_buf_t *buf;
|
2010-10-17 10:55:15 +02:00
|
|
|
unsigned int count;
|
2010-01-22 15:54:45 +00:00
|
|
|
|
2010-10-17 10:55:15 +02:00
|
|
|
count = 0;
|
2009-07-05 14:37:02 +01:00
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
2008-11-04 10:45:34 +00:00
|
|
|
hash = _cairo_hash_bytes (hash, buf->op,
|
2009-07-05 14:37:02 +01:00
|
|
|
buf->num_ops * sizeof (buf->op[0]));
|
2010-10-17 10:55:15 +02:00
|
|
|
count += buf->num_ops;
|
|
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
|
|
|
|
hash = _cairo_hash_bytes (hash, &count, sizeof (count));
|
|
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
2008-11-04 10:45:34 +00:00
|
|
|
hash = _cairo_hash_bytes (hash, buf->points,
|
2009-07-05 14:37:02 +01:00
|
|
|
buf->num_points * sizeof (buf->points[0]));
|
2010-10-17 10:55:15 +02:00
|
|
|
count += buf->num_points;
|
2009-07-05 14:37:02 +01:00
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
2010-10-17 10:55:15 +02:00
|
|
|
hash = _cairo_hash_bytes (hash, &count, sizeof (count));
|
2008-11-04 10:45:34 +00:00
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned long
|
|
|
|
|
_cairo_path_fixed_size (const cairo_path_fixed_t *path)
|
|
|
|
|
{
|
|
|
|
|
const cairo_path_buf_t *buf;
|
|
|
|
|
int num_points, num_ops;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
num_ops = num_points = 0;
|
|
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
2008-11-04 10:45:34 +00:00
|
|
|
num_ops += buf->num_ops;
|
|
|
|
|
num_points += buf->num_points;
|
2009-07-05 14:37:02 +01:00
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
2008-11-04 10:45:34 +00:00
|
|
|
|
|
|
|
|
return num_ops * sizeof (buf->op[0]) +
|
|
|
|
|
num_points * sizeof (buf->points[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_bool_t
|
|
|
|
|
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
|
|
|
|
|
const cairo_path_fixed_t *b)
|
|
|
|
|
{
|
|
|
|
|
const cairo_path_buf_t *buf_a, *buf_b;
|
|
|
|
|
const cairo_path_op_t *ops_a, *ops_b;
|
|
|
|
|
const cairo_point_t *points_a, *points_b;
|
|
|
|
|
int num_points_a, num_ops_a;
|
|
|
|
|
int num_points_b, num_ops_b;
|
|
|
|
|
|
|
|
|
|
if (a == b)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2009-07-05 14:43:50 +01:00
|
|
|
/* use the flags to quickly differentiate based on contents */
|
2010-10-17 11:38:23 +02:00
|
|
|
if (a->has_curve_to != b->has_curve_to)
|
2009-07-05 14:43:50 +01:00
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-22 15:54:45 +00:00
|
|
|
if (a->extents.p1.x != b->extents.p1.x ||
|
|
|
|
|
a->extents.p1.y != b->extents.p1.y ||
|
|
|
|
|
a->extents.p2.x != b->extents.p2.x ||
|
|
|
|
|
a->extents.p2.y != b->extents.p2.y)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
num_ops_a = num_points_a = 0;
|
2010-05-07 10:24:49 -04:00
|
|
|
cairo_path_foreach_buf_start (buf_a, a) {
|
|
|
|
|
num_ops_a += buf_a->num_ops;
|
|
|
|
|
num_points_a += buf_a->num_points;
|
|
|
|
|
} cairo_path_foreach_buf_end (buf_a, a);
|
2008-11-04 10:45:34 +00:00
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
num_ops_b = num_points_b = 0;
|
2010-05-07 10:24:49 -04:00
|
|
|
cairo_path_foreach_buf_start (buf_b, b) {
|
|
|
|
|
num_ops_b += buf_b->num_ops;
|
|
|
|
|
num_points_b += buf_b->num_points;
|
|
|
|
|
} cairo_path_foreach_buf_end (buf_b, b);
|
2008-11-04 10:45:34 +00:00
|
|
|
|
|
|
|
|
if (num_ops_a == 0 && num_ops_b == 0)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (num_ops_a != num_ops_b || num_points_a != num_points_b)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
buf_a = cairo_path_head (a);
|
2008-11-04 10:45:34 +00:00
|
|
|
num_points_a = buf_a->num_points;
|
|
|
|
|
num_ops_a = buf_a->num_ops;
|
|
|
|
|
ops_a = buf_a->op;
|
|
|
|
|
points_a = buf_a->points;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
buf_b = cairo_path_head (b);
|
2008-11-04 10:45:34 +00:00
|
|
|
num_points_b = buf_b->num_points;
|
|
|
|
|
num_ops_b = buf_b->num_ops;
|
|
|
|
|
ops_b = buf_b->op;
|
|
|
|
|
points_b = buf_b->points;
|
|
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
|
int num_ops = MIN (num_ops_a, num_ops_b);
|
|
|
|
|
int num_points = MIN (num_points_a, num_points_b);
|
|
|
|
|
|
|
|
|
|
if (memcmp (ops_a, ops_b, num_ops * sizeof (cairo_path_op_t)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (memcmp (points_a, points_b, num_points * sizeof (cairo_point_t)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
num_ops_a -= num_ops;
|
|
|
|
|
ops_a += num_ops;
|
|
|
|
|
num_points_a -= num_points;
|
|
|
|
|
points_a += num_points;
|
|
|
|
|
if (num_ops_a == 0 || num_points_a == 0) {
|
|
|
|
|
if (num_ops_a || num_points_a)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
buf_a = cairo_path_buf_next (buf_a);
|
|
|
|
|
if (buf_a == cairo_path_head (a))
|
2008-11-04 10:45:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
num_points_a = buf_a->num_points;
|
|
|
|
|
num_ops_a = buf_a->num_ops;
|
|
|
|
|
ops_a = buf_a->op;
|
|
|
|
|
points_a = buf_a->points;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_ops_b -= num_ops;
|
|
|
|
|
ops_b += num_ops;
|
|
|
|
|
num_points_b -= num_points;
|
|
|
|
|
points_b += num_points;
|
|
|
|
|
if (num_ops_b == 0 || num_points_b == 0) {
|
|
|
|
|
if (num_ops_b || num_points_b)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
buf_b = cairo_path_buf_next (buf_b);
|
|
|
|
|
if (buf_b == cairo_path_head (b))
|
2008-11-04 10:45:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
num_points_b = buf_b->num_points;
|
|
|
|
|
num_ops_b = buf_b->num_ops;
|
|
|
|
|
ops_b = buf_b->op;
|
|
|
|
|
points_b = buf_b->points;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-31 15:08:02 +00:00
|
|
|
cairo_path_fixed_t *
|
|
|
|
|
_cairo_path_fixed_create (void)
|
|
|
|
|
{
|
2007-10-04 00:38:12 +01:00
|
|
|
cairo_path_fixed_t *path;
|
2005-08-31 15:08:02 +00:00
|
|
|
|
2007-10-04 00:38:12 +01:00
|
|
|
path = malloc (sizeof (cairo_path_fixed_t));
|
|
|
|
|
if (!path) {
|
2007-10-04 13:15:46 +01:00
|
|
|
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
2005-08-31 15:08:02 +00:00
|
|
|
return NULL;
|
2007-10-04 00:38:12 +01:00
|
|
|
}
|
|
|
|
|
|
2005-08-31 15:08:02 +00:00
|
|
|
_cairo_path_fixed_init (path);
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-18 11:34:19 +00:00
|
|
|
void
|
2005-03-23 13:52:54 +00:00
|
|
|
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2007-03-08 16:23:49 -05:00
|
|
|
cairo_path_buf_t *buf;
|
|
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
buf = cairo_path_buf_next (cairo_path_head (path));
|
|
|
|
|
while (buf != cairo_path_head (path)) {
|
2007-03-08 16:23:49 -05:00
|
|
|
cairo_path_buf_t *this = buf;
|
2009-07-05 14:37:02 +01:00
|
|
|
buf = cairo_path_buf_next (buf);
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_buf_destroy (this);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2009-06-04 14:12:20 +01:00
|
|
|
VG (VALGRIND_MAKE_MEM_NOACCESS (path, sizeof (cairo_path_fixed_t)));
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-31 15:08:02 +00:00
|
|
|
void
|
|
|
|
|
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
|
|
|
|
|
{
|
|
|
|
|
_cairo_path_fixed_fini (path);
|
|
|
|
|
free (path);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-19 17:20:49 +01:00
|
|
|
static cairo_path_op_t
|
2010-10-17 11:53:58 +02:00
|
|
|
_cairo_path_fixed_last_op (cairo_path_fixed_t *path)
|
2009-07-05 14:37:02 +01:00
|
|
|
{
|
|
|
|
|
cairo_path_buf_t *buf;
|
|
|
|
|
|
|
|
|
|
buf = cairo_path_tail (path);
|
2010-10-17 11:56:49 +02:00
|
|
|
assert (buf->num_ops != 0);
|
2009-07-05 14:37:02 +01:00
|
|
|
|
|
|
|
|
return buf->op[buf->num_ops - 1];
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-17 11:54:19 +02:00
|
|
|
static inline const cairo_point_t *
|
|
|
|
|
_cairo_path_fixed_penultimate_point (cairo_path_fixed_t *path)
|
|
|
|
|
{
|
|
|
|
|
cairo_path_buf_t *buf;
|
|
|
|
|
|
|
|
|
|
buf = cairo_path_tail (path);
|
|
|
|
|
if (likely (buf->num_points >= 2)) {
|
|
|
|
|
return &buf->points[buf->num_points - 2];
|
|
|
|
|
} else {
|
|
|
|
|
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
|
|
|
|
|
|
|
|
|
|
assert (prev_buf->num_points >= 2 - buf->num_points);
|
|
|
|
|
return &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 11:21:26 +01:00
|
|
|
static void
|
2010-10-17 11:54:19 +02:00
|
|
|
_cairo_path_fixed_drop_line_to (cairo_path_fixed_t *path)
|
|
|
|
|
{
|
|
|
|
|
cairo_path_buf_t *buf;
|
|
|
|
|
|
|
|
|
|
assert (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO);
|
|
|
|
|
|
|
|
|
|
buf = cairo_path_tail (path);
|
|
|
|
|
buf->num_points--;
|
|
|
|
|
buf->num_ops--;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-18 11:34:19 +00:00
|
|
|
cairo_status_t
|
2005-04-26 12:38:06 +00:00
|
|
|
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
|
|
|
|
|
cairo_fixed_t x,
|
|
|
|
|
cairo_fixed_t y)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2010-10-21 15:14:31 +02:00
|
|
|
_cairo_path_fixed_new_sub_path (path);
|
2005-04-26 12:38:06 +00:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
path->has_current_point = TRUE;
|
|
|
|
|
path->current_point.x = x;
|
|
|
|
|
path->current_point.y = y;
|
2012-09-05 14:55:55 +01:00
|
|
|
path->last_move_point = path->current_point;
|
2010-10-21 15:14:31 +02:00
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cairo_path_fixed_move_to_apply (cairo_path_fixed_t *path)
|
|
|
|
|
{
|
|
|
|
|
if (likely (! path->needs_move_to))
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
path->needs_move_to = FALSE;
|
2009-07-05 14:37:02 +01:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
if (path->has_extents) {
|
|
|
|
|
_cairo_box_add_point (&path->extents, &path->current_point);
|
2007-01-17 15:07:12 -08:00
|
|
|
} else {
|
2010-10-21 15:14:31 +02:00
|
|
|
_cairo_box_set (&path->extents, &path->current_point, &path->current_point);
|
|
|
|
|
path->has_extents = TRUE;
|
|
|
|
|
}
|
2009-07-05 09:09:42 +01:00
|
|
|
|
2010-10-28 18:02:59 +02:00
|
|
|
if (path->fill_maybe_region) {
|
|
|
|
|
path->fill_maybe_region = _cairo_fixed_is_integer (path->current_point.x) &&
|
2010-10-21 15:14:31 +02:00
|
|
|
_cairo_fixed_is_integer (path->current_point.y);
|
2007-01-17 15:07:12 -08:00
|
|
|
}
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
path->last_move_point = path->current_point;
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
return _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &path->current_point, 1);
|
2003-12-16 07:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
2006-02-23 22:01:07 -08:00
|
|
|
void
|
|
|
|
|
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
|
|
|
|
|
{
|
2010-10-21 15:14:31 +02:00
|
|
|
if (! path->needs_move_to) {
|
|
|
|
|
/* If the current subpath doesn't need_move_to, it contains at least one command */
|
2010-10-28 17:56:37 +02:00
|
|
|
if (path->fill_is_rectilinear) {
|
2010-10-21 15:14:31 +02:00
|
|
|
/* Implicitly close for fill */
|
2010-10-28 17:56:37 +02:00
|
|
|
path->fill_is_rectilinear = path->current_point.x == path->last_move_point.x ||
|
|
|
|
|
path->current_point.y == path->last_move_point.y;
|
2010-10-28 18:02:59 +02:00
|
|
|
path->fill_maybe_region &= path->fill_is_rectilinear;
|
2010-10-21 15:14:31 +02:00
|
|
|
}
|
|
|
|
|
path->needs_move_to = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-23 22:01:07 -08:00
|
|
|
path->has_current_point = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-16 07:10:48 +00:00
|
|
|
cairo_status_t
|
2005-03-23 14:36:29 +00:00
|
|
|
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_fixed_t dx,
|
|
|
|
|
cairo_fixed_t dy)
|
2003-12-16 07:10:48 +00:00
|
|
|
{
|
2009-07-05 09:09:42 +01:00
|
|
|
if (unlikely (! path->has_current_point))
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
|
2005-05-03 14:28:50 +00:00
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
return _cairo_path_fixed_move_to (path,
|
|
|
|
|
path->current_point.x + dx,
|
|
|
|
|
path->current_point.y + dy);
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2005-03-23 14:36:29 +00:00
|
|
|
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_fixed_t x,
|
|
|
|
|
cairo_fixed_t y)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2003-12-16 07:10:48 +00:00
|
|
|
cairo_status_t status;
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_point_t point;
|
|
|
|
|
|
|
|
|
|
point.x = x;
|
|
|
|
|
point.y = y;
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2006-08-18 06:27:45 -07:00
|
|
|
/* When there is not yet a current point, the line_to operation
|
|
|
|
|
* becomes a move_to instead. Note: We have to do this by
|
2009-06-16 23:27:20 +02:00
|
|
|
* explicitly calling into _cairo_path_fixed_move_to to ensure
|
2006-08-18 06:27:45 -07:00
|
|
|
* that the last_move_point state is updated properly.
|
|
|
|
|
*/
|
2009-10-30 07:49:56 +00:00
|
|
|
if (! path->has_current_point)
|
|
|
|
|
return _cairo_path_fixed_move_to (path, point.x, point.y);
|
2009-08-04 13:59:03 +01:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
status = _cairo_path_fixed_move_to_apply (path);
|
|
|
|
|
if (unlikely (status))
|
|
|
|
|
return status;
|
|
|
|
|
|
2009-10-30 07:58:45 +00:00
|
|
|
/* 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.
|
|
|
|
|
*/
|
2010-10-17 11:53:58 +02:00
|
|
|
if (_cairo_path_fixed_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
|
2009-10-30 07:58:45 +00:00
|
|
|
if (x == path->current_point.x && y == path->current_point.y)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-30 07:49:56 +00:00
|
|
|
/* 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.
|
|
|
|
|
*/
|
2010-10-17 11:53:58 +02:00
|
|
|
if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
|
2009-10-30 07:49:56 +00:00
|
|
|
const cairo_point_t *p;
|
|
|
|
|
|
2010-10-17 12:33:40 +02:00
|
|
|
p = _cairo_path_fixed_penultimate_point (path);
|
2009-10-30 07:49:56 +00:00
|
|
|
if (p->x == path->current_point.x && p->y == path->current_point.y) {
|
|
|
|
|
/* previous line element was degenerate, replace */
|
2010-10-17 12:33:40 +02:00
|
|
|
_cairo_path_fixed_drop_line_to (path);
|
2009-10-30 07:49:56 +00:00
|
|
|
} else {
|
|
|
|
|
cairo_slope_t prev, self;
|
|
|
|
|
|
|
|
|
|
_cairo_slope_init (&prev, p, &path->current_point);
|
|
|
|
|
_cairo_slope_init (&self, &path->current_point, &point);
|
2010-01-12 17:00:25 +00:00
|
|
|
if (_cairo_slope_equal (&prev, &self) &&
|
|
|
|
|
/* cannot trim anti-parallel segments whilst stroking */
|
|
|
|
|
! _cairo_slope_backwards (&prev, &self))
|
|
|
|
|
{
|
2010-10-17 12:33:40 +02:00
|
|
|
_cairo_path_fixed_drop_line_to (path);
|
|
|
|
|
/* In this case the flags might be more restrictive than
|
|
|
|
|
* what we actually need.
|
|
|
|
|
* When changing the flags definition we should check if
|
|
|
|
|
* changing the line_to point can affect them.
|
|
|
|
|
*/
|
2009-10-30 07:49:56 +00:00
|
|
|
}
|
2009-07-05 09:09:42 +01:00
|
|
|
}
|
2009-10-30 07:49:56 +00:00
|
|
|
}
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2010-10-28 17:56:37 +02:00
|
|
|
if (path->stroke_is_rectilinear) {
|
|
|
|
|
path->stroke_is_rectilinear = path->current_point.x == x ||
|
|
|
|
|
path->current_point.y == y;
|
|
|
|
|
path->fill_is_rectilinear &= path->stroke_is_rectilinear;
|
2010-10-28 18:02:59 +02:00
|
|
|
path->fill_maybe_region &= path->fill_is_rectilinear;
|
|
|
|
|
if (path->fill_maybe_region) {
|
|
|
|
|
path->fill_maybe_region = _cairo_fixed_is_integer (x) &&
|
2010-10-28 17:56:37 +02:00
|
|
|
_cairo_fixed_is_integer (y);
|
|
|
|
|
}
|
2010-10-28 18:02:59 +02:00
|
|
|
if (path->fill_is_empty) {
|
|
|
|
|
path->fill_is_empty = path->current_point.x == x &&
|
2010-10-28 17:56:37 +02:00
|
|
|
path->current_point.y == y;
|
|
|
|
|
}
|
2009-08-11 17:01:50 +01:00
|
|
|
}
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2009-10-30 07:49:56 +00:00
|
|
|
path->current_point = point;
|
2010-10-21 15:14:31 +02:00
|
|
|
|
|
|
|
|
_cairo_box_add_point (&path->extents, &point);
|
2010-10-17 14:21:07 +02:00
|
|
|
|
|
|
|
|
return _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
|
2003-12-16 07:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2005-03-23 14:36:29 +00:00
|
|
|
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_fixed_t dx,
|
|
|
|
|
cairo_fixed_t dy)
|
2003-12-16 07:10:48 +00:00
|
|
|
{
|
2009-07-05 09:09:42 +01:00
|
|
|
if (unlikely (! path->has_current_point))
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
|
2005-05-03 14:28:50 +00:00
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
return _cairo_path_fixed_line_to (path,
|
|
|
|
|
path->current_point.x + dx,
|
|
|
|
|
path->current_point.y + dy);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2005-03-23 14:36:29 +00:00
|
|
|
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_fixed_t x0, cairo_fixed_t y0,
|
|
|
|
|
cairo_fixed_t x1, cairo_fixed_t y1,
|
|
|
|
|
cairo_fixed_t x2, cairo_fixed_t y2)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2003-12-16 07:10:48 +00:00
|
|
|
cairo_status_t status;
|
2003-10-04 09:06:15 +00:00
|
|
|
cairo_point_t point[3];
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2011-07-30 17:28:21 +01:00
|
|
|
/* If this curves does not move, replace it with a line-to.
|
|
|
|
|
* This frequently happens with rounded-rectangles and r==0.
|
|
|
|
|
*/
|
|
|
|
|
if (path->current_point.x == x2 && path->current_point.y == y2) {
|
|
|
|
|
if (x1 == x2 && x0 == x2 && y1 == y2 && y0 == y2)
|
|
|
|
|
return _cairo_path_fixed_line_to (path, x2, y2);
|
|
|
|
|
|
|
|
|
|
/* We may want to check for the absence of a cusp, in which case
|
|
|
|
|
* we can also replace the curve-to with a line-to.
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-16 23:27:20 +02:00
|
|
|
/* make sure subpaths are started properly */
|
2006-02-23 22:01:07 -08:00
|
|
|
if (! path->has_current_point) {
|
2009-07-05 09:09:42 +01:00
|
|
|
status = _cairo_path_fixed_move_to (path, x0, y0);
|
2010-10-21 15:14:31 +02:00
|
|
|
assert (status == CAIRO_STATUS_SUCCESS);
|
2006-02-23 22:01:07 -08:00
|
|
|
}
|
|
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
status = _cairo_path_fixed_move_to_apply (path);
|
|
|
|
|
if (unlikely (status))
|
|
|
|
|
return status;
|
|
|
|
|
|
2010-10-17 14:10:58 +02:00
|
|
|
/* If the previous op was a degenerate LINE_TO, drop it. */
|
|
|
|
|
if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
|
|
|
|
|
const cairo_point_t *p;
|
|
|
|
|
|
|
|
|
|
p = _cairo_path_fixed_penultimate_point (path);
|
|
|
|
|
if (p->x == path->current_point.x && p->y == path->current_point.y) {
|
|
|
|
|
/* previous line element was degenerate, replace */
|
|
|
|
|
_cairo_path_fixed_drop_line_to (path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
point[0].x = x0; point[0].y = y0;
|
|
|
|
|
point[1].x = x1; point[1].y = y1;
|
|
|
|
|
point[2].x = x2; point[2].y = y2;
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2010-10-22 23:03:51 +02:00
|
|
|
_cairo_box_add_curve_to (&path->extents, &path->current_point,
|
|
|
|
|
&point[0], &point[1], &point[2]);
|
2010-01-22 15:54:45 +00:00
|
|
|
|
2010-10-21 15:14:31 +02:00
|
|
|
path->current_point = point[2];
|
|
|
|
|
path->has_curve_to = TRUE;
|
2010-10-28 17:56:37 +02:00
|
|
|
path->stroke_is_rectilinear = FALSE;
|
|
|
|
|
path->fill_is_rectilinear = FALSE;
|
2010-10-28 18:02:59 +02:00
|
|
|
path->fill_maybe_region = FALSE;
|
|
|
|
|
path->fill_is_empty = FALSE;
|
2010-10-21 15:14:31 +02:00
|
|
|
|
2010-10-17 14:21:07 +02:00
|
|
|
return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
|
2003-12-16 07:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2005-03-23 13:52:54 +00:00
|
|
|
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_fixed_t dx0, cairo_fixed_t dy0,
|
|
|
|
|
cairo_fixed_t dx1, cairo_fixed_t dy1,
|
|
|
|
|
cairo_fixed_t dx2, cairo_fixed_t dy2)
|
2003-12-16 07:10:48 +00:00
|
|
|
{
|
2009-07-05 09:09:42 +01:00
|
|
|
if (unlikely (! path->has_current_point))
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
|
2005-05-03 14:28:50 +00:00
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
return _cairo_path_fixed_curve_to (path,
|
|
|
|
|
path->current_point.x + dx0,
|
|
|
|
|
path->current_point.y + dy0,
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
path->current_point.x + dx1,
|
|
|
|
|
path->current_point.y + dy1,
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
path->current_point.x + dx2,
|
|
|
|
|
path->current_point.y + dy2);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2005-03-23 13:52:54 +00:00
|
|
|
_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2003-12-16 07:10:48 +00:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2006-02-23 22:01:07 -08:00
|
|
|
if (! path->has_current_point)
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
|
2010-10-17 11:40:34 +02:00
|
|
|
/*
|
|
|
|
|
* Add a line_to, to compute flags and solve any degeneracy.
|
|
|
|
|
* It will be removed later (if it was actually added).
|
|
|
|
|
*/
|
|
|
|
|
status = _cairo_path_fixed_line_to (path,
|
|
|
|
|
path->last_move_point.x,
|
|
|
|
|
path->last_move_point.y);
|
|
|
|
|
if (unlikely (status))
|
|
|
|
|
return status;
|
2009-08-11 17:02:41 +01:00
|
|
|
|
2010-10-17 11:40:34 +02:00
|
|
|
/*
|
|
|
|
|
* If the command used to close the path is a line_to, drop it.
|
|
|
|
|
* We must check that last command is actually a line_to,
|
|
|
|
|
* because the path could have been closed with a curve_to (and
|
|
|
|
|
* the previous line_to not added as it would be degenerate).
|
|
|
|
|
*/
|
|
|
|
|
if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO)
|
|
|
|
|
_cairo_path_fixed_drop_line_to (path);
|
2009-08-11 17:02:41 +01:00
|
|
|
|
2010-10-17 15:02:54 +02:00
|
|
|
path->needs_move_to = TRUE; /* After close_path, add an implicit move_to */
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2010-10-17 15:02:54 +02:00
|
|
|
return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
|
2003-12-16 07:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-30 10:42:22 +00:00
|
|
|
cairo_bool_t
|
2005-03-23 14:36:29 +00:00
|
|
|
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
|
2005-04-26 12:38:06 +00:00
|
|
|
cairo_fixed_t *x,
|
|
|
|
|
cairo_fixed_t *y)
|
2003-12-16 07:10:48 +00:00
|
|
|
{
|
2007-10-30 10:42:22 +00:00
|
|
|
if (! path->has_current_point)
|
|
|
|
|
return FALSE;
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2005-04-26 12:38:06 +00:00
|
|
|
*x = path->current_point.x;
|
|
|
|
|
*y = path->current_point.y;
|
2003-12-16 07:10:48 +00:00
|
|
|
|
2007-10-30 10:42:22 +00:00
|
|
|
return TRUE;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
2009-07-05 09:09:42 +01:00
|
|
|
_cairo_path_fixed_add (cairo_path_fixed_t *path,
|
|
|
|
|
cairo_path_op_t op,
|
|
|
|
|
const cairo_point_t *points,
|
|
|
|
|
int num_points)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2009-07-05 14:37:02 +01:00
|
|
|
cairo_path_buf_t *buf = cairo_path_tail (path);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2010-06-11 09:06:20 +01:00
|
|
|
if (buf->num_ops + 1 > buf->size_ops ||
|
|
|
|
|
buf->num_points + num_points > buf->size_points)
|
2007-11-04 11:55:25 +00:00
|
|
|
{
|
2010-06-11 09:06:20 +01:00
|
|
|
buf = _cairo_path_buf_create (buf->num_ops * 2, buf->num_points * 2);
|
2008-11-18 17:26:55 +00:00
|
|
|
if (unlikely (buf == NULL))
|
2007-10-04 13:15:46 +01:00
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_fixed_add_buf (path, buf);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-05 09:21:47 +01:00
|
|
|
if (WATCH_PATH) {
|
|
|
|
|
const char *op_str[] = {
|
|
|
|
|
"move-to",
|
|
|
|
|
"line-to",
|
|
|
|
|
"curve-to",
|
|
|
|
|
"close-path",
|
|
|
|
|
};
|
|
|
|
|
char buf[1024];
|
|
|
|
|
int len = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
len += snprintf (buf + len, sizeof (buf), "[");
|
|
|
|
|
for (i = 0; i < num_points; i++) {
|
|
|
|
|
if (i != 0)
|
|
|
|
|
len += snprintf (buf + len, sizeof (buf), " ");
|
|
|
|
|
len += snprintf (buf + len, sizeof (buf), "(%f, %f)",
|
|
|
|
|
_cairo_fixed_to_double (points[i].x),
|
|
|
|
|
_cairo_fixed_to_double (points[i].y));
|
|
|
|
|
}
|
|
|
|
|
len += snprintf (buf + len, sizeof (buf), "]");
|
|
|
|
|
|
2010-10-21 16:59:01 +02:00
|
|
|
#define STRINGIFYFLAG(x) (path->x ? #x " " : "")
|
2009-07-05 09:21:47 +01:00
|
|
|
fprintf (stderr,
|
2010-10-21 16:59:01 +02:00
|
|
|
"_cairo_path_fixed_add (%s, %s) [%s%s%s%s%s%s%s%s]\n",
|
|
|
|
|
op_str[(int) op], buf,
|
|
|
|
|
STRINGIFYFLAG(has_current_point),
|
|
|
|
|
STRINGIFYFLAG(needs_move_to),
|
|
|
|
|
STRINGIFYFLAG(has_extents),
|
|
|
|
|
STRINGIFYFLAG(has_curve_to),
|
|
|
|
|
STRINGIFYFLAG(stroke_is_rectilinear),
|
|
|
|
|
STRINGIFYFLAG(fill_is_rectilinear),
|
|
|
|
|
STRINGIFYFLAG(fill_is_empty),
|
|
|
|
|
STRINGIFYFLAG(fill_maybe_region)
|
|
|
|
|
);
|
|
|
|
|
#undef STRINGIFYFLAG
|
2009-07-05 09:21:47 +01:00
|
|
|
}
|
|
|
|
|
|
2007-11-04 11:55:25 +00:00
|
|
|
_cairo_path_buf_add_op (buf, op);
|
|
|
|
|
_cairo_path_buf_add_points (buf, points, num_points);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
|
|
|
|
|
cairo_path_buf_t *buf)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2009-07-05 14:37:02 +01:00
|
|
|
cairo_list_add_tail (&buf->link, &cairo_path_head (path)->link);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
2010-06-11 09:06:20 +01:00
|
|
|
COMPILE_TIME_ASSERT (sizeof (cairo_path_op_t) == 1);
|
2007-03-08 16:23:49 -05:00
|
|
|
static cairo_path_buf_t *
|
2010-06-11 09:06:20 +01:00
|
|
|
_cairo_path_buf_create (int size_ops, int size_points)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2007-03-08 16:23:49 -05:00
|
|
|
cairo_path_buf_t *buf;
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2010-06-11 09:06:20 +01:00
|
|
|
/* adjust size_ops to ensure that buf->points is naturally aligned */
|
|
|
|
|
size_ops += sizeof (double) - ((sizeof (cairo_path_buf_t) + size_ops) % sizeof (double));
|
|
|
|
|
buf = _cairo_malloc_ab_plus_c (size_points, sizeof (cairo_point_t), size_ops + sizeof (cairo_path_buf_t));
|
2007-03-08 16:23:49 -05:00
|
|
|
if (buf) {
|
|
|
|
|
buf->num_ops = 0;
|
|
|
|
|
buf->num_points = 0;
|
2010-06-11 09:06:20 +01:00
|
|
|
buf->size_ops = size_ops;
|
|
|
|
|
buf->size_points = size_points;
|
2007-11-04 11:55:25 +00:00
|
|
|
|
2007-12-27 12:46:13 +00:00
|
|
|
buf->op = (cairo_path_op_t *) (buf + 1);
|
2010-06-11 09:06:20 +01:00
|
|
|
buf->points = (cairo_point_t *) (buf->op + size_ops);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
2007-03-08 16:23:49 -05:00
|
|
|
return buf;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_buf_destroy (cairo_path_buf_t *buf)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2007-03-08 16:23:49 -05:00
|
|
|
free (buf);
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2007-03-08 16:23:49 -05:00
|
|
|
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
|
|
|
|
|
cairo_path_op_t op)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2007-03-08 16:23:49 -05:00
|
|
|
buf->op[buf->num_ops++] = op;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2009-07-05 09:09:42 +01:00
|
|
|
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
|
|
|
|
|
const cairo_point_t *points,
|
|
|
|
|
int num_points)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2011-09-16 18:00:21 +02:00
|
|
|
if (num_points == 0)
|
2011-09-16 16:11:42 +01:00
|
|
|
return;
|
|
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
memcpy (buf->points + buf->num_points,
|
|
|
|
|
points,
|
|
|
|
|
sizeof (points[0]) * num_points);
|
|
|
|
|
buf->num_points += num_points;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2008-05-09 13:13:15 +02:00
|
|
|
_cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
|
2005-03-23 13:52:54 +00:00
|
|
|
cairo_path_fixed_move_to_func_t *move_to,
|
|
|
|
|
cairo_path_fixed_line_to_func_t *line_to,
|
|
|
|
|
cairo_path_fixed_curve_to_func_t *curve_to,
|
|
|
|
|
cairo_path_fixed_close_path_func_t *close_path,
|
|
|
|
|
void *closure)
|
2003-07-18 11:34:19 +00:00
|
|
|
{
|
2010-12-09 22:00:06 +01:00
|
|
|
const cairo_path_buf_t *buf;
|
2003-07-18 11:34:19 +00:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2010-12-09 22:00:06 +01:00
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
|
|
|
|
const cairo_point_t *points = buf->points;
|
|
|
|
|
unsigned int i;
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2010-12-09 22:00:06 +01:00
|
|
|
for (i = 0; i < buf->num_ops; i++) {
|
|
|
|
|
switch (buf->op[i]) {
|
2003-09-27 05:00:47 +00:00
|
|
|
case CAIRO_PATH_OP_MOVE_TO:
|
2007-03-08 16:23:49 -05:00
|
|
|
status = (*move_to) (closure, &points[0]);
|
2010-12-09 22:00:06 +01:00
|
|
|
points += 1;
|
2003-07-18 11:34:19 +00:00
|
|
|
break;
|
2003-09-27 05:00:47 +00:00
|
|
|
case CAIRO_PATH_OP_LINE_TO:
|
2007-03-08 16:23:49 -05:00
|
|
|
status = (*line_to) (closure, &points[0]);
|
2010-12-09 22:00:06 +01:00
|
|
|
points += 1;
|
2003-07-18 11:34:19 +00:00
|
|
|
break;
|
2003-09-27 05:00:47 +00:00
|
|
|
case CAIRO_PATH_OP_CURVE_TO:
|
2007-03-08 16:23:49 -05:00
|
|
|
status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
|
2010-12-09 22:00:06 +01:00
|
|
|
points += 3;
|
2003-07-18 11:34:19 +00:00
|
|
|
break;
|
2003-12-08 13:38:26 +00:00
|
|
|
default:
|
2009-07-05 09:09:42 +01:00
|
|
|
ASSERT_NOT_REACHED;
|
|
|
|
|
case CAIRO_PATH_OP_CLOSE_PATH:
|
2004-02-12 19:02:33 +00:00
|
|
|
status = (*close_path) (closure);
|
2003-07-18 11:34:19 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2010-12-09 22:00:06 +01:00
|
|
|
|
2008-11-18 15:38:37 +00:00
|
|
|
if (unlikely (status))
|
2003-12-08 13:38:26 +00:00
|
|
|
return status;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
2010-12-09 22:00:06 +01:00
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
2003-07-18 11:34:19 +00:00
|
|
|
|
2004-02-12 19:02:33 +00:00
|
|
|
return CAIRO_STATUS_SUCCESS;
|
2003-07-18 11:34:19 +00:00
|
|
|
}
|
2006-05-04 01:45:41 -07:00
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
typedef struct _cairo_path_fixed_append_closure {
|
|
|
|
|
cairo_point_t offset;
|
|
|
|
|
cairo_path_fixed_t *path;
|
|
|
|
|
} cairo_path_fixed_append_closure_t;
|
|
|
|
|
|
2008-05-09 13:13:52 +02:00
|
|
|
static cairo_status_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_append_move_to (void *abstract_closure,
|
2008-12-09 20:44:25 +00:00
|
|
|
const cairo_point_t *point)
|
2008-05-09 13:13:52 +02:00
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
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);
|
2008-05-09 13:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_append_line_to (void *abstract_closure,
|
2008-12-09 20:44:25 +00:00
|
|
|
const cairo_point_t *point)
|
2008-05-09 13:13:52 +02:00
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
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);
|
2008-05-09 13:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_append_curve_to (void *abstract_closure,
|
2008-12-09 20:44:25 +00:00
|
|
|
const cairo_point_t *p0,
|
|
|
|
|
const cairo_point_t *p1,
|
|
|
|
|
const cairo_point_t *p2)
|
2008-05-09 13:13:52 +02:00
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
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);
|
2008-05-09 13:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_append_close_path (void *abstract_closure)
|
2008-05-09 13:13:52 +02:00
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
cairo_path_fixed_append_closure_t *closure = abstract_closure;
|
|
|
|
|
|
|
|
|
|
return _cairo_path_fixed_close_path (closure->path);
|
2008-05-09 13:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-09 20:44:25 +00:00
|
|
|
cairo_status_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_cairo_path_fixed_append (cairo_path_fixed_t *path,
|
|
|
|
|
const cairo_path_fixed_t *other,
|
|
|
|
|
cairo_fixed_t tx,
|
|
|
|
|
cairo_fixed_t ty)
|
2008-05-09 13:13:52 +02:00
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
cairo_path_fixed_append_closure_t closure;
|
|
|
|
|
|
|
|
|
|
closure.path = path;
|
|
|
|
|
closure.offset.x = tx;
|
|
|
|
|
closure.offset.y = ty;
|
|
|
|
|
|
2010-12-09 22:00:01 +01:00
|
|
|
return _cairo_path_fixed_interpret (other,
|
2008-05-09 13:13:52 +02:00
|
|
|
_append_move_to,
|
|
|
|
|
_append_line_to,
|
|
|
|
|
_append_curve_to,
|
|
|
|
|
_append_close_path,
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
&closure);
|
2008-05-09 13:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
2006-05-04 01:45:41 -07:00
|
|
|
static void
|
|
|
|
|
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
|
|
|
|
|
cairo_fixed_t offx,
|
|
|
|
|
cairo_fixed_t offy,
|
|
|
|
|
cairo_fixed_t scalex,
|
|
|
|
|
cairo_fixed_t scaley)
|
|
|
|
|
{
|
2009-07-05 14:37:02 +01:00
|
|
|
cairo_path_buf_t *buf;
|
2008-11-28 17:12:03 +00:00
|
|
|
unsigned int i;
|
2006-05-04 01:45:41 -07:00
|
|
|
|
2010-10-21 17:11:48 +02:00
|
|
|
if (scalex == CAIRO_FIXED_ONE && scaley == CAIRO_FIXED_ONE) {
|
|
|
|
|
_cairo_path_fixed_translate (path, offx, offy);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-28 18:36:42 +02:00
|
|
|
path->last_move_point.x = _cairo_fixed_mul (scalex, path->last_move_point.x) + offx;
|
|
|
|
|
path->last_move_point.y = _cairo_fixed_mul (scaley, path->last_move_point.y) + offy;
|
|
|
|
|
path->current_point.x = _cairo_fixed_mul (scalex, path->current_point.x) + offx;
|
|
|
|
|
path->current_point.y = _cairo_fixed_mul (scaley, path->current_point.y) + offy;
|
2010-10-28 18:38:50 +02:00
|
|
|
|
|
|
|
|
path->fill_maybe_region = TRUE;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
|
2009-07-05 14:37:02 +01:00
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
2007-03-08 16:23:49 -05:00
|
|
|
for (i = 0; i < buf->num_points; i++) {
|
2007-08-20 17:32:05 -07:00
|
|
|
if (scalex != CAIRO_FIXED_ONE)
|
|
|
|
|
buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex);
|
|
|
|
|
buf->points[i].x += offx;
|
|
|
|
|
|
|
|
|
|
if (scaley != CAIRO_FIXED_ONE)
|
|
|
|
|
buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley);
|
|
|
|
|
buf->points[i].y += offy;
|
2010-10-28 18:38:50 +02:00
|
|
|
|
|
|
|
|
if (path->fill_maybe_region) {
|
|
|
|
|
path->fill_maybe_region = _cairo_fixed_is_integer (buf->points[i].x) &&
|
|
|
|
|
_cairo_fixed_is_integer (buf->points[i].y);
|
|
|
|
|
}
|
2006-05-04 01:45:41 -07:00
|
|
|
}
|
2009-07-05 14:37:02 +01:00
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
2010-01-22 15:54:45 +00:00
|
|
|
|
2010-10-28 18:38:50 +02:00
|
|
|
path->fill_maybe_region &= path->fill_is_rectilinear;
|
|
|
|
|
|
2010-01-22 15:54:45 +00:00
|
|
|
path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx;
|
|
|
|
|
path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx;
|
|
|
|
|
path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy;
|
|
|
|
|
path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy;
|
2006-05-04 01:45:41 -07:00
|
|
|
}
|
|
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
path->last_move_point.x += offx;
|
2010-01-22 15:54:45 +00:00
|
|
|
path->last_move_point.y += offy;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
path->current_point.x += offx;
|
2010-01-22 15:54:45 +00:00
|
|
|
path->current_point.y += offy;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
|
2010-10-22 22:19:48 +02:00
|
|
|
path->fill_maybe_region = TRUE;
|
|
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
2010-10-22 22:19:48 +02:00
|
|
|
for (i = 0; i < buf->num_points; i++) {
|
|
|
|
|
buf->points[i].x += offx;
|
|
|
|
|
buf->points[i].y += offy;
|
|
|
|
|
|
|
|
|
|
if (path->fill_maybe_region) {
|
|
|
|
|
path->fill_maybe_region = _cairo_fixed_is_integer (buf->points[i].x) &&
|
|
|
|
|
_cairo_fixed_is_integer (buf->points[i].y);
|
|
|
|
|
}
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
}
|
|
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
2010-01-22 15:54:45 +00:00
|
|
|
|
2010-10-22 22:19:48 +02:00
|
|
|
path->fill_maybe_region &= path->fill_is_rectilinear;
|
|
|
|
|
|
2010-01-22 15:54:45 +00:00
|
|
|
path->extents.p1.x += offx;
|
|
|
|
|
path->extents.p1.y += offy;
|
|
|
|
|
path->extents.p2.x += offx;
|
|
|
|
|
path->extents.p2.y += offy;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
}
|
|
|
|
|
|
2010-10-21 17:25:46 +02:00
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
_cairo_path_fixed_transform_point (cairo_point_t *p,
|
|
|
|
|
const cairo_matrix_t *matrix)
|
|
|
|
|
{
|
|
|
|
|
double dx, dy;
|
|
|
|
|
|
|
|
|
|
dx = _cairo_fixed_to_double (p->x);
|
|
|
|
|
dy = _cairo_fixed_to_double (p->y);
|
|
|
|
|
cairo_matrix_transform_point (matrix, &dx, &dy);
|
|
|
|
|
p->x = _cairo_fixed_from_double (dx);
|
|
|
|
|
p->y = _cairo_fixed_from_double (dy);
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-10 00:12:51 -07:00
|
|
|
/**
|
2008-05-13 16:10:28 -04:00
|
|
|
* _cairo_path_fixed_transform:
|
2006-06-10 00:12:51 -07:00
|
|
|
* @path: a #cairo_path_fixed_t to be transformed
|
2008-05-13 16:10:28 -04:00
|
|
|
* @matrix: a #cairo_matrix_t
|
2006-06-10 00:12:51 -07:00
|
|
|
*
|
2008-05-13 16:10:28 -04:00
|
|
|
* Transform the fixed-point path according to the given matrix.
|
|
|
|
|
* There is a fast path for the case where @matrix has no rotation
|
|
|
|
|
* or shear.
|
2006-06-10 00:12:51 -07:00
|
|
|
**/
|
2006-05-04 01:45:41 -07:00
|
|
|
void
|
2008-05-13 16:10:28 -04:00
|
|
|
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
const cairo_matrix_t *matrix)
|
2006-05-04 01:45:41 -07:00
|
|
|
{
|
2010-10-22 23:16:21 +02:00
|
|
|
cairo_box_t extents;
|
2010-10-21 17:25:46 +02:00
|
|
|
cairo_point_t point;
|
2008-05-13 16:10:28 -04:00
|
|
|
cairo_path_buf_t *buf;
|
2008-11-28 17:12:03 +00:00
|
|
|
unsigned int i;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
|
2008-05-13 16:10:28 -04:00
|
|
|
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
|
|
|
|
|
/* Fast path for the common case of scale+transform */
|
2010-10-21 17:11:48 +02:00
|
|
|
_cairo_path_fixed_offset_and_scale (path,
|
|
|
|
|
_cairo_fixed_from_double (matrix->x0),
|
|
|
|
|
_cairo_fixed_from_double (matrix->y0),
|
|
|
|
|
_cairo_fixed_from_double (matrix->xx),
|
|
|
|
|
_cairo_fixed_from_double (matrix->yy));
|
2008-05-13 16:10:28 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-21 17:25:46 +02:00
|
|
|
_cairo_path_fixed_transform_point (&path->last_move_point, matrix);
|
|
|
|
|
_cairo_path_fixed_transform_point (&path->current_point, matrix);
|
2008-05-13 16:10:28 -04:00
|
|
|
|
2010-10-21 17:25:46 +02:00
|
|
|
buf = cairo_path_head (path);
|
|
|
|
|
if (buf->num_points == 0)
|
|
|
|
|
return;
|
2008-05-13 16:10:28 -04:00
|
|
|
|
2010-10-22 23:16:21 +02:00
|
|
|
extents = path->extents;
|
2010-10-21 17:25:46 +02:00
|
|
|
point = buf->points[0];
|
|
|
|
|
_cairo_path_fixed_transform_point (&point, matrix);
|
|
|
|
|
_cairo_box_set (&path->extents, &point, &point);
|
2010-01-22 15:54:45 +00:00
|
|
|
|
2010-10-21 17:25:46 +02:00
|
|
|
cairo_path_foreach_buf_start (buf, path) {
|
|
|
|
|
for (i = 0; i < buf->num_points; i++) {
|
|
|
|
|
_cairo_path_fixed_transform_point (&buf->points[i], matrix);
|
|
|
|
|
_cairo_box_add_point (&path->extents, &buf->points[i]);
|
|
|
|
|
}
|
2009-07-05 14:37:02 +01:00
|
|
|
} cairo_path_foreach_buf_end (buf, path);
|
2010-10-21 17:25:46 +02:00
|
|
|
|
2010-10-22 23:16:21 +02:00
|
|
|
if (path->has_curve_to) {
|
|
|
|
|
cairo_bool_t is_tight;
|
|
|
|
|
|
|
|
|
|
_cairo_matrix_transform_bounding_box_fixed (matrix, &extents, &is_tight);
|
|
|
|
|
if (!is_tight) {
|
|
|
|
|
cairo_bool_t has_extents;
|
|
|
|
|
|
|
|
|
|
has_extents = _cairo_path_bounder_extents (path, &extents);
|
|
|
|
|
assert (has_extents);
|
|
|
|
|
}
|
|
|
|
|
path->extents = extents;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-21 17:25:46 +02:00
|
|
|
/* flags might become more strict than needed */
|
|
|
|
|
path->stroke_is_rectilinear = FALSE;
|
|
|
|
|
path->fill_is_rectilinear = FALSE;
|
|
|
|
|
path->fill_is_empty = FALSE;
|
|
|
|
|
path->fill_maybe_region = FALSE;
|
2006-05-04 01:45:41 -07:00
|
|
|
}
|
2007-08-25 20:49:50 +02:00
|
|
|
|
2008-01-19 22:31:10 +00:00
|
|
|
/* Closure for path flattening */
|
|
|
|
|
typedef struct cairo_path_flattener {
|
|
|
|
|
double tolerance;
|
|
|
|
|
cairo_point_t current_point;
|
|
|
|
|
cairo_path_fixed_move_to_func_t *move_to;
|
|
|
|
|
cairo_path_fixed_line_to_func_t *line_to;
|
|
|
|
|
cairo_path_fixed_close_path_func_t *close_path;
|
|
|
|
|
void *closure;
|
|
|
|
|
} cpf_t;
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
2008-12-09 20:44:25 +00:00
|
|
|
_cpf_move_to (void *closure,
|
|
|
|
|
const cairo_point_t *point)
|
2008-01-19 22:31:10 +00:00
|
|
|
{
|
|
|
|
|
cpf_t *cpf = closure;
|
|
|
|
|
|
|
|
|
|
cpf->current_point = *point;
|
|
|
|
|
|
|
|
|
|
return cpf->move_to (cpf->closure, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
2008-12-09 20:44:25 +00:00
|
|
|
_cpf_line_to (void *closure,
|
|
|
|
|
const cairo_point_t *point)
|
2008-01-19 22:31:10 +00:00
|
|
|
{
|
|
|
|
|
cpf_t *cpf = closure;
|
|
|
|
|
|
|
|
|
|
cpf->current_point = *point;
|
|
|
|
|
|
|
|
|
|
return cpf->line_to (cpf->closure, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cpf_curve_to (void *closure,
|
2008-12-09 20:44:25 +00:00
|
|
|
const cairo_point_t *p1,
|
|
|
|
|
const cairo_point_t *p2,
|
|
|
|
|
const cairo_point_t *p3)
|
2008-01-19 22:31:10 +00:00
|
|
|
{
|
|
|
|
|
cpf_t *cpf = closure;
|
|
|
|
|
cairo_spline_t spline;
|
|
|
|
|
|
|
|
|
|
cairo_point_t *p0 = &cpf->current_point;
|
|
|
|
|
|
2008-11-14 17:18:47 +00:00
|
|
|
if (! _cairo_spline_init (&spline,
|
2011-08-15 09:44:03 +01:00
|
|
|
(cairo_spline_add_point_func_t)cpf->line_to,
|
2008-11-14 17:18:47 +00:00
|
|
|
cpf->closure,
|
|
|
|
|
p0, p1, p2, p3))
|
|
|
|
|
{
|
2009-01-21 12:04:06 +00:00
|
|
|
return _cpf_line_to (closure, p3);
|
2008-01-19 22:31:10 +00:00
|
|
|
}
|
|
|
|
|
|
2008-11-14 17:18:47 +00:00
|
|
|
cpf->current_point = *p3;
|
2008-01-19 22:31:10 +00:00
|
|
|
|
2008-12-09 20:15:34 +00:00
|
|
|
return _cairo_spline_decompose (&spline, cpf->tolerance);
|
2008-01-19 22:31:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_status_t
|
|
|
|
|
_cpf_close_path (void *closure)
|
|
|
|
|
{
|
|
|
|
|
cpf_t *cpf = closure;
|
|
|
|
|
|
|
|
|
|
return cpf->close_path (cpf->closure);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_status_t
|
2008-05-09 13:13:15 +02:00
|
|
|
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
|
2008-01-19 22:31:10 +00:00
|
|
|
cairo_path_fixed_move_to_func_t *move_to,
|
|
|
|
|
cairo_path_fixed_line_to_func_t *line_to,
|
|
|
|
|
cairo_path_fixed_close_path_func_t *close_path,
|
|
|
|
|
void *closure,
|
|
|
|
|
double tolerance)
|
|
|
|
|
{
|
|
|
|
|
cpf_t flattener;
|
|
|
|
|
|
2009-07-05 09:09:42 +01:00
|
|
|
if (! path->has_curve_to) {
|
2010-12-09 22:00:01 +01:00
|
|
|
return _cairo_path_fixed_interpret (path,
|
2008-09-12 19:32:12 +03:00
|
|
|
move_to,
|
|
|
|
|
line_to,
|
|
|
|
|
NULL,
|
|
|
|
|
close_path,
|
|
|
|
|
closure);
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-19 22:31:10 +00:00
|
|
|
flattener.tolerance = tolerance;
|
|
|
|
|
flattener.move_to = move_to;
|
|
|
|
|
flattener.line_to = line_to;
|
|
|
|
|
flattener.close_path = close_path;
|
|
|
|
|
flattener.closure = closure;
|
2010-12-09 22:00:01 +01:00
|
|
|
return _cairo_path_fixed_interpret (path,
|
2008-01-19 22:31:10 +00:00
|
|
|
_cpf_move_to,
|
|
|
|
|
_cpf_line_to,
|
|
|
|
|
_cpf_curve_to,
|
|
|
|
|
_cpf_close_path,
|
|
|
|
|
&flattener);
|
|
|
|
|
}
|
2008-02-25 21:06:23 -05:00
|
|
|
|
2009-08-29 08:02:52 +01:00
|
|
|
static inline void
|
|
|
|
|
_canonical_box (cairo_box_t *box,
|
|
|
|
|
const cairo_point_t *p1,
|
|
|
|
|
const cairo_point_t *p2)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-14 11:26:56 +00:00
|
|
|
/*
|
2008-02-25 21:06:23 -05:00
|
|
|
* Check whether the given path contains a single rectangle.
|
|
|
|
|
*/
|
|
|
|
|
cairo_bool_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
|
2008-02-25 21:06:23 -05:00
|
|
|
cairo_box_t *box)
|
|
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
const cairo_path_buf_t *buf = cairo_path_head (path);
|
2008-02-25 21:06:23 -05:00
|
|
|
|
2010-10-28 17:56:37 +02:00
|
|
|
if (! path->fill_is_rectilinear)
|
2009-07-05 09:09:42 +01:00
|
|
|
return FALSE;
|
|
|
|
|
|
2008-02-25 21:06:23 -05:00
|
|
|
/* Do we have the right number of ops? */
|
2009-08-26 23:32:34 +01:00
|
|
|
if (buf->num_ops < 4 || buf->num_ops > 6)
|
2008-02-25 21:06:23 -05:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Check whether the ops are those that would be used for a rectangle */
|
|
|
|
|
if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
|
|
|
|
|
buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
|
|
|
|
|
buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
|
|
|
|
|
buf->op[3] != CAIRO_PATH_OP_LINE_TO)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-26 23:32:34 +01:00
|
|
|
/* we accept an implicit close for filled paths */
|
|
|
|
|
if (buf->num_ops > 4) {
|
|
|
|
|
/* Now, there are choices. The rectangle might end with a LINE_TO
|
|
|
|
|
* (to the original point), but this isn't required. If it
|
|
|
|
|
* doesn't, then it must end with a CLOSE_PATH. */
|
|
|
|
|
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
|
|
|
|
|
if (buf->points[4].x != buf->points[0].x ||
|
|
|
|
|
buf->points[4].y != buf->points[0].y)
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
|
2008-02-25 21:06:23 -05:00
|
|
|
return FALSE;
|
2009-08-26 23:32:34 +01:00
|
|
|
}
|
2008-02-25 21:06:23 -05:00
|
|
|
|
2009-08-26 23:32:34 +01:00
|
|
|
if (buf->num_ops == 6) {
|
|
|
|
|
/* A trailing CLOSE_PATH or MOVE_TO is ok */
|
|
|
|
|
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
|
|
|
|
|
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2008-02-25 21:06:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ok, we may have a box, if the points line up */
|
|
|
|
|
if (buf->points[0].y == buf->points[1].y &&
|
|
|
|
|
buf->points[1].x == buf->points[2].x &&
|
|
|
|
|
buf->points[2].y == buf->points[3].y &&
|
|
|
|
|
buf->points[3].x == buf->points[0].x)
|
|
|
|
|
{
|
2009-08-29 08:02:52 +01:00
|
|
|
_canonical_box (box, &buf->points[0], &buf->points[2]);
|
2008-02-25 21:06:23 -05:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buf->points[0].x == buf->points[1].x &&
|
|
|
|
|
buf->points[1].y == buf->points[2].y &&
|
|
|
|
|
buf->points[2].x == buf->points[3].x &&
|
|
|
|
|
buf->points[3].y == buf->points[0].y)
|
|
|
|
|
{
|
2009-08-29 08:02:52 +01:00
|
|
|
_canonical_box (box, &buf->points[0], &buf->points[2]);
|
2008-02-25 21:06:23 -05:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2008-02-26 23:17:04 +10:30
|
|
|
|
2011-07-30 17:28:21 +01:00
|
|
|
cairo_bool_t
|
|
|
|
|
_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
|
|
|
|
|
cairo_box_t *box)
|
|
|
|
|
{
|
|
|
|
|
const cairo_path_buf_t *buf = cairo_path_head (path);
|
|
|
|
|
|
|
|
|
|
if (! path->fill_is_rectilinear)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Do we have the right number of ops? */
|
|
|
|
|
if (buf->num_ops != 5)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Check whether the ops are those that would be used for a rectangle */
|
|
|
|
|
if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
|
|
|
|
|
buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
|
|
|
|
|
buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
|
|
|
|
|
buf->op[3] != CAIRO_PATH_OP_LINE_TO ||
|
|
|
|
|
buf->op[4] != 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 &&
|
|
|
|
|
buf->points[1].x == buf->points[2].x &&
|
|
|
|
|
buf->points[2].y == buf->points[3].y &&
|
|
|
|
|
buf->points[3].x == buf->points[0].x)
|
|
|
|
|
{
|
|
|
|
|
_canonical_box (box, &buf->points[0], &buf->points[2]);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buf->points[0].x == buf->points[1].x &&
|
|
|
|
|
buf->points[1].y == buf->points[2].y &&
|
|
|
|
|
buf->points[2].x == buf->points[3].x &&
|
|
|
|
|
buf->points[3].y == buf->points[0].y)
|
|
|
|
|
{
|
|
|
|
|
_canonical_box (box, &buf->points[0], &buf->points[2]);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-10 00:57:44 +02:00
|
|
|
/*
|
2008-02-26 23:17:04 +10:30
|
|
|
* Check whether the given path contains a single rectangle
|
|
|
|
|
* that is logically equivalent to:
|
2008-06-01 19:14:13 -04:00
|
|
|
* <informalexample><programlisting>
|
2008-02-26 23:17:04 +10:30
|
|
|
* cairo_move_to (cr, x, y);
|
|
|
|
|
* cairo_rel_line_to (cr, width, 0);
|
|
|
|
|
* cairo_rel_line_to (cr, 0, height);
|
|
|
|
|
* cairo_rel_line_to (cr, -width, 0);
|
|
|
|
|
* cairo_close_path (cr);
|
2008-06-01 19:14:13 -04:00
|
|
|
* </programlisting></informalexample>
|
2008-02-26 23:17:04 +10:30
|
|
|
*/
|
|
|
|
|
cairo_bool_t
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
|
2008-02-26 23:17:04 +10:30
|
|
|
cairo_box_t *box)
|
|
|
|
|
{
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
const cairo_path_buf_t *buf;
|
2008-02-26 23:17:04 +10:30
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
if (! _cairo_path_fixed_is_box (path, box))
|
2008-02-26 23:17:04 +10:30
|
|
|
return FALSE;
|
|
|
|
|
|
2011-03-08 10:26:06 +01:00
|
|
|
/* This check is valid because the current implementation of
|
|
|
|
|
* _cairo_path_fixed_is_box () only accepts rectangles like:
|
|
|
|
|
* move,line,line,line[,line|close[,close|move]]. */
|
2009-07-05 14:37:02 +01:00
|
|
|
buf = cairo_path_head (path);
|
2011-03-08 10:26:06 +01:00
|
|
|
if (buf->num_ops > 4)
|
2008-02-26 23:17:04 +10:30
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2008-11-25 11:52:01 +00:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
const cairo_path_fixed_t *path)
|
2008-11-25 11:52:01 +00:00
|
|
|
{
|
2009-07-29 15:36:25 +01:00
|
|
|
iter->first = iter->buf = cairo_path_head (path);
|
2008-11-25 11:52:01 +00:00
|
|
|
iter->n_op = 0;
|
|
|
|
|
iter->n_point = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cairo_bool_t
|
|
|
|
|
_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
|
|
|
|
|
{
|
2008-11-28 17:12:03 +00:00
|
|
|
if (++iter->n_op >= iter->buf->num_ops) {
|
2009-07-05 14:37:02 +01:00
|
|
|
iter->buf = cairo_path_buf_next (iter->buf);
|
2009-07-29 15:36:25 +01:00
|
|
|
if (iter->buf == iter->first) {
|
|
|
|
|
iter->buf = NULL;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-25 11:52:01 +00:00
|
|
|
iter->n_op = 0;
|
|
|
|
|
iter->n_point = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-29 15:36:25 +01:00
|
|
|
return TRUE;
|
2008-11-25 11:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_bool_t
|
2008-11-25 17:23:33 +00:00
|
|
|
_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
|
|
|
|
|
cairo_box_t *box)
|
2008-11-25 11:52:01 +00:00
|
|
|
{
|
|
|
|
|
cairo_point_t points[5];
|
|
|
|
|
cairo_path_fixed_iter_t iter;
|
|
|
|
|
|
|
|
|
|
if (_iter->buf == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
iter = *_iter;
|
|
|
|
|
|
2011-08-09 15:15:41 +01:00
|
|
|
if (iter.n_op == iter.buf->num_ops && ! _cairo_path_fixed_iter_next_op (&iter))
|
2008-11-28 17:12:03 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
2008-11-25 11:52:01 +00:00
|
|
|
/* Check whether the ops are those that would be used for a rectangle */
|
|
|
|
|
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO)
|
|
|
|
|
return FALSE;
|
|
|
|
|
points[0] = iter.buf->points[iter.n_point++];
|
|
|
|
|
if (! _cairo_path_fixed_iter_next_op (&iter))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
|
|
|
|
|
return FALSE;
|
|
|
|
|
points[1] = iter.buf->points[iter.n_point++];
|
|
|
|
|
if (! _cairo_path_fixed_iter_next_op (&iter))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2011-08-09 15:15:41 +01:00
|
|
|
/* a horizontal/vertical closed line is also a degenerate rectangle */
|
|
|
|
|
switch (iter.buf->op[iter.n_op]) {
|
|
|
|
|
case CAIRO_PATH_OP_CLOSE_PATH:
|
|
|
|
|
_cairo_path_fixed_iter_next_op (&iter);
|
|
|
|
|
case CAIRO_PATH_OP_MOVE_TO: /* implicit close */
|
|
|
|
|
box->p1 = box->p2 = points[0];
|
|
|
|
|
*_iter = iter;
|
|
|
|
|
return TRUE;
|
|
|
|
|
default:
|
2008-11-25 11:52:01 +00:00
|
|
|
return FALSE;
|
2011-08-09 15:15:41 +01:00
|
|
|
case CAIRO_PATH_OP_LINE_TO:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-25 11:52:01 +00:00
|
|
|
points[2] = iter.buf->points[iter.n_point++];
|
|
|
|
|
if (! _cairo_path_fixed_iter_next_op (&iter))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
|
|
|
|
|
return FALSE;
|
|
|
|
|
points[3] = iter.buf->points[iter.n_point++];
|
|
|
|
|
|
|
|
|
|
/* Now, there are choices. The rectangle might end with a LINE_TO
|
|
|
|
|
* (to the original point), but this isn't required. If it
|
2008-11-25 17:23:33 +00:00
|
|
|
* doesn't, then it must end with a CLOSE_PATH (which may be implicit). */
|
2011-08-09 23:39:07 +01:00
|
|
|
if (! _cairo_path_fixed_iter_next_op (&iter)) {
|
|
|
|
|
/* implicit close due to fill */
|
|
|
|
|
} else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) {
|
2008-11-25 11:52:01 +00:00
|
|
|
points[4] = iter.buf->points[iter.n_point++];
|
|
|
|
|
if (points[4].x != points[0].x || points[4].y != points[0].y)
|
|
|
|
|
return FALSE;
|
2011-08-09 15:15:41 +01:00
|
|
|
_cairo_path_fixed_iter_next_op (&iter);
|
|
|
|
|
} else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH) {
|
|
|
|
|
_cairo_path_fixed_iter_next_op (&iter);
|
|
|
|
|
} else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO) {
|
2011-08-09 23:39:07 +01:00
|
|
|
/* implicit close-path due to new-sub-path */
|
2011-08-09 15:15:41 +01:00
|
|
|
} else {
|
2008-11-25 11:52:01 +00:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ok, we may have a box, if the points line up */
|
|
|
|
|
if (points[0].y == points[1].y &&
|
|
|
|
|
points[1].x == points[2].x &&
|
|
|
|
|
points[2].y == points[3].y &&
|
|
|
|
|
points[3].x == points[0].x)
|
|
|
|
|
{
|
|
|
|
|
box->p1 = points[0];
|
|
|
|
|
box->p2 = points[2];
|
|
|
|
|
*_iter = iter;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (points[0].x == points[1].x &&
|
|
|
|
|
points[1].y == points[2].y &&
|
|
|
|
|
points[2].x == points[3].x &&
|
|
|
|
|
points[3].y == points[0].y)
|
|
|
|
|
{
|
2009-08-27 16:21:30 +01:00
|
|
|
box->p1 = points[1];
|
|
|
|
|
box->p2 = points[3];
|
2008-11-25 11:52:01 +00:00
|
|
|
*_iter = iter;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cairo_bool_t
|
|
|
|
|
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
|
|
|
|
|
{
|
|
|
|
|
if (iter->buf == NULL)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2010-10-21 17:24:30 +02:00
|
|
|
return iter->n_op == iter->buf->num_ops;
|
2008-11-25 11:52:01 +00:00
|
|
|
}
|