Bug 562746. Update cairo to 1.10.

A lot of changes from upstream here that will hopefully be smoothed
out a bit soon.
This commit is contained in:
Jeff Muizelaar 2011-03-10 14:52:15 -05:00
parent 366a527a30
commit f30c726d3a
214 changed files with 25105 additions and 11735 deletions

View File

@ -8407,6 +8407,7 @@ if test "$MOZ_TREE_CAIRO"; then
AC_DEFINE(HAVE_UINT64_T)
# Define macros for cairo-features.h
TEE_SURFACE_FEATURE="#define CAIRO_HAS_TEE_SURFACE 1"
if test "$MOZ_X11"; then
XLIB_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_SURFACE 1"
XLIB_XRENDER_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1"
@ -8489,6 +8490,7 @@ if test "$MOZ_TREE_CAIRO"; then
AC_SUBST(QUARTZ_FONT_FEATURE)
AC_SUBST(PNG_FUNCTIONS_FEATURE)
AC_SUBST(QT_SURFACE_FEATURE)
AC_SUBST(TEE_SURFACE_FEATURE)
MOZ_CAIRO_LIBS='$(call EXPAND_LIBNAME_PATH,mozcairo,$(DEPTH)/gfx/cairo/cairo/src)'" $CAIRO_FT_LIBS"

View File

@ -70,20 +70,25 @@ CSRCS = \
cairo-arc.c \
cairo-array.c \
cairo-atomic.c \
cairo-base64-stream.c \
cairo-bentley-ottmann.c \
cairo-bentley-ottmann-rectilinear.c \
cairo-bentley-ottmann-rectangular.c \
cairo-base64-stream.c \
cairo-botor-scan-converter.c \
cairo-boxes.c \
cairo-cache.c \
cairo-clip.c \
cairo-color.c \
cairo-composite-rectangles.c \
cairo-debug.c \
cairo-deflate-stream.c \
cairo-device.c \
cairo-fixed.c \
cairo-font-face.c \
cairo-font-face-twin.c \
cairo-font-face-twin-data.c \
cairo-font-options.c \
cairo-freed-pool.c \
cairo-freelist.c \
cairo-gstate.c \
cairo-hash.c \
@ -94,6 +99,7 @@ CSRCS = \
cairo-matrix.c \
cairo-misc.c \
cairo-mutex.c \
cairo-observer.c \
cairo-output-stream.c \
cairo-paginated-surface.c \
cairo-path.c \
@ -107,6 +113,7 @@ CSRCS = \
cairo-polygon.c \
cairo-recording-surface.c \
cairo-rectangle.c \
cairo-rectangular-scan-converter.c \
cairo-region.c \
cairo-scaled-font.c \
cairo-scaled-font-subsets.c \
@ -117,6 +124,9 @@ CSRCS = \
cairo-surface.c \
cairo-surface-clipper.c \
cairo-surface-fallback.c \
cairo-surface-offset.c \
cairo-surface-snapshot.c \
cairo-surface-subsurface.c \
cairo-surface-wrapper.c \
cairo-tee-surface.c \
cairo-tor-scan-converter.c \
@ -130,7 +140,7 @@ CSRCS = \
EXPORTS_NAMESPACES = cairo
EXPORTS_cairo = cairo.h cairo-version.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-rename.h
EXPORTS_cairo = cairo.h cairo-version.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-rename.h cairo-tee.h
# cairo-type1-subset.c should be here, but it's only supported on freetype platforms
@ -153,6 +163,7 @@ PDF_EXPORTS = cairo-pdf.h
PS_EXPORTS = cairo-ps.h
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
DEFINES += -DDISABLE_SOME_FLOATING_POINT
CSRCS += cairo-win32-surface.c
ifndef WINCE
@ -269,3 +280,4 @@ endif
cairo-features.h: $(srcdir)/cairo-features.h.in $(GLOBAL_DEPS)
$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) ./$@
cat cairo-dwrite-font.i | gzip | python -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)"

View File

@ -11,7 +11,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,6 +37,8 @@
#include "cairoint.h"
CAIRO_BEGIN_DECLS
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target);
@ -71,4 +73,6 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
CAIRO_END_DECLS
#endif /* CAIRO_ANALYSIS_SURFACE_H */

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,8 +37,10 @@
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-region-private.h"
typedef struct {
@ -99,10 +101,11 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
cairo_status_t status;
cairo_surface_t *source;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (_cairo_surface_is_recording (surface_pattern->surface));
assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
@ -114,8 +117,13 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
status = _cairo_recording_surface_replay_and_create_regions (surface_pattern->surface,
&surface->base);
source = surface_pattern->surface;
if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
source = sub->target;
}
status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base);
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
@ -396,9 +404,9 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@ -716,7 +724,9 @@ _cairo_analysis_surface_create (cairo_surface_t *target)
/* I believe the content type here is truly arbitrary. I'm quite
* sure nothing will ever use this value. */
_cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_analysis_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
cairo_matrix_init_identity (&surface->ctm);
@ -831,9 +841,9 @@ typedef cairo_int_status_t
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
@ -906,7 +916,10 @@ _cairo_null_surface_create (cairo_content_t content)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (surface, &cairo_null_surface_backend, content);
_cairo_surface_init (surface,
&cairo_null_surface_backend,
NULL, /* device */
content);
return surface;
}

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -36,6 +36,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
/**
* _cairo_array_init:
@ -260,7 +261,7 @@ _cairo_array_append (cairo_array_t *array,
}
/**
* _cairo_array_append:
* _cairo_array_append_multiple:
* @array: a #cairo_array_t
*
* Append one or more items onto the array by growing the array by

View File

@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
* Copyright © 2010 Andrea Canciani
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -12,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -32,6 +33,7 @@
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Andrea Canciani <ranma42@gmail.com>
*/
#ifndef CAIRO_ATOMIC_PRIVATE_H
@ -57,12 +59,29 @@ CAIRO_BEGIN_DECLS
typedef int cairo_atomic_int_t;
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x)
{
__sync_synchronize ();
return *x;
}
static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
__sync_synchronize ();
return *x;
}
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_set(x, value) ((*x) = value)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef int cairo_atomic_intptr_t;
@ -75,7 +94,10 @@ typedef long long cairo_atomic_intptr_t;
#endif
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
(void*)__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
__sync_bool_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
# define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
_cairo_atomic_intptr_to_voidptr (__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv))
#endif
@ -87,11 +109,10 @@ typedef long long cairo_atomic_intptr_t;
typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_set(x, value) (AO_store_full (x))
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) ((cairo_atomic_int_t) AO_compare_and_swap_full(x, oldv, newv) ? oldv : *x)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
@ -103,45 +124,129 @@ typedef unsigned long long cairo_atomic_intptr_t;
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x))
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
(void*) (cairo_atomic_intptr_t) _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
_cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
#endif
#if HAVE_OS_ATOMIC_OPS
#include <libkern/OSAtomic.h>
#define HAS_ATOMIC_OPS 1
typedef int32_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
# define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
#if SIZEOF_VOID_P==4
typedef int32_t cairo_atomic_intptr_t;
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
OSAtomicCompareAndSwap32Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
#elif SIZEOF_VOID_P==8
typedef int64_t cairo_atomic_intptr_t;
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
OSAtomicCompareAndSwap64Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
#else
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_get(x) (OSMemoryBarrier(), *(x))
#endif
#ifndef HAS_ATOMIC_OPS
typedef int cairo_atomic_int_t;
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
typedef unsigned long cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
typedef unsigned long long cairo_atomic_intptr_t;
#else
#error No matching integer pointer type
#endif
typedef cairo_atomic_intptr_t cairo_atomic_int_t;
cairo_private void
_cairo_atomic_int_inc (int *x);
_cairo_atomic_int_inc (cairo_atomic_int_t *x);
cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x);
_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);
cairo_private int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv);
cairo_private cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv);
cairo_private void *
_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv);
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_impl (x, oldv, newv)
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_impl (x, oldv, newv)
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
# include "cairo-compiler-private.h"
cairo_private int
_cairo_atomic_int_get (int *x);
cairo_private void
_cairo_atomic_int_set (int *x, int value);
cairo_private cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x);
# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_set(x, value) ((*x) = value)
/* Workaround GCC complaining about casts */
static cairo_always_inline void *
_cairo_atomic_intptr_to_voidptr (cairo_atomic_intptr_t x)
{
return (void *) x;
}
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_fallback(cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv)
{
cairo_atomic_int_t curr;
do {
curr = _cairo_atomic_int_get (x);
} while (curr == oldv && !_cairo_atomic_int_cmpxchg (x, oldv, newv));
return curr;
}
static cairo_always_inline void *
_cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
{
void *curr;
do {
curr = _cairo_atomic_ptr_get (x);
} while (curr == oldv && !_cairo_atomic_ptr_cmpxchg (x, oldv, newv));
return curr;
}
#endif
#ifndef _cairo_atomic_int_cmpxchg_return_old
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
#ifndef _cairo_atomic_ptr_cmpxchg_return_old
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
#ifndef _cairo_atomic_int_cmpxchg
#define _cairo_atomic_int_cmpxchg(x, oldv, newv) (_cairo_atomic_int_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
#ifndef _cairo_atomic_ptr_cmpxchg
#define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (_cairo_atomic_ptr_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
#define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -42,7 +42,7 @@ COMPILE_TIME_ASSERT(sizeof(void*) == sizeof(int) ||
sizeof(void*) == sizeof(long long));
#else
void
_cairo_atomic_int_inc (int *x)
_cairo_atomic_int_inc (cairo_atomic_intptr_t *x)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x += 1;
@ -50,7 +50,7 @@ _cairo_atomic_int_inc (int *x)
}
cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x)
_cairo_atomic_int_dec_and_test (cairo_atomic_intptr_t *x)
{
cairo_bool_t ret;
@ -61,10 +61,10 @@ _cairo_atomic_int_dec_and_test (int *x)
return ret;
}
int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv)
cairo_atomic_intptr_t
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t oldv, cairo_atomic_intptr_t newv)
{
int ret;
cairo_atomic_intptr_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
@ -76,7 +76,7 @@ _cairo_atomic_int_cmpxchg (int *x, int oldv, int newv)
}
void *
_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv)
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv)
{
void *ret;
@ -88,13 +88,12 @@ _cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv)
return ret;
}
#endif
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
int
_cairo_atomic_int_get (int *x)
cairo_atomic_intptr_t
_cairo_atomic_int_get (cairo_atomic_intptr_t *x)
{
int ret;
cairo_atomic_intptr_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
@ -102,12 +101,6 @@ _cairo_atomic_int_get (int *x)
return ret;
}
void
_cairo_atomic_int_set (int *x, int value)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x = value;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
#endif
#endif

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,6 +37,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base64_stream {

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,6 +35,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base85_stream {

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -38,7 +38,9 @@
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-combsort-private.h"
#include "cairo-error-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
@ -215,20 +217,33 @@ edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
cairo_bool_t do_traps,
void *container)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
_cairo_traps_add_trap (traps,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
if (do_traps) {
_cairo_traps_add_trap (container,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
status = _cairo_traps_status ((cairo_traps_t *) container);
} else {
cairo_box_t box;
box.p1.x = left->edge.line.p1.x;
box.p1.y = trap->top;
box.p2.x = trap->right->edge.line.p1.x;
box.p2.y = bot;
status = _cairo_boxes_add (container, &box);
}
}
trap->right = NULL;
return _cairo_traps_status (traps);
return status;
}
/* Start a new trapezoid at the given top y coordinate, whose edges
@ -240,7 +255,8 @@ static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
cairo_bool_t do_traps,
void *container)
{
cairo_status_t status;
@ -255,7 +271,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_bo_edge_end_trap (left, top, traps);
status = _cairo_bo_edge_end_trap (left, top, do_traps, container);
if (unlikely (status))
return status;
}
@ -272,7 +288,8 @@ static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
cairo_bool_t do_traps,
void *container)
{
cairo_bo_edge_t *right;
cairo_status_t status;
@ -303,7 +320,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
@ -321,8 +338,8 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
do_traps, container);
if (unlikely (status))
return status;
@ -337,7 +354,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
@ -358,8 +375,8 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
do_traps, container);
if (unlikely (status))
return status;
@ -376,7 +393,8 @@ static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
cairo_bool_t do_traps,
void *container)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
@ -388,7 +406,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events
if (event->point.y != sweep_line.current_y) {
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
fill_rule, traps);
fill_rule, do_traps, container);
if (unlikely (status))
return status;
@ -406,7 +424,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events
if (event->edge->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (event->edge,
sweep_line.current_y,
traps);
do_traps, container);
if (unlikely (status))
return status;
}
@ -476,7 +494,8 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
}
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule, traps);
fill_rule,
TRUE, traps);
if (events != stack_events)
free (events);
@ -485,6 +504,72 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_status_t status;
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
int num_events;
int i, j;
if (unlikely (polygon->num_edges == 0))
return CAIRO_STATUS_SUCCESS;
num_events = 2 * polygon->num_edges;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
event_ptrs = (cairo_bo_event_t **) (events + num_events);
edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
}
for (i = j = 0; i < polygon->num_edges; i++) {
edges[i].edge = polygon->edges[i];
edges[i].deferred_trap.right = NULL;
edges[i].prev = NULL;
edges[i].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = polygon->edges[i].top;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = polygon->edges[i].bottom;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
}
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
FALSE, boxes);
if (events != stack_events)
free (events);
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
@ -572,7 +657,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
traps);
TRUE, traps);
traps->is_rectilinear = TRUE;
if (events != stack_events)

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -38,6 +38,7 @@
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-combsort-private.h"
@ -129,21 +130,25 @@ static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
cairo_box_t extents;
int n;
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
#if 0
if (traps->has_limits) {
printf ("%s: limits=(%d, %d, %d, %d)\n",
filename,
traps->limits.p1.x, traps->limits.p1.y,
traps->limits.p2.x, traps->limits.p2.y);
}
#endif
_cairo_traps_extents (traps, &extents);
printf ("%s: extents=(%d, %d, %d, %d)\n",
filename,
traps->extents.p1.x, traps->extents.p1.y,
traps->extents.p2.x, traps->extents.p2.y);
extents.p1.x, extents.p1.y,
extents.p2.x, extents.p2.y);
file = fopen (filename, "a");
if (file != NULL) {

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_BOXES_H
#define CAIRO_BOXES_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
struct _cairo_boxes_t {
cairo_status_t status;
cairo_box_t limit;
const cairo_box_t *limits;
int num_limits;
int num_boxes;
unsigned int is_pixel_aligned : 1;
struct _cairo_boxes_chunk {
struct _cairo_boxes_chunk *next;
cairo_box_t *base;
int count;
int size;
} chunks, *tail;
cairo_box_t boxes_embedded[32];
};
cairo_private void
_cairo_boxes_init (cairo_boxes_t *boxes);
cairo_private void
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array,
int num_boxes);
cairo_private void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits);
cairo_private cairo_status_t
_cairo_boxes_add (cairo_boxes_t *boxes,
const cairo_box_t *box);
cairo_private void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_rectangle_int_t *extents);
cairo_private void
_cairo_boxes_clear (cairo_boxes_t *boxes);
cairo_private void
_cairo_boxes_fini (cairo_boxes_t *boxes);
#endif /* CAIRO_BOXES_H */

View File

@ -0,0 +1,300 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
void
_cairo_boxes_init (cairo_boxes_t *boxes)
{
boxes->status = CAIRO_STATUS_SUCCESS;
boxes->num_limits = 0;
boxes->num_boxes = 0;
boxes->tail = &boxes->chunks;
boxes->chunks.next = NULL;
boxes->chunks.base = boxes->boxes_embedded;
boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
boxes->chunks.count = 0;
boxes->is_pixel_aligned = TRUE;
}
void
_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array,
int num_boxes)
{
int n;
boxes->status = CAIRO_STATUS_SUCCESS;
boxes->num_limits = 0;
boxes->num_boxes = num_boxes;
boxes->tail = &boxes->chunks;
boxes->chunks.next = NULL;
boxes->chunks.base = array;
boxes->chunks.size = num_boxes;
boxes->chunks.count = num_boxes;
for (n = 0; n < num_boxes; n++) {
if (! _cairo_fixed_is_integer (array[n].p1.x) ||
! _cairo_fixed_is_integer (array[n].p1.y) ||
! _cairo_fixed_is_integer (array[n].p2.x) ||
! _cairo_fixed_is_integer (array[n].p2.y))
{
break;
}
}
boxes->is_pixel_aligned = n == num_boxes;
}
void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits)
{
int n;
boxes->limits = limits;
boxes->num_limits = num_limits;
if (boxes->num_limits) {
boxes->limit = limits[0];
for (n = 1; n < num_limits; n++) {
if (limits[n].p1.x < boxes->limit.p1.x)
boxes->limit.p1.x = limits[n].p1.x;
if (limits[n].p1.y < boxes->limit.p1.y)
boxes->limit.p1.y = limits[n].p1.y;
if (limits[n].p2.x > boxes->limit.p2.x)
boxes->limit.p2.x = limits[n].p2.x;
if (limits[n].p2.y > boxes->limit.p2.y)
boxes->limit.p2.y = limits[n].p2.y;
}
}
}
static void
_cairo_boxes_add_internal (cairo_boxes_t *boxes,
const cairo_box_t *box)
{
struct _cairo_boxes_chunk *chunk;
if (unlikely (boxes->status))
return;
chunk = boxes->tail;
if (unlikely (chunk->count == chunk->size)) {
int size;
size = chunk->size * 2;
chunk->next = _cairo_malloc_ab_plus_c (size,
sizeof (cairo_box_t),
sizeof (struct _cairo_boxes_chunk));
if (unlikely (chunk->next == NULL)) {
boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return;
}
chunk = chunk->next;
boxes->tail = chunk;
chunk->next = NULL;
chunk->count = 0;
chunk->size = size;
chunk->base = (cairo_box_t *) (chunk + 1);
}
chunk->base[chunk->count++] = *box;
boxes->num_boxes++;
if (boxes->is_pixel_aligned) {
boxes->is_pixel_aligned =
_cairo_fixed_is_integer (box->p1.x) &&
_cairo_fixed_is_integer (box->p1.y) &&
_cairo_fixed_is_integer (box->p2.x) &&
_cairo_fixed_is_integer (box->p2.y);
}
}
cairo_status_t
_cairo_boxes_add (cairo_boxes_t *boxes,
const cairo_box_t *box)
{
if (box->p1.y == box->p2.y)
return CAIRO_STATUS_SUCCESS;
if (box->p1.x == box->p2.x)
return CAIRO_STATUS_SUCCESS;
if (boxes->num_limits) {
cairo_point_t p1, p2;
cairo_bool_t reversed = FALSE;
int n;
/* support counter-clockwise winding for rectangular tessellation */
if (box->p1.x < box->p2.x) {
p1.x = box->p1.x;
p2.x = box->p2.x;
} else {
p2.x = box->p1.x;
p1.x = box->p2.x;
reversed = ! reversed;
}
if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x)
return CAIRO_STATUS_SUCCESS;
if (box->p1.y < box->p2.y) {
p1.y = box->p1.y;
p2.y = box->p2.y;
} else {
p2.y = box->p1.y;
p1.y = box->p2.y;
reversed = ! reversed;
}
if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y)
return CAIRO_STATUS_SUCCESS;
for (n = 0; n < boxes->num_limits; n++) {
const cairo_box_t *limits = &boxes->limits[n];
cairo_box_t _box;
cairo_point_t _p1, _p2;
if (p1.x >= limits->p2.x || p2.x <= limits->p1.x)
continue;
if (p1.y >= limits->p2.y || p2.y <= limits->p1.y)
continue;
/* Otherwise, clip the box to the limits. */
_p1 = p1;
if (_p1.x < limits->p1.x)
_p1.x = limits->p1.x;
if (_p1.y < limits->p1.y)
_p1.y = limits->p1.y;
_p2 = p2;
if (_p2.x > limits->p2.x)
_p2.x = limits->p2.x;
if (_p2.y > limits->p2.y)
_p2.y = limits->p2.y;
if (_p2.y <= _p1.y || _p2.x <= _p1.x)
continue;
_box.p1.y = _p1.y;
_box.p2.y = _p2.y;
if (reversed) {
_box.p1.x = _p2.x;
_box.p2.x = _p1.x;
} else {
_box.p1.x = _p1.x;
_box.p2.x = _p2.x;
}
_cairo_boxes_add_internal (boxes, &_box);
}
} else {
_cairo_boxes_add_internal (boxes, box);
}
return boxes->status;
}
void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_rectangle_int_t *extents)
{
const struct _cairo_boxes_chunk *chunk;
cairo_box_t box;
int i;
box.p1.y = box.p1.x = INT_MAX;
box.p2.y = box.p2.x = INT_MIN;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *b = chunk->base;
for (i = 0; i < chunk->count; i++) {
if (b[i].p1.x < box.p1.x)
box.p1.x = b[i].p1.x;
if (b[i].p1.y < box.p1.y)
box.p1.y = b[i].p1.y;
if (b[i].p2.x > box.p2.x)
box.p2.x = b[i].p2.x;
if (b[i].p2.y > box.p2.y)
box.p2.y = b[i].p2.y;
}
}
_cairo_box_round_to_rectangle (&box, extents);
}
void
_cairo_boxes_clear (cairo_boxes_t *boxes)
{
struct _cairo_boxes_chunk *chunk, *next;
for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
boxes->tail = &boxes->chunks;
boxes->chunks.next = 0;
boxes->chunks.count = 0;
boxes->num_boxes = 0;
boxes->is_pixel_aligned = TRUE;
}
void
_cairo_boxes_fini (cairo_boxes_t *boxes)
{
struct _cairo_boxes_chunk *chunk, *next;
for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
next = chunk->next;
free (chunk);
}
}

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,6 +37,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
@ -174,9 +175,7 @@ _cairo_cache_thaw (cairo_cache_t *cache)
{
assert (cache->freeze_count > 0);
cache->freeze_count--;
if (cache->freeze_count == 0)
if (--cache->freeze_count == 0)
_cairo_cache_shrink_to_accommodate (cache, 0);
}
@ -240,9 +239,6 @@ static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional)
{
if (cache->freeze_count)
return;
while (cache->size + additional > cache->max_size) {
if (! _cairo_cache_remove_random (cache))
return;
@ -267,7 +263,8 @@ _cairo_cache_insert (cairo_cache_t *cache,
{
cairo_status_t status;
_cairo_cache_shrink_to_accommodate (cache, entry->size);
if (entry->size && ! cache->freeze_count)
_cairo_cache_shrink_to_accommodate (cache, entry->size);
status = _cairo_hash_table_insert (cache->hash_table,
(cairo_hash_entry_t *) entry);

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -41,6 +41,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
@ -117,6 +118,7 @@ typedef struct _cairo_cff_font {
cairo_array_t local_sub_index;
int num_glyphs;
cairo_bool_t is_cid;
int units_per_em;
/* CID Font Data */
int *fdselect;
@ -1772,6 +1774,9 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->y_max = (int16_t) be16_to_cpu (head.y_max);
font->ascent = (int16_t) be16_to_cpu (hhea.ascender);
font->descent = (int16_t) be16_to_cpu (hhea.descender);
font->units_per_em = (int16_t) be16_to_cpu (head.units_per_em);
if (font->units_per_em == 0)
font->units_per_em = 1000;
font->font_name = NULL;
status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font,
@ -1955,20 +1960,20 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
cff_subset->font_name = NULL;
}
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
cff_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs);
if (unlikely (cff_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
cff_subset->widths[i] = font->widths[i];
cff_subset->widths[i] = (double)font->widths[i]/font->units_per_em;
cff_subset->x_min = font->x_min;
cff_subset->y_min = font->y_min;
cff_subset->x_max = font->x_max;
cff_subset->y_max = font->y_max;
cff_subset->ascent = font->ascent;
cff_subset->descent = font->descent;
cff_subset->x_min = (double)font->x_min/font->units_per_em;
cff_subset->y_min = (double)font->y_min/font->units_per_em;
cff_subset->x_max = (double)font->x_max/font->units_per_em;
cff_subset->y_max = (double)font->y_max/font->units_per_em;
cff_subset->ascent = (double)font->ascent/font->units_per_em;
cff_subset->descent = (double)font->descent/font->units_per_em;
cff_subset->data = malloc (length);
if (unlikely (cff_subset->data == NULL)) {
@ -2212,21 +2217,21 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
goto fail2;
}
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
cff_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs);
if (unlikely (cff_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
cff_subset->widths[i] = type2_subset.widths[i];
cff_subset->widths[i] = (double)type2_subset.widths[i]/1000;
cff_subset->x_min = type2_subset.x_min;
cff_subset->y_min = type2_subset.y_min;
cff_subset->x_max = type2_subset.x_max;
cff_subset->y_max = type2_subset.y_max;
cff_subset->ascent = type2_subset.y_max;
cff_subset->descent = type2_subset.y_min;
cff_subset->x_min = (double)type2_subset.x_min/1000;
cff_subset->y_min = (double)type2_subset.y_min/1000;
cff_subset->x_max = (double)type2_subset.x_max/1000;
cff_subset->y_max = (double)type2_subset.y_max/1000;
cff_subset->ascent = (double)type2_subset.y_max/1000;
cff_subset->descent = (double)type2_subset.y_min/1000;
cff_subset->data = malloc (length);
if (unlikely (cff_subset->data == NULL)) {

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -76,10 +76,6 @@ struct _cairo_clip {
cairo_private void
_cairo_clip_init (cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_init_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
cairo_private_no_warn cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
@ -91,6 +87,10 @@ _cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
cairo_private cairo_bool_t
_cairo_clip_equal (const cairo_clip_t *clip_a,
const cairo_clip_t *clip_b);
#define _cairo_clip_fini(clip) _cairo_clip_reset (clip)
cairo_private cairo_status_t
@ -112,12 +112,12 @@ cairo_private const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst);
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty);
cairo_private cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents);
int dst_x, int dst_y);
cairo_private cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
@ -128,6 +128,20 @@ _cairo_clip_get_boxes (cairo_clip_t *clip,
cairo_box_t **boxes,
int *count);
cairo_private cairo_status_t
_cairo_clip_to_boxes (cairo_clip_t **clip,
cairo_composite_rectangles_t *extents,
cairo_box_t **boxes,
int *num_boxes);
cairo_private cairo_bool_t
_cairo_clip_contains_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
cairo_private cairo_bool_t
_cairo_clip_contains_extents (cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents);
cairo_private void
_cairo_clip_drop_cache (cairo_clip_t *clip);

View File

@ -15,7 +15,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -41,95 +41,16 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
/* Keep a stash of recently freed clip_paths, since we need to
* reallocate them frequently.
*/
#define MAX_FREED_POOL_SIZE 4
typedef struct {
void *pool[MAX_FREED_POOL_SIZE];
int top;
} freed_pool_t;
#if HAS_FREED_POOL
static freed_pool_t clip_path_pool;
static void *
_atomic_fetch (void **slot)
{
return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
}
static cairo_bool_t
_atomic_store (void **slot, void *ptr)
{
return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL;
}
static void *
_freed_pool_get (freed_pool_t *pool)
{
void *ptr;
int i;
i = pool->top - 1;
if (i < 0)
i = 0;
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
pool->top = i;
return ptr;
}
/* either empty or contended */
for (i = ARRAY_LENGTH (pool->pool); i--;) {
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
pool->top = i;
return ptr;
}
}
/* empty */
pool->top = 0;
return NULL;
}
static void
_freed_pool_put (freed_pool_t *pool, void *ptr)
{
int i = pool->top;
if (_atomic_store (&pool->pool[i], ptr)) {
pool->top = i + 1;
return;
}
/* either full or contended */
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], ptr)) {
pool->top = i + 1;
return;
}
}
/* full */
pool->top = ARRAY_LENGTH (pool->pool);
free (ptr);
}
static void
_freed_pool_reset (freed_pool_t *pool)
{
int i;
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
free (pool->pool[i]);
pool->pool[i] = NULL;
}
}
#endif
static cairo_clip_path_t *
_cairo_clip_path_create (cairo_clip_t *clip)
@ -158,9 +79,6 @@ _cairo_clip_path_create (cairo_clip_t *clip)
static cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
{
if (clip_path == NULL)
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
_cairo_reference_count_inc (&clip_path->ref_count);
@ -247,47 +165,40 @@ _cairo_clip_intersect_rectangle (cairo_clip_t *clip,
status = _cairo_path_fixed_close_path (&clip_path->path);
assert (status == CAIRO_STATUS_SUCCESS);
clip_path->extents = *rect;
clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
clip_path->tolerance = 1;
clip_path->antialias = CAIRO_ANTIALIAS_NONE;
clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT;
clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
clip_path->extents = *rect;
if (clip_path->prev != NULL) {
if (! _cairo_rectangle_intersect (&clip_path->extents,
&clip_path->prev->extents))
{
_cairo_clip_set_all_clipped (clip);
}
}
/* could preallocate the region if it proves worthwhile */
return CAIRO_STATUS_SUCCESS;
}
/* XXX consider accepting a matrix, no users yet. */
cairo_status_t
_cairo_clip_init_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect)
{
_cairo_clip_init (clip);
if (rect == NULL)
return CAIRO_STATUS_SUCCESS;
if (rect->width == 0 || rect->height == 0) {
_cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
return _cairo_clip_intersect_rectangle (clip, rect);
}
cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
{
if (other != NULL) {
clip->all_clipped = other->all_clipped;
clip->path = _cairo_clip_path_reference (other->path);
/* this guy is here because of the weird return semantics of _cairo_clip_init_copy */
if (!other->path)
return NULL;
if (other->path == NULL) {
clip->path = NULL;
if (! clip->all_clipped)
clip = NULL;
} else {
clip->path = _cairo_clip_path_reference (other->path);
}
} else {
_cairo_clip_init (clip);
clip = NULL;
}
return clip;
@ -318,9 +229,8 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
if (clip->path != NULL) {
if (clip->path->fill_rule == fill_rule &&
(path->is_rectilinear ||
(tolerance == clip->path->tolerance &&
antialias == clip->path->antialias)) &&
(path->is_rectilinear || tolerance == clip->path->tolerance) &&
antialias == clip->path->antialias &&
_cairo_path_fixed_equal (&clip->path->path, path))
{
return CAIRO_STATUS_SUCCESS;
@ -372,6 +282,38 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_clip_equal (const cairo_clip_t *clip_a,
const cairo_clip_t *clip_b)
{
const cairo_clip_path_t *clip_path_a, *clip_path_b;
clip_path_a = clip_a->path;
clip_path_b = clip_b->path;
while (clip_path_a && clip_path_b) {
if (clip_path_a == clip_path_b)
return TRUE;
if (clip_path_a->fill_rule != clip_path_b->fill_rule)
return FALSE;
if (clip_path_a->tolerance != clip_path_b->tolerance)
return FALSE;
if (clip_path_a->antialias != clip_path_b->antialias)
return FALSE;
if (! _cairo_path_fixed_equal (&clip_path_a->path, &clip_path_b->path))
return FALSE;
clip_path_a = clip_path_a->prev;
clip_path_b = clip_path_b->prev;
}
return clip_path_a == clip_path_b; /* ie both NULL */
}
cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
@ -409,7 +351,7 @@ _cairo_clip_rectangle (cairo_clip_t *clip,
if (clip->path != NULL) {
if (rectangle->x <= clip->path->extents.x &&
rectangle->y <= clip->path->extents.y &&
rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
{
return CAIRO_STATUS_SUCCESS;
@ -443,6 +385,7 @@ _cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip,
status = _cairo_path_fixed_init_copy (&clip_path->path,
&other_path->path);
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
@ -485,6 +428,7 @@ _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip,
status = _cairo_path_fixed_init_copy (&clip_path->path,
&other_path->path);
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
@ -500,6 +444,13 @@ _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip,
clip_path->flags = other_path->flags;
if (other_path->region != NULL) {
clip_path->region = cairo_region_copy (other_path->region);
status = clip_path->region->status;
if (unlikely (status)) {
clip->path = clip->path->prev;
_cairo_clip_path_destroy (clip_path);
return status;
}
cairo_region_translate (clip_path->region, tx, ty);
}
clip_path->surface = cairo_surface_reference (other_path->surface);
@ -997,104 +948,73 @@ _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_combine_region (cairo_surface_t *surface,
const cairo_region_t *region,
const cairo_rectangle_int_t *extents)
{
cairo_region_t clear_region;
cairo_status_t status;
_cairo_region_init_rectangle (&clear_region, extents);
status = cairo_region_subtract (&clear_region, region);
if (unlikely (status))
return status;
if (! cairo_region_is_empty (&clear_region)) {
cairo_region_translate (&clear_region, -extents->x, -extents->y);
status = _cairo_surface_fill_region (surface,
CAIRO_OPERATOR_CLEAR,
CAIRO_COLOR_TRANSPARENT,
&clear_region);
}
_cairo_region_fini (&clear_region);
return status;
}
static cairo_surface_t *
_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
cairo_surface_t *target)
cairo_surface_t *target,
int *tx, int *ty)
{
cairo_surface_t *surface;
cairo_pattern_union_t pattern;
cairo_status_t status;
const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
cairo_clip_path_t *prev;
cairo_bool_t need_translate;
cairo_surface_t *surface;
cairo_clip_path_t *prev;
cairo_status_t status;
while (clip_path->prev != NULL &&
clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
clip_path->path.maybe_fill_region)
{
clip_path = clip_path->prev;
}
clip_extents = &clip_path->extents;
if (clip_path->surface != NULL &&
clip_path->surface->backend == target->backend)
{
return cairo_surface_reference (clip_path->surface);
*tx = clip_extents->x;
*ty = clip_extents->y;
return clip_path->surface;
}
surface = _cairo_surface_create_similar_solid (target,
CAIRO_CONTENT_ALPHA,
clip_extents->width,
clip_extents->height,
CAIRO_COLOR_TRANSPARENT,
FALSE);
surface = _cairo_surface_create_similar_scratch (target,
CAIRO_CONTENT_ALPHA,
clip_extents->width,
clip_extents->height);
if (surface == NULL) {
if (clip_path->surface != NULL &&
clip_path->surface->backend == &_cairo_image_surface_backend)
{
return cairo_surface_reference (clip_path->surface);
}
surface =
_cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA,
clip_extents->width,
clip_extents->height);
surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
clip_extents->width,
clip_extents->height);
}
if (unlikely (surface->status))
return surface;
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
status = _cairo_clip_path_to_region (clip_path);
if (unlikely (_cairo_status_is_error (status)))
goto BAIL;
need_translate = clip_extents->x | clip_extents->y;
if (status == CAIRO_STATUS_SUCCESS) {
if (need_translate) {
cairo_region_translate (clip_path->region,
-clip_extents->x, -clip_extents->y);
}
status = _cairo_surface_fill_region (surface,
CAIRO_OPERATOR_SOURCE,
CAIRO_COLOR_WHITE,
clip_path->region);
if (need_translate) {
cairo_region_translate (clip_path->region,
clip_extents->x, clip_extents->y);
}
if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
clip_path->path.maybe_fill_region)
{
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_SOURCE,
&_cairo_pattern_white.base,
NULL);
if (unlikely (status))
goto BAIL;
}
else
{
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_CLEAR,
&_cairo_pattern_clear.base,
NULL);
if (unlikely (status))
goto BAIL;
goto DONE;
} else {
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (-clip_extents->x),
_cairo_fixed_from_int (-clip_extents->y));
}
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_OVER,
&pattern.base,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
@ -1111,19 +1031,16 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
}
prev = clip_path->prev;
NEXT_PATH:
if (prev != NULL) {
status = _cairo_clip_path_to_region (prev);
if (unlikely (_cairo_status_is_error (status)))
goto BAIL;
if (status == CAIRO_STATUS_SUCCESS) {
status = _combine_region (surface, prev->region, clip_extents);
if (unlikely (status))
goto BAIL;
} else if (prev->flags & CAIRO_CLIP_PATH_IS_BOX) {
while (prev != NULL) {
if (prev->flags & CAIRO_CLIP_PATH_IS_BOX &&
prev->path.maybe_fill_region)
{
/* a simple box only affects the extents */
} else if (prev->path.is_rectilinear) {
}
else if (prev->path.is_rectilinear ||
prev->surface == NULL ||
prev->surface->backend != target->backend)
{
if (need_translate) {
_cairo_path_fixed_translate (&prev->path,
_cairo_fixed_from_int (-clip_extents->x),
@ -1131,7 +1048,7 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
}
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_IN,
&pattern.base,
&_cairo_pattern_white.base,
&prev->path,
prev->fill_rule,
prev->tolerance,
@ -1145,19 +1062,23 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
if (unlikely (status))
goto BAIL;
prev = prev->prev;
goto NEXT_PATH;
} else {
}
else
{
cairo_surface_pattern_t pattern;
cairo_surface_t *prev_surface;
int prev_tx, prev_ty;
prev_surface = _cairo_clip_path_get_surface (prev, target);
_cairo_pattern_init_for_surface (&pattern.surface, prev_surface);
cairo_surface_destroy (prev_surface);
prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty);
status = prev_surface->status;
if (unlikely (status))
goto BAIL;
_cairo_pattern_init_for_surface (&pattern, prev_surface);
pattern.base.filter = CAIRO_FILTER_NEAREST;
cairo_matrix_init_translate (&pattern.base.matrix,
-prev->extents.x + clip_extents->x,
-prev->extents.y + clip_extents->y);
clip_extents->x - prev_tx,
clip_extents->y - prev_ty);
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_IN,
&pattern.base,
@ -1166,18 +1087,75 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
if (unlikely (status))
goto BAIL;
break;
}
prev = prev->prev;
}
DONE:
*tx = clip_extents->x;
*ty = clip_extents->y;
cairo_surface_destroy (clip_path->surface);
return clip_path->surface = cairo_surface_reference (surface);
return clip_path->surface = surface;
BAIL:
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (status);
}
cairo_bool_t
_cairo_clip_contains_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect)
{
cairo_clip_path_t *clip_path;
if (clip == NULL)
return FALSE;
clip_path = clip->path;
if (clip_path->extents.x > rect->x ||
clip_path->extents.y > rect->y ||
clip_path->extents.x + clip_path->extents.width < rect->x + rect->width ||
clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
{
return FALSE;
}
do {
cairo_box_t box;
if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0)
return FALSE;
if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
return FALSE;
if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
box.p1.y > _cairo_fixed_from_int (rect->y) ||
box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
{
return FALSE;
}
} while ((clip_path = clip_path->prev) != NULL);
return TRUE;
}
cairo_bool_t
_cairo_clip_contains_extents (cairo_clip_t *clip,
const cairo_composite_rectangles_t *extents)
{
const cairo_rectangle_int_t *rect;
if (clip == NULL)
return FALSE;
rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
return _cairo_clip_contains_rectangle (clip, rect);
}
void
_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
{
@ -1202,72 +1180,48 @@ _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
clip_path = clip->path;
do {
fprintf (stream, "path: has region? %s, has surface? %s: ",
fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ",
clip_path->region == NULL ? "no" : "yes",
clip_path->surface == NULL ? "no" : "yes");
clip_path->surface == NULL ? "no" : "yes",
clip_path->antialias,
clip_path->tolerance,
clip_path->fill_rule);
_cairo_debug_print_path (stream, &clip_path->path);
fprintf (stream, "\n");
} while ((clip_path = clip_path->prev) != NULL);
}
cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty)
{
/* XXX is_clear -> all_clipped */
assert (clip->path != NULL);
return _cairo_clip_path_get_surface (clip->path, target);
return _cairo_clip_path_get_surface (clip->path, target, tx, ty);
}
cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
int dst_x, int dst_y)
{
cairo_pattern_union_t pattern;
cairo_clip_path_t *clip_path = clip->path;
cairo_bool_t need_translate;
cairo_status_t status;
assert (clip_path != NULL);
if (clip_path->surface != NULL &&
clip_path->surface->backend == dst->backend)
{
_cairo_pattern_init_for_surface (&pattern.surface,
clip_path->surface);
cairo_matrix_init_translate (&pattern.base.matrix,
extents->x - clip_path->extents.x,
extents->y - clip_path->extents.y);
status = _cairo_surface_paint (dst,
CAIRO_OPERATOR_IN,
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
return status;
}
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
need_translate = extents->x | extents->y;
need_translate = dst_x | dst_y;
do {
status = _cairo_clip_path_to_region (clip_path);
if (unlikely (_cairo_status_is_error (status)))
return status;
if (status == CAIRO_STATUS_SUCCESS)
return _combine_region (dst, clip_path->region, extents);
if (clip_path->surface != NULL &&
clip_path->surface->backend == dst->backend)
{
_cairo_pattern_init_for_surface (&pattern.surface,
clip_path->surface);
cairo_surface_pattern_t pattern;
_cairo_pattern_init_for_surface (&pattern, clip_path->surface);
cairo_matrix_init_translate (&pattern.base.matrix,
extents->x - clip_path->extents.x,
extents->y - clip_path->extents.y);
dst_x - clip_path->extents.x,
dst_y - clip_path->extents.y);
pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_surface_paint (dst,
CAIRO_OPERATOR_IN,
&pattern.base,
@ -1278,30 +1232,29 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
return status;
}
if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) {
cairo_region_t clip_region;
if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
clip_path->path.maybe_fill_region)
{
continue;
}
_cairo_region_init_rectangle (&clip_region, &clip_path->extents);
status = _combine_region (dst, &clip_region, extents);
} else {
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (-extents->x),
_cairo_fixed_from_int (-extents->y));
}
status = _cairo_surface_fill (dst,
CAIRO_OPERATOR_IN,
&pattern.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
NULL);
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (extents->x),
_cairo_fixed_from_int (extents->y));
}
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (-dst_x),
_cairo_fixed_from_int (-dst_y));
}
status = _cairo_surface_fill (dst,
CAIRO_OPERATOR_IN,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias,
NULL);
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (dst_x),
_cairo_fixed_from_int (dst_y));
}
if (unlikely (status))
@ -1432,6 +1385,90 @@ _cairo_clip_get_boxes (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
box_is_aligned (const cairo_box_t *box)
{
return
_cairo_fixed_is_integer (box->p1.x) &&
_cairo_fixed_is_integer (box->p1.y) &&
_cairo_fixed_is_integer (box->p2.x) &&
_cairo_fixed_is_integer (box->p2.y);
}
static void
intersect_with_boxes (cairo_composite_rectangles_t *extents,
cairo_box_t *boxes,
int num_boxes)
{
cairo_rectangle_int_t rect;
cairo_box_t box;
cairo_bool_t is_empty;
box.p1.x = box.p1.y = INT_MIN;
box.p2.x = box.p2.y = INT_MAX;
while (num_boxes--) {
if (boxes->p1.x < box.p1.x)
box.p1.x = boxes->p1.x;
if (boxes->p1.y < box.p1.y)
box.p1.y = boxes->p1.y;
if (boxes->p2.x > box.p2.x)
box.p2.x = boxes->p2.x;
if (boxes->p2.y > box.p2.y)
box.p2.y = boxes->p2.y;
}
_cairo_box_round_to_rectangle (&box, &rect);
is_empty = _cairo_rectangle_intersect (&extents->bounded, &rect);
is_empty = _cairo_rectangle_intersect (&extents->unbounded, &rect);
}
cairo_status_t
_cairo_clip_to_boxes (cairo_clip_t **clip,
cairo_composite_rectangles_t *extents,
cairo_box_t **boxes,
int *num_boxes)
{
cairo_status_t status;
const cairo_rectangle_int_t *rect;
rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
if (*clip == NULL)
goto EXTENTS;
status = _cairo_clip_rectangle (*clip, rect);
if (unlikely (status))
return status;
status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
switch ((int) status) {
case CAIRO_STATUS_SUCCESS:
intersect_with_boxes (extents, *boxes, *num_boxes);
if (rect->width == 0 || rect->height == 0 ||
extents->is_bounded ||
(*num_boxes == 1 && box_is_aligned (*boxes)))
{
*clip = NULL;
}
goto DONE;
case CAIRO_INT_STATUS_UNSUPPORTED:
goto EXTENTS;
default:
return status;
}
EXTENTS:
status = CAIRO_STATUS_SUCCESS;
_cairo_box_from_rectangle (&(*boxes)[0], rect);
*num_boxes = 1;
DONE:
return status;
}
static cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error (cairo_status_t status)
{

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -67,13 +67,14 @@ _cairo_stock_color (cairo_stock_t stock)
return &cairo_color_black;
case CAIRO_STOCK_TRANSPARENT:
return &cairo_color_transparent;
case CAIRO_STOCK_NUM_COLORS:
default:
ASSERT_NOT_REACHED;
/* If the user can get here somehow, give a color that indicates a
* problem. */
return &cairo_color_magenta;
}
ASSERT_NOT_REACHED;
/* If the user can get here somehow, give a color that indicates a
* problem. */
return &cairo_color_magenta;
}
void
@ -161,6 +162,7 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color,
*alpha = color->alpha;
}
/* NB: This function works both for unmultiplied and premultiplied colors */
cairo_bool_t
_cairo_color_equal (const cairo_color_t *color_a,
const cairo_color_t *color_b)
@ -168,8 +170,42 @@ _cairo_color_equal (const cairo_color_t *color_a,
if (color_a == color_b)
return TRUE;
if (color_a->alpha_short != color_b->alpha_short)
return FALSE;
if (color_a->alpha_short == 0)
return TRUE;
return color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short &&
color_a->alpha_short == color_b->alpha_short;
color_a->blue_short == color_b->blue_short;
}
cairo_bool_t
_cairo_color_stop_equal (const cairo_color_stop_t *color_a,
const cairo_color_stop_t *color_b)
{
if (color_a == color_b)
return TRUE;
return color_a->alpha_short == color_b->alpha_short &&
color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short;
}
cairo_content_t
_cairo_color_get_content (const cairo_color_t *color)
{
if (CAIRO_COLOR_IS_OPAQUE (color))
return CAIRO_CONTENT_COLOR;
if (color->red_short == 0 &&
color->green_short == 0 &&
color->blue_short == 0)
{
return CAIRO_CONTENT_ALPHA;
}
return CAIRO_CONTENT_COLOR_ALPHA;
}

View File

@ -11,7 +11,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -44,6 +44,45 @@
#include "config.h"
#endif
/* Size in bytes of buffer to use off the stack per functions.
* Mostly used by text functions. For larger allocations, they'll
* malloc(). */
#ifndef CAIRO_STACK_BUFFER_SIZE
#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
#endif
#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
/*
* The goal of this block is to define the following macros for
* providing faster linkage to functions in the public API for calls
* from within cairo.
*
* slim_hidden_proto(f)
* slim_hidden_proto_no_warn(f)
*
* Declares `f' as a library internal function and hides the
* function from the global symbol table. This macro must be
* expanded after `f' has been declared with a prototype but before
* any calls to the function are seen by the compiler. The no_warn
* variant inhibits warnings about the return value being unused at
* call sites. The macro works by renaming `f' to an internal name
* in the symbol table and hiding that. As far as cairo internal
* calls are concerned they're calling a library internal function
* and thus don't need to bounce via the PLT.
*
* slim_hidden_def(f)
*
* Exports `f' back to the global symbol table. This macro must be
* expanded right after the function definition and only for symbols
* hidden previously with slim_hidden_proto(). The macro works by
* adding a global entry to the symbol table which points at the
* internal name of `f' created by slim_hidden_proto().
*
* Functions in the public API which aren't called by the library
* don't need to be hidden and re-exported using the slim hidden
* macros.
*/
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
@ -134,9 +173,11 @@
#if __GNUC__ >= 3
#define cairo_pure __attribute__((pure))
#define cairo_const __attribute__((const))
#define cairo_always_inline inline __attribute__((always_inline))
#else
#define cairo_pure
#define cairo_const
#define cairo_always_inline inline
#endif
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
@ -171,6 +212,26 @@
#ifdef _MSC_VER
#undef inline
#define inline __inline
/* there are currently linkage problems that arise when trying to include intrin.h in c++:
* D:\sdks\v7.0\include\winnt.h(3674) : error C2733: second C linkage of overloaded function '_interlockedbittestandset' not allowed
* so avoid defining ffs in c++ code for now */
#ifndef __cplusplus
/* Add a definition of ffs */
#include <intrin.h>
#pragma intrinsic(_BitScanForward)
static __forceinline int
ffs (int x)
{
unsigned long i;
if (_BitScanForward(&i, x) != 0)
return i + 1;
return 0;
}
#endif
#endif
#if defined(_MSC_VER) && defined(_M_IX86)

View File

@ -0,0 +1,105 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
#ifndef CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
#define CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
#include "cairo-types-private.h"
CAIRO_BEGIN_DECLS
/* Rectangles that take part in a composite operation.
*
* The source and mask track the extents of the respective patterns in device
* space. The unbounded rectangle is essentially the clip rectangle. And the
* intersection of all is the bounded rectangle, which is the minimum extents
* the operation may require. Whether or not the operation is actually bounded
* is tracked in the is_bounded boolean.
*
*/
struct _cairo_composite_rectangles {
cairo_rectangle_int_t source;
cairo_rectangle_int_t mask;
cairo_rectangle_int_t bounded; /* dst */
cairo_rectangle_int_t unbounded; /* clip */
uint32_t is_bounded;
};
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip,
cairo_bool_t *overlap);
#endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */

View File

@ -0,0 +1,195 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-composite-rectangles-private.h"
/* A collection of routines to facilitate writing compositors. */
static inline cairo_bool_t
_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
extents->unbounded = *surface_extents;
if (clip != NULL) {
const cairo_rectangle_int_t *clip_extents;
clip_extents = _cairo_clip_get_extents (clip);
if (clip_extents == NULL)
return FALSE;
if (! _cairo_rectangle_intersect (&extents->unbounded, clip_extents))
return FALSE;
}
extents->bounded = extents->unbounded;
extents->is_bounded = _cairo_operator_bounded_by_either (op);
_cairo_pattern_get_extents (source, &extents->source);
if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
return FALSE;
}
return TRUE;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_extents,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
extents->mask = extents->bounded;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents)
{
cairo_bool_t ret;
ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_extents,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_pattern_get_extents (mask, &extents->mask);
return _cairo_composite_rectangles_intersect (extents);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_extents,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);
return _cairo_composite_rectangles_intersect (extents);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface_extents,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_path_fixed_approximate_fill_extents (path, &extents->mask);
return _cairo_composite_rectangles_intersect (extents);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *surface_extents,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_clip_t *clip,
cairo_bool_t *overlap)
{
cairo_status_t status;
if (! _cairo_composite_rectangles_init (extents,
surface_extents,
op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs, num_glyphs,
&extents->mask,
overlap);
if (unlikely (status))
return status;
return _cairo_composite_rectangles_intersect (extents);
}

View File

@ -43,10 +43,8 @@
#include <d3d10.h>
#include <dxgi.h>
extern "C" {
#include "cairoint.h"
#include "cairo-surface-clipper-private.h"
}
#include "cairo-win32-refptr.h"
#include "cairo-d2d-private-fx.h"

View File

@ -39,10 +39,9 @@
#include "cairo-d2d-private.h"
#include "cairo-dwrite-private.h"
extern "C" {
#include "cairo-win32.h"
#include "cairo-analysis-surface-private.h"
}
#include "cairo-error-private.h"
// Required for using placement new.
#include <new>
@ -649,9 +648,9 @@ _cairo_d2d_stroke(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
@ -763,6 +762,16 @@ _cairo_d2d_compute_surface_mem_size(cairo_d2d_surface_t *surface)
return size;
}
static D2D1_COLOR_F
_cairo_d2d_color_from_cairo_color_stop(const cairo_color_stop_t &color)
{
return D2D1::ColorF((FLOAT)color.red,
(FLOAT)color.green,
(FLOAT)color.blue,
(FLOAT)color.alpha);
}
/**
* Gets the surface buffer texture for window surfaces whose backbuffer
* is not directly usable as a bitmap.
@ -1435,7 +1444,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf,
stops[i].position = (FLOAT)((repeat + source_pattern->base.stops[stop].offset) * stop_scale);
}
stops[i].color =
_cairo_d2d_color_from_cairo_color(source_pattern->base.stops[stop].color);
_cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[stop].color);
}
} else {
// Simple case, we don't need to reflect.
@ -1445,7 +1454,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf,
// Calculate which stop this would be in the original pattern
cairo_gradient_stop_t *stop = &source_pattern->base.stops[i % source_pattern->base.n_stops];
stops[i].position = (FLOAT)((repeat + stop->offset) * stop_scale);
stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
}
}
} else if (source_pattern->base.base.extend == CAIRO_EXTEND_PAD) {
@ -1458,7 +1467,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf,
for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) {
cairo_gradient_stop_t *stop = &source_pattern->base.stops[i];
stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor);
stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
}
} else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) {
float offset_factor = (outer_radius - inner_radius) / outer_radius;
@ -1482,7 +1491,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf,
for (unsigned int j = 0; j < source_pattern->base.n_stops; j++, i++) {
cairo_gradient_stop_t *stop = &source_pattern->base.stops[j];
stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor);
stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
}
stops[i].position = 1.0f;
stops[i].color = D2D1::ColorF(0, 0);
@ -1514,7 +1523,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
// Cairo behavior in this situation is to draw a solid color the size of the last stop.
RefPtr<ID2D1SolidColorBrush> brush;
d2dsurf->rt->CreateSolidColorBrush(
_cairo_d2d_color_from_cairo_color(source_pattern->base.stops[source_pattern->base.n_stops - 1].color),
_cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[source_pattern->base.n_stops - 1].color),
&brush);
return brush;
}
@ -1619,7 +1628,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
stops[i].position = (FLOAT)((repeat + source_pattern->base.stops[stop].offset) * stop_scale);
}
stops[i].color =
_cairo_d2d_color_from_cairo_color(source_pattern->base.stops[stop].color);
_cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[stop].color);
}
} else {
// Simple case, we don't need to reflect.
@ -1629,7 +1638,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
// Calculate which stop this would be in the original pattern
cairo_gradient_stop_t *stop = &source_pattern->base.stops[i % source_pattern->base.n_stops];
stops[i].position = (FLOAT)((repeat + stop->offset) * stop_scale);
stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
}
}
} else if (source_pattern->base.base.extend == CAIRO_EXTEND_PAD) {
@ -1637,7 +1646,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) {
cairo_gradient_stop_t *stop = &source_pattern->base.stops[i];
stops[i].position = (FLOAT)stop->offset;
stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
}
} else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) {
num_stops += 2;
@ -1647,7 +1656,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
for (unsigned int i = 1; i < source_pattern->base.n_stops + 1; i++) {
cairo_gradient_stop_t *stop = &source_pattern->base.stops[i - 1];
stops[i].position = (FLOAT)stop->offset;
stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color);
stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
}
stops[source_pattern->base.n_stops + 1].position = 1.0f;
stops[source_pattern->base.n_stops + 1].color = D2D1::ColorF(0, 0);
@ -2309,6 +2318,16 @@ static cairo_operator_t _cairo_d2d_simplify_operator(cairo_operator_t op,
return op;
}
void
_cairo_d2d_surface_init(cairo_d2d_surface_t *newSurf, cairo_d2d_device_t *d2d_device, cairo_format_t format)
{
newSurf->format = format;
newSurf->device = d2d_device;
cairo_addref_device(&d2d_device->base);
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
}
// Implementation
static cairo_surface_t*
_cairo_d2d_create_similar(void *surface,
@ -2320,7 +2339,7 @@ _cairo_d2d_create_similar(void *surface,
cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
new (newSurf) cairo_d2d_surface_t();
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
D2D1_SIZE_U sizePixels;
@ -2425,9 +2444,7 @@ _cairo_d2d_create_similar(void *surface,
_d2d_clear_surface(newSurf);
newSurf->device = d2dsurf->device;
cairo_addref_device(&newSurf->device->base);
newSurf->device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
_cairo_d2d_surface_init(newSurf, d2dsurf->device, _cairo_format_from_content(content));
return reinterpret_cast<cairo_surface_t*>(newSurf);
@ -2501,8 +2518,8 @@ _cairo_d2d_acquire_source_image(void *abstract_surface,
return _cairo_error(CAIRO_STATUS_NO_DEVICE);
}
*image_out =
(cairo_image_surface_t*)_cairo_image_surface_create_for_data_with_content((unsigned char*)data.pData,
d2dsurf->base.content,
(cairo_image_surface_t*)cairo_image_surface_create_for_data((unsigned char*)data.pData,
d2dsurf->format,
size.width,
size.height,
data.RowPitch);
@ -2573,8 +2590,8 @@ _cairo_d2d_acquire_dest_image(void *abstract_surface,
return _cairo_error(CAIRO_STATUS_NO_DEVICE);
}
*image_out =
(cairo_image_surface_t*)_cairo_image_surface_create_for_data_with_content((unsigned char*)data.pData,
d2dsurf->base.content,
(cairo_image_surface_t*)cairo_image_surface_create_for_data((unsigned char*)data.pData,
_cairo_format_from_content(d2dsurf->base.content),
size.width,
size.height,
data.RowPitch);
@ -3178,7 +3195,7 @@ _cairo_d2d_mask(void *surface,
if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solidPattern =
(cairo_solid_pattern_t*)mask;
if (solidPattern->content = CAIRO_CONTENT_ALPHA) {
if (_cairo_color_get_content (&solidPattern->color) == CAIRO_CONTENT_ALPHA) {
isSolidAlphaMask = true;
solidAlphaValue = solidPattern->color.alpha;
}
@ -3321,9 +3338,9 @@ _cairo_d2d_stroke(void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@ -3526,7 +3543,12 @@ _cairo_d2d_fill(void *surface,
if (target_rt.get() != d2dsurf->rt.get()) {
double x1, y1, x2, y2;
_cairo_path_fixed_bounds(path, &x1, &y1, &x2, &y2);
cairo_box_t box;
_cairo_path_fixed_extents (path, &box);
x1 = _cairo_fixed_to_double (box.p1.x);
y1 = _cairo_fixed_to_double (box.p1.y);
x2 = _cairo_fixed_to_double (box.p2.x);
y2 = _cairo_fixed_to_double (box.p2.y);
cairo_rectangle_int_t bounds;
_cairo_d2d_round_out_to_int_rect(&bounds, x1, y1, x2, y2);
return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip, &bounds);
@ -4118,6 +4140,8 @@ _cairo_d2d_getextents(void *surface,
/** Helper functions. */
cairo_surface_t*
cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device,
HWND wnd,
@ -4127,7 +4151,7 @@ cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device,
cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
new (newSurf) cairo_d2d_surface_t();
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
RECT rc;
HRESULT hr;
@ -4229,9 +4253,7 @@ cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device,
_d2d_clear_surface(newSurf);
newSurf->device = d2d_device;
cairo_addref_device(cairo_device);
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
_cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content));
return reinterpret_cast<cairo_surface_t*>(newSurf);
@ -4241,6 +4263,8 @@ FAIL_HWND:
return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
}
cairo_surface_t *
cairo_d2d_surface_create(cairo_device_t *device,
cairo_format_t format,
@ -4258,12 +4282,12 @@ cairo_d2d_surface_create(cairo_device_t *device,
DXGI_FORMAT dxgiformat = DXGI_FORMAT_B8G8R8A8_UNORM;
D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
if (format == CAIRO_FORMAT_ARGB32) {
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR_ALPHA);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR_ALPHA);
} else if (format == CAIRO_FORMAT_RGB24) {
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR);
alpha = D2D1_ALPHA_MODE_IGNORE;
} else {
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_ALPHA);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_ALPHA);
dxgiformat = DXGI_FORMAT_A8_UNORM;
}
@ -4343,9 +4367,7 @@ cairo_d2d_surface_create(cairo_device_t *device,
_d2d_clear_surface(newSurf);
newSurf->device = d2d_device;
cairo_addref_device(device);
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
_cairo_d2d_surface_init(newSurf, d2d_device, format);
return reinterpret_cast<cairo_surface_t*>(newSurf);
@ -4398,7 +4420,7 @@ cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo
status = CAIRO_STATUS_INVALID_CONTENT;
goto FAIL_CREATEHANDLE;
}
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
if (content == CAIRO_CONTENT_COLOR) {
alpha = D2D1_ALPHA_MODE_IGNORE;
}
@ -4407,7 +4429,7 @@ cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo
status = CAIRO_STATUS_INVALID_CONTENT;
goto FAIL_CREATEHANDLE;
}
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_ALPHA);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_ALPHA);
} else {
status = CAIRO_STATUS_INVALID_FORMAT;
// We don't know how to support this format!
@ -4444,9 +4466,7 @@ cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo
newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
newSurf->device = d2d_device;
cairo_addref_device(device);
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
_cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content));
return &newSurf->base;
@ -4467,10 +4487,10 @@ cairo_d2d_surface_create_for_texture(cairo_device_t *device,
D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
if (content == CAIRO_CONTENT_COLOR) {
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR);
alpha = D2D1_ALPHA_MODE_IGNORE;
} else {
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
}
D2D1_SIZE_U sizePixels;
@ -4527,9 +4547,7 @@ cairo_d2d_surface_create_for_texture(cairo_device_t *device,
newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
newSurf->device = d2d_device;
cairo_addref_device(device);
d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
_cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content));
return reinterpret_cast<cairo_surface_t*>(newSurf);

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -77,10 +77,14 @@ cairo_debug_reset_static_data (void)
_cairo_clip_reset_static_data ();
_cairo_image_reset_static_data ();
#if CAIRO_HAS_DRM_SURFACE
_cairo_drm_device_reset_static_data ();
#endif
_cairo_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
}
@ -106,10 +110,14 @@ _cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface)
case CAIRO_FORMAT_A8:
width = image->width;
break;
case CAIRO_FORMAT_RGB16_565:
width = image->width*2;
break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_ARGB32:
width = image->width*4;
break;
case CAIRO_FORMAT_INVALID:
default:
/* XXX compute width from pixman bpp */
return;
@ -221,6 +229,12 @@ _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;
printf ("path: extents=(%f, %f), (%f, %f)\n",
_cairo_fixed_to_double (path->extents.p1.x),
_cairo_fixed_to_double (path->extents.p1.y),
_cairo_fixed_to_double (path->extents.p2.x),
_cairo_fixed_to_double (path->extents.p2.y));
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_print_move_to,

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,6 +35,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
#include <zlib.h>

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -36,20 +36,6 @@
#ifndef CAIRO_DEPRECATED_H
#define CAIRO_DEPRECATED_H
/* The %CAIRO_FORMAT_RGB16_565 value was added in cairo 1.2.0 as part
* of fixing cairo's xlib backend to work with X servers advertising a
* 16-bit, 565 visual. But as it turned out, adding this format to
* #cairo_format_t was not necessary, and was a mistake, (cairo's xlib
* backend can work fine with 16-bit visuals in the same way it works
* with BGR visuals without any BGR formats in
* #cairo_format_t).
*
* Additionally, the support for the RGB16_565 format was never
* completely implemented. So while this format value is currently
* deprecated, it may eventually acquire complete support in the future.
*/
/* #define CAIRO_FORMAT_RGB16_565 4 */
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
/* Obsolete functions. These definitions exist to coerce the compiler
@ -123,7 +109,6 @@
#define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t
#define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create
#define cairo_set_target_glitz cairo_set_target_glitz_DEPRECATED_BY_cairo_glitz_surface_create
#define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data
#define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create
#define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png

View File

@ -0,0 +1,86 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef _CAIRO_DEVICE_PRIVATE_H_
#define _CAIRO_DEVICE_PRIVATE_H_
#include "cairo-compiler-private.h"
#include "cairo-mutex-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
struct _cairo_device {
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
const cairo_device_backend_t *backend;
cairo_recursive_mutex_t mutex;
unsigned mutex_depth;
cairo_bool_t finished;
};
struct _cairo_device_backend {
cairo_device_type_t type;
void (*lock) (void *device);
void (*unlock) (void *device);
cairo_warn cairo_status_t (*flush) (void *device);
void (*finish) (void *device);
void (*destroy) (void *device);
};
cairo_private cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status);
cairo_private void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend);
cairo_private cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t error);
slim_hidden_proto_no_warn (cairo_device_reference);
slim_hidden_proto (cairo_device_acquire);
slim_hidden_proto (cairo_device_release);
slim_hidden_proto (cairo_device_flush);
slim_hidden_proto (cairo_device_finish);
slim_hidden_proto (cairo_device_destroy);
#endif /* _CAIRO_DEVICE_PRIVATE_H_ */

View File

@ -0,0 +1,533 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
/**
* SECTION:cairo-device
* @Title: cairo_device_t
* @Short_Description: interface to underlying rendering system
* @See_Also: #cairo_surface_t
*
* Devices are the abstraction Cairo employs for the rendering system
* used by a #cairo_surface_t. You can get the device of a surface using
* cairo_surface_get_device().
*
* Devices are created using custom functions specific to the rendering
* system you want to use. See the documentation for the surface types
* for those functions.
*
* An important function that devices fulfill is sharing access to the
* rendering system between Cairo and your application. If you want to
* access a device directly that you used to draw to with Cairo, you must
* first call cairo_device_flush() to ensure that Cairo finishes all
* operations on the device and resets it to a clean state.
*
* Cairo also provides the functions cairo_device_acquire() and
* cairo_device_release() to synchronize access to the rendering system
* in a multithreaded environment. This is done internally, but can also
* be used by applications.
*
* Putting this all together, a function that works with devices should
* look something like this:
* <informalexample><programlisting>
* void
* my_device_modifying_function (cairo_device_t *device)
* {
* cairo_status_t status;
*
* // Ensure the device is properly reset
* cairo_device_flush (device);
* // Try to acquire the device
* status = cairo_device_acquire (device);
* if (status != CAIRO_STATUS_SUCCESS) {
* printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status));
* return;
* }
*
* // Do the custom operations on the device here.
* // But do not call any Cairo functions that might acquire devices.
*
* // Release the device when done.
* cairo_device_release (device);
* }
* </programlisting></informalexample>
*
* <note><para>Please refer to the documentation of each backend for
* additional usage requirements, guarantees provided, and
* interactions with existing surface API of the device functions for
* surfaces of that type.
* </para></note>
*/
static const cairo_device_t _nil_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_NO_MEMORY,
};
static const cairo_device_t _mismatch_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
};
static const cairo_device_t _invalid_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_ERROR,
};
cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_device_t *) &_nil_device;
case CAIRO_STATUS_DEVICE_ERROR:
return (cairo_device_t *) &_invalid_device;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return (cairo_device_t *) &_mismatch_device;
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
/* fall-through */
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_INVALID_FORMAT:
case CAIRO_STATUS_INVALID_VISUAL:
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
case CAIRO_STATUS_FILE_NOT_FOUND:
case CAIRO_STATUS_TEMP_FILE_ERROR:
case CAIRO_STATUS_INVALID_STRIDE:
case CAIRO_STATUS_INVALID_SIZE:
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
case CAIRO_STATUS_INVALID_CONTENT:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_device_t *) &_nil_device;
}
}
void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
device->status = CAIRO_STATUS_SUCCESS;
device->backend = backend;
CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
device->mutex_depth = 0;
device->finished = FALSE;
_cairo_user_data_array_init (&device->user_data);
}
/**
* cairo_device_reference:
* @device: a #cairo_device_t
*
* Increases the reference count on @device by one. This prevents
* @device from being destroyed until a matching call to
* cairo_device_destroy() is made.
*
* The number of references to a #cairo_device_t can be get using
* cairo_device_get_reference_count().
*
* Return value: the referenced #cairo_device_t.
*
* Since: 1.10
**/
cairo_device_t *
cairo_device_reference (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return device;
}
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
_cairo_reference_count_inc (&device->ref_count);
return device;
}
slim_hidden_def (cairo_device_reference);
/**
* cairo_device_status:
* @device: a #cairo_device_t
*
* Checks whether an error has previously occurred for this
* device.
*
* Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
* the device is in an error state.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_status (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_NULL_POINTER;
return device->status;
}
/**
* cairo_device_flush:
* @device: a #cairo_device_t
*
* Finish any pending operations for the device and also restore any
* temporary modifications cairo has made to the device's state.
* This function must be called before switching from using the
* device with Cairo to operating on it directly with native APIs.
* If the device doesn't support direct access, then this function
* does nothing.
*
* This function may acquire devices.
*
* Since: 1.10
**/
void
cairo_device_flush (cairo_device_t *device)
{
cairo_status_t status;
if (device == NULL || device->status)
return;
if (device->backend->flush != NULL) {
status = device->backend->flush (device);
if (unlikely (status))
status = _cairo_device_set_error (device, status);
}
}
slim_hidden_def (cairo_device_flush);
/**
* cairo_device_finish:
* @device: the #cairo_device_t to finish
*
* This function finishes the device and drops all references to
* external resources. All surfaces, fonts and other objects created
* for this @device will be finished, too.
* Further operations on the @device will not affect the @device but
* will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
*
* When the last call to cairo_device_destroy() decreases the
* reference count to zero, cairo will call cairo_device_finish() if
* it hasn't been called already, before freeing the resources
* associated with the device.
*
* This function may acquire devices.
*
* Since: 1.10
**/
void
cairo_device_finish (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
if (device->finished)
return;
cairo_device_flush (device);
device->finished = TRUE;
if (device->backend->finish != NULL)
device->backend->finish (device);
}
slim_hidden_def (cairo_device_finish);
/**
* cairo_device_destroy:
* @device: a #cairo_device_t
*
* Decreases the reference count on @device by one. If the result is
* zero, then @device and all associated resources are freed. See
* cairo_device_reference().
*
* This function may acquire devices if the last reference was dropped.
*
* Since: 1.10
**/
void
cairo_device_destroy (cairo_device_t *device)
{
cairo_user_data_array_t user_data;
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
if (! _cairo_reference_count_dec_and_test (&device->ref_count))
return;
cairo_device_finish (device);
assert (device->mutex_depth == 0);
CAIRO_MUTEX_FINI (device->mutex);
user_data = device->user_data;
device->backend->destroy (device);
_cairo_user_data_array_fini (&user_data);
}
slim_hidden_def (cairo_device_destroy);
/**
* cairo_device_get_type:
* @device: a #cairo_device_t
*
* This function returns the type of the device. See #cairo_device_type_t
* for available types.
*
* Return value: The type of @device.
*
* Since: 1.10
**/
cairo_device_type_t
cairo_device_get_type (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return (cairo_device_type_t) -1;
}
return device->backend->type;
}
/**
* cairo_device_acquire:
* @device: a #cairo_device_t
*
* Acquires the @device for the current thread. This function will block
* until no other thread has acquired the device.
*
* If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
* device. From now on your thread owns the device and no other thread will be
* able to acquire it until a matching call to cairo_device_release(). It is
* allowed to recursively acquire the device multiple times from the same
* thread.
*
* <note><para>You must never acquire two different devices at the same time
* unless this is explicitly allowed. Otherwise the possibility of deadlocks
* exist.
*
* As various Cairo functions can acquire devices when called, these functions
* may also cause deadlocks when you call them with an acquired device. So you
* must not have a device acquired when calling them. These functions are
* marked in the documentation.
* </para></note>
*
* Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
* the device is in an error state and could not be
* acquired. After a successful call to cairo_device_acquire(),
* a matching call to cairo_device_release() is required.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_acquire (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_SUCCESS;
if (unlikely (device->status))
return device->status;
if (unlikely (device->finished))
return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */
CAIRO_MUTEX_LOCK (device->mutex);
if (device->mutex_depth++ == 0) {
if (device->backend->lock != NULL)
device->backend->lock (device);
}
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_device_acquire);
/**
* cairo_device_release:
* @device: a #cairo_device_t
*
* Releases a @device previously acquired using cairo_device_acquire(). See
* that function for details.
*
* Since: 1.10
**/
void
cairo_device_release (cairo_device_t *device)
{
if (device == NULL)
return;
assert (device->mutex_depth > 0);
if (--device->mutex_depth == 0) {
if (device->backend->unlock != NULL)
device->backend->unlock (device);
}
CAIRO_MUTEX_UNLOCK (device->mutex);
}
slim_hidden_def (cairo_device_release);
cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&device->status, status);
return _cairo_error (status);
}
/**
* cairo_device_get_reference_count:
* @device: a #cairo_device_t
*
* Returns the current reference count of @device.
*
* Return value: the current reference count of @device. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.10
**/
unsigned int
cairo_device_get_reference_count (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
return 0;
return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
}
/**
* cairo_device_get_user_data:
* @device: a #cairo_device_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @device using the
* specified key. If no user data has been attached with the given
* key this function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
*
* Since: 1.10
**/
void *
cairo_device_get_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&device->user_data,
key);
}
/**
* cairo_device_set_user_data:
* @device: a #cairo_device_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the #cairo_device_t
* @destroy: a #cairo_destroy_func_t which will be called when the
* #cairo_t is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @device. To remove user data from a surface,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
*
* Since: 1.10
**/
cairo_status_t
cairo_device_set_user_data (cairo_device_t *device,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
return device->status;
return _cairo_user_data_array_set_data (&device->user_data,
key, user_data, destroy);
}

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -39,6 +39,7 @@
#include "cairo-directfb.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include <pixman.h>
@ -564,6 +565,7 @@ _cairo_directfb_surface_create_internal (IDirectFB *dfb,
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
NULL, /* device */
content);
surface->pixman_format = _directfb_to_pixman_format (format);
surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
@ -762,14 +764,14 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pixman_image_composite (PIXMAN_OP_SRC,
image_src->pixman_image,
NULL,
pixman_image,
src_x, src_y,
0, 0,
0, 0,
width, height);
pixman_image_composite32 (PIXMAN_OP_SRC,
image_src->pixman_image,
NULL,
pixman_image,
src_x, src_y,
0, 0,
0, 0,
width, height);
pixman_image_unref (pixman_image);
@ -1814,7 +1816,7 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
static cairo_bool_t
_cairo_directfb_surface_is_similar (void *surface_a, void *surface_b, cairo_content_t content)
_cairo_directfb_surface_is_similar (void *surface_a, void *surface_b)
{
cairo_directfb_surface_t *a = (cairo_directfb_surface_t *) surface_a;
cairo_directfb_surface_t *b = (cairo_directfb_surface_t *) surface_b;
@ -1955,6 +1957,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
NULL, /* device */
_directfb_format_to_content (format));
return &surface->base;

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -39,56 +39,41 @@
CAIRO_BEGIN_DECLS
typedef struct _cairo_drm_device cairo_drm_device_t;
struct udev_device;
cairo_public cairo_drm_device_t *
cairo_public cairo_device_t *
cairo_drm_device_get (struct udev_device *device);
cairo_public cairo_drm_device_t *
cairo_public cairo_device_t *
cairo_drm_device_get_for_fd (int fd);
cairo_public cairo_drm_device_t *
cairo_public cairo_device_t *
cairo_drm_device_default (void);
cairo_public cairo_drm_device_t *
cairo_drm_device_reference (cairo_drm_device_t *device);
cairo_public cairo_status_t
cairo_drm_device_status (cairo_drm_device_t *device);
cairo_public int
cairo_drm_device_get_fd (cairo_drm_device_t *device);
cairo_drm_device_get_fd (cairo_device_t *device);
cairo_public void
cairo_drm_device_throttle (cairo_drm_device_t *device);
cairo_public void
cairo_drm_device_destroy (cairo_drm_device_t *device);
cairo_drm_device_throttle (cairo_device_t *device);
cairo_public cairo_surface_t *
cairo_drm_surface_create (cairo_drm_device_t *device,
cairo_content_t content,
cairo_drm_surface_create (cairo_device_t *device,
cairo_format_t format,
int width, int height);
cairo_public cairo_surface_t *
cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
cairo_drm_surface_create_for_name (cairo_device_t *device,
unsigned int name,
cairo_format_t format,
int width, int height, int stride);
cairo_public cairo_surface_t *
cairo_drm_surface_create_from_cacheable_image (cairo_drm_device_t *device,
cairo_drm_surface_create_from_cacheable_image (cairo_device_t *device,
cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_drm_surface_enable_scan_out (cairo_surface_t *surface);
cairo_public cairo_drm_device_t *
cairo_drm_surface_get_device (cairo_surface_t *abstract_surface);
cairo_public unsigned int
cairo_drm_surface_get_handle (cairo_surface_t *surface);
@ -120,7 +105,7 @@ cairo_drm_surface_get_stride (cairo_surface_t *surface);
* will also disassociate the mapping.)
*/
cairo_public cairo_surface_t *
cairo_drm_surface_map (cairo_surface_t *surface);
cairo_drm_surface_map_to_image (cairo_surface_t *surface);
cairo_public void
cairo_drm_surface_unmap (cairo_surface_t *drm_surface,

View File

@ -34,13 +34,12 @@
* Bas Schouten <bschouten@mozilla.com>
*/
extern "C" {
#include "cairoint.h"
#include "cairo-win32-private.h"
#include "cairo-surface-private.h"
#include "cairo-clip-private.h"
}
#include "cairo-d2d-private.h"
#include "cairo-dwrite-private.h"
#include <float.h>

View File

@ -0,0 +1,60 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef _CAIRO_ERROR_PRIVATE_H_
#define _CAIRO_ERROR_PRIVATE_H_
#include "cairo.h"
#include "cairo-compiler-private.h"
CAIRO_BEGIN_DECLS
#define _cairo_status_is_error(status) \
(status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS)
cairo_private cairo_status_t
_cairo_error (cairo_status_t status);
/* hide compiler warnings when discarding the return value */
#define _cairo_error_throw(status) do { \
cairo_status_t status__ = _cairo_error (status); \
(void) status__; \
} while (0)
CAIRO_END_DECLS
#endif /* _CAIRO_ERROR_PRIVATE_H_ */

View File

@ -89,6 +89,8 @@
@QUARTZ_FONT_FEATURE@
@TEE_SURFACE_FEATURE@
@PNG_FUNCTIONS_FEATURE@
@FC_FONT_FEATURE@

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -53,7 +53,7 @@
#define CAIRO_FIXED_ONE_FLOAT ((float)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1))
#define CAIRO_FIXED_FRAC_MASK (((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_FRAC_MASK ((cairo_fixed_t)(((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS)))
#define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK)
static inline cairo_fixed_t
@ -136,6 +136,16 @@ _cairo_fixed_from_26_6 (uint32_t i)
#endif
}
static inline cairo_fixed_t
_cairo_fixed_from_16_16 (uint32_t i)
{
#if CAIRO_FIXED_FRAC_BITS > 16
return i << (CAIRO_FIXED_FRAC_BITS - 16);
#else
return i >> (16 - CAIRO_FIXED_FRAC_BITS);
#endif
}
static inline double
_cairo_fixed_to_double (cairo_fixed_t f)
{
@ -154,12 +164,48 @@ _cairo_fixed_is_integer (cairo_fixed_t f)
return (f & CAIRO_FIXED_FRAC_MASK) == 0;
}
static inline cairo_fixed_t
_cairo_fixed_floor (cairo_fixed_t f)
{
return f & ~CAIRO_FIXED_FRAC_MASK;
}
static inline cairo_fixed_t
_cairo_fixed_round (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + (CAIRO_FIXED_FRAC_MASK+1)/2);
}
static inline cairo_fixed_t
_cairo_fixed_round_down (cairo_fixed_t f)
{
return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK/2);
}
static inline int
_cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> CAIRO_FIXED_FRAC_BITS;
}
static inline int
_cairo_fixed_integer_round (cairo_fixed_t f)
{
return _cairo_fixed_integer_part (f + (CAIRO_FIXED_FRAC_MASK+1)/2);
}
static inline int
_cairo_fixed_integer_round_down (cairo_fixed_t f)
{
return _cairo_fixed_integer_part (f + CAIRO_FIXED_FRAC_MASK/2);
}
static inline int
_cairo_fixed_fractional_part (cairo_fixed_t f)
{
return f & CAIRO_FIXED_FRAC_MASK;
}
static inline int
_cairo_fixed_integer_floor (cairo_fixed_t f)
{
@ -225,12 +271,18 @@ _cairo_fixed_16_16_from_double (double d)
}
static inline int
_cairo_fixed_16_16_floor (cairo_fixed_t f)
_cairo_fixed_16_16_floor (cairo_fixed_16_16_t f)
{
if (f >= 0)
return f >> 16;
return f >> 16;
else
return -((-f - 1) >> 16) - 1;
return -((-f - 1) >> 16) - 1;
}
static inline double
_cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f)
{
return ((double) f) / (double) (1 << 16);
}
#if CAIRO_FIXED_BITS == 32

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,6 +35,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include <math.h>

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -39,6 +39,24 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
/**
* SECTION:cairo-font-face
* @Title: cairo_font_face_t
* @Short_Description: Base class for font faces
* @See_Also: #cairo_scaled_font_t
*
* #cairo_font_face_t represents a particular font at a particular weight,
* slant, and other characteristic but no size, transformation, or size.
*
* Font faces are created using <firstterm>font-backend</firstterm>-specific
* constructors, typically of the form
* cairo_<emphasis>backend</emphasis>_font_face_create(), or implicitly
* using the <firstterm>toy</firstterm> text API by way of
* cairo_select_font_face(). The resulting face can be accessed using
* cairo_get_font_face().
*/
/* #cairo_font_face_t */

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,12 +35,27 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
/**
* SECTION:cairo-font-options
* @Title: cairo_font_options_t
* @Short_Description: How a font should be rendered
* @See_Also: #cairo_scaled_font_t
*
* The font options specify how fonts should be rendered. Most of the
* time the font options implied by a surface are just right and do not
* need any changes, but for pixel-based targets tweaking font options
* may result in superior output on a particular display.
*/
static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_LCD_FILTER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
CAIRO_HINT_METRICS_DEFAULT,
CAIRO_ROUND_GLYPH_POS_DEFAULT
};
/**
@ -54,8 +69,10 @@ _cairo_font_options_init_default (cairo_font_options_t *options)
{
options->antialias = CAIRO_ANTIALIAS_DEFAULT;
options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
options->lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
options->round_glyph_positions = CAIRO_ROUND_GLYPH_POS_DEFAULT;
}
void
@ -64,8 +81,10 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
{
options->antialias = other->antialias;
options->subpixel_order = other->subpixel_order;
options->lcd_filter = other->lcd_filter;
options->hint_style = other->hint_style;
options->hint_metrics = other->hint_metrics;
options->round_glyph_positions = other->round_glyph_positions;
}
/**
@ -189,10 +208,14 @@ cairo_font_options_merge (cairo_font_options_t *options,
options->antialias = other->antialias;
if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
options->subpixel_order = other->subpixel_order;
if (other->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
options->lcd_filter = other->lcd_filter;
if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
options->hint_style = other->hint_style;
if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT)
options->hint_metrics = other->hint_metrics;
if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT)
options->round_glyph_positions = other->round_glyph_positions;
}
slim_hidden_def (cairo_font_options_merge);
@ -221,8 +244,10 @@ cairo_font_options_equal (const cairo_font_options_t *options,
return (options->antialias == other->antialias &&
options->subpixel_order == other->subpixel_order &&
options->lcd_filter == other->lcd_filter &&
options->hint_style == other->hint_style &&
options->hint_metrics == other->hint_metrics);
options->hint_metrics == other->hint_metrics &&
options->round_glyph_positions == other->round_glyph_positions);
}
slim_hidden_def (cairo_font_options_equal);
@ -246,7 +271,8 @@ cairo_font_options_hash (const cairo_font_options_t *options)
return ((options->antialias) |
(options->subpixel_order << 4) |
(options->hint_style << 8) |
(options->lcd_filter << 8) |
(options->hint_style << 12) |
(options->hint_metrics << 16));
}
slim_hidden_def (cairo_font_options_hash);
@ -327,6 +353,87 @@ cairo_font_options_get_subpixel_order (const cairo_font_options_t *options)
return options->subpixel_order;
}
/**
* _cairo_font_options_set_lcd_filter:
* @options: a #cairo_font_options_t
* @lcd_filter: the new LCD filter
*
* Sets the LCD filter for the font options object. The LCD filter
* specifies how pixels are filtered when rendered with an antialiasing
* mode of %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
* #cairo_lcd_filter_t for full details.
*
* Since: 1.8
**/
void
_cairo_font_options_set_lcd_filter (cairo_font_options_t *options,
cairo_lcd_filter_t lcd_filter)
{
if (cairo_font_options_status (options))
return;
options->lcd_filter = lcd_filter;
}
/**
* _cairo_font_options_get_lcd_filter:
* @options: a #cairo_font_options_t
*
* Gets the LCD filter for the font options object.
* See the documentation for #cairo_lcd_filter_t for full details.
*
* Return value: the LCD filter for the font options object
*
* Since: 1.8
**/
cairo_lcd_filter_t
_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_LCD_FILTER_DEFAULT;
return options->lcd_filter;
}
/**
* _cairo_font_options_set_round_glyph_positions:
* @options: a #cairo_font_options_t
* @round: the new rounding value
*
* Sets the rounding options for the font options object. If rounding is set, a
* glyph's position will be rounded to integer values.
*
* Since: 1.12
**/
void
_cairo_font_options_set_round_glyph_positions (cairo_font_options_t *options,
cairo_round_glyph_positions_t round)
{
if (cairo_font_options_status (options))
return;
options->round_glyph_positions = round;
}
/**
* _cairo_font_options_get_round_glyph_positions:
* @options: a #cairo_font_options_t
*
* Gets the glyph position rounding option for the font options object.
*
* Return value: The round glyph posistions flag for the font options object.
*
* Since: 1.12
**/
cairo_round_glyph_positions_t
_cairo_font_options_get_round_glyph_positions (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_ROUND_GLYPH_POS_DEFAULT;
return options->round_glyph_positions;
}
/**
* cairo_font_options_set_hint_style:
* @options: a #cairo_font_options_t

View File

@ -0,0 +1,78 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2000 Keith Packard
* Copyright © 2005 Red Hat, Inc
* Copyright © 2010 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
* Keith Packard <keithp@keithp.com>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef _CAIRO_FONTCONFIG_PRIVATE_H
#define _CAIRO_FONTCONFIG_PRIVATE_H
#include "cairo.h"
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
#endif
/* sub-pixel order */
#ifndef FC_RGBA_UNKNOWN
#define FC_RGBA_UNKNOWN 0
#define FC_RGBA_RGB 1
#define FC_RGBA_BGR 2
#define FC_RGBA_VRGB 3
#define FC_RGBA_VBGR 4
#define FC_RGBA_NONE 5
#endif
/* hinting style */
#ifndef FC_HINT_NONE
#define FC_HINT_NONE 0
#define FC_HINT_SLIGHT 1
#define FC_HINT_MEDIUM 2
#define FC_HINT_FULL 3
#endif
/* LCD filter */
#ifndef FC_LCD_NONE
#define FC_LCD_NONE 0
#define FC_LCD_DEFAULT 1
#define FC_LCD_LIGHT 2
#define FC_LCD_LEGACY 3
#endif
#endif /* _CAIRO_FONTCONFIG_PRIVATE_H */

View File

@ -0,0 +1,129 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_FREED_POOL_H
#define CAIRO_FREED_POOL_H
#include "cairoint.h"
#include "cairo-atomic-private.h"
#if HAS_ATOMIC_OPS
/* Keep a stash of recently freed clip_paths, since we need to
* reallocate them frequently.
*/
#define MAX_FREED_POOL_SIZE 4
typedef struct {
void *pool[MAX_FREED_POOL_SIZE];
int top;
} freed_pool_t;
static cairo_always_inline void *
_atomic_fetch (void **slot)
{
void *ptr;
do {
ptr = _cairo_atomic_ptr_get (slot);
} while (! _cairo_atomic_ptr_cmpxchg (slot, ptr, NULL));
return ptr;
}
static cairo_always_inline cairo_bool_t
_atomic_store (void **slot, void *ptr)
{
return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr);
}
cairo_private void *
_freed_pool_get_search (freed_pool_t *pool);
static inline void *
_freed_pool_get (freed_pool_t *pool)
{
void *ptr;
int i;
i = pool->top - 1;
if (i < 0)
i = 0;
ptr = _atomic_fetch (&pool->pool[i]);
if (likely (ptr != NULL)) {
pool->top = i;
return ptr;
}
/* either empty or contended */
return _freed_pool_get_search (pool);
}
cairo_private void
_freed_pool_put_search (freed_pool_t *pool, void *ptr);
static inline void
_freed_pool_put (freed_pool_t *pool, void *ptr)
{
int i;
i = pool->top;
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], ptr)))
{
pool->top = i + 1;
return;
}
/* either full or contended */
_freed_pool_put_search (pool, ptr);
}
cairo_private void
_freed_pool_reset (freed_pool_t *pool);
#define HAS_FREED_POOL 1
#else
typedef int freed_pool_t;
#define _freed_pool_get(pool) NULL
#define _freed_pool_put(pool, ptr) free(ptr)
#define _freed_pool_reset(ptr)
#endif
#endif /* CAIRO_FREED_POOL_PRIVATE_H */

View File

@ -0,0 +1,93 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-freed-pool-private.h"
#if HAS_FREED_POOL
void *
_freed_pool_get_search (freed_pool_t *pool)
{
void *ptr;
int i;
for (i = ARRAY_LENGTH (pool->pool); i--;) {
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
pool->top = i;
return ptr;
}
}
/* empty */
pool->top = 0;
return NULL;
}
void
_freed_pool_put_search (freed_pool_t *pool, void *ptr)
{
int i;
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], ptr)) {
pool->top = i + 1;
return;
}
}
/* full */
pool->top = i;
free (ptr);
}
void
_freed_pool_reset (freed_pool_t *pool)
{
int i;
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
free (pool->pool[i]);
pool->pool[i] = NULL;
}
pool->top = 0;
}
#endif

View File

@ -24,6 +24,7 @@
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-freelist-type-private.h"
/* for stand-alone compilation*/
#ifndef VG
@ -34,32 +35,6 @@
#define NULL (void *) 0
#endif
typedef struct _cairo_freelist_node cairo_freelist_node_t;
struct _cairo_freelist_node {
cairo_freelist_node_t *next;
};
typedef struct _cairo_freelist {
cairo_freelist_node_t *first_free_node;
unsigned nodesize;
} cairo_freelist_t;
typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
struct _cairo_freelist_pool {
cairo_freelist_pool_t *next;
unsigned size, rem;
uint8_t *data;
};
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_pool_t *pools;
unsigned nodesize;
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
} cairo_freepool_t;
/* Initialise a freelist that will be responsible for allocating
* nodes of size nodesize. */
cairo_private void
@ -96,6 +71,20 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize);
cairo_private void
_cairo_freepool_fini (cairo_freepool_t *freepool);
static inline void
_cairo_freepool_reset (cairo_freepool_t *freepool)
{
while (freepool->pools != &freepool->embedded_pool) {
cairo_freelist_pool_t *pool = freepool->pools;
freepool->pools = pool->next;
pool->next = freepool->freepools;
freepool->freepools = pool;
}
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
}
cairo_private void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);

View File

@ -0,0 +1,54 @@
/*
* Copyright © 2010 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef CAIRO_FREELIST_TYPE_H
#define CAIRO_FREELIST_TYPE_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
typedef struct _cairo_freelist_node cairo_freelist_node_t;
struct _cairo_freelist_node {
cairo_freelist_node_t *next;
};
typedef struct _cairo_freelist {
cairo_freelist_node_t *first_free_node;
unsigned nodesize;
} cairo_freelist_t;
typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
struct _cairo_freelist_pool {
cairo_freelist_pool_t *next;
unsigned size, rem;
uint8_t *data;
};
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_pool_t *pools;
cairo_freelist_pool_t *freepools;
unsigned nodesize;
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
} cairo_freepool_t;
#endif /* CAIRO_FREELIST_TYPE_H */

View File

@ -22,6 +22,7 @@
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
void
@ -83,12 +84,12 @@ _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
}
}
void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
{
freepool->first_free_node = NULL;
freepool->pools = &freepool->embedded_pool;
freepool->freepools = NULL;
freepool->nodesize = nodesize;
freepool->embedded_pool.next = NULL;
@ -96,19 +97,28 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data,
sizeof (freepool->embedded_data)));
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data)));
}
void
_cairo_freepool_fini (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool = freepool->pools;
cairo_freelist_pool_t *pool;
pool = freepool->pools;
while (pool != &freepool->embedded_pool) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
pool = freepool->freepools;
while (pool != NULL) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
}
@ -118,23 +128,31 @@ _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
cairo_freelist_pool_t *pool;
int poolsize;
if (freepool->pools != &freepool->embedded_pool)
poolsize = 2 * freepool->pools->size;
else
poolsize = (128 * freepool->nodesize + 8191) & -8192;
pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
if (unlikely (pool == NULL))
return pool;
if (freepool->freepools != NULL) {
pool = freepool->freepools;
freepool->freepools = pool->next;
poolsize = pool->size;
} else {
if (freepool->pools != &freepool->embedded_pool)
poolsize = 2 * freepool->pools->size;
else
poolsize = (128 * freepool->nodesize + 8191) & -8192;
pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
if (unlikely (pool == NULL))
return pool;
pool->size = poolsize;
}
pool->next = freepool->pools;
freepool->pools = pool;
pool->size = poolsize;
pool->rem = poolsize - freepool->nodesize;
pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize));
VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize));
VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem));
return pool + 1;
}

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -41,14 +41,12 @@
#define _BSD_SOURCE /* for strdup() */
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-ft-private.h"
#include <float.h>
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
#endif
#include "cairo-fontconfig-private.h"
#include <ft2build.h>
#include FT_FREETYPE_H
@ -59,6 +57,30 @@
#include FT_SYNTHESIS_H
#endif
#if HAVE_FT_LIBRARY_SETLCDFILTER
#include FT_LCD_FILTER_H
#endif
/* Fontconfig version older than 2.6 didn't have these options */
#ifndef FC_LCD_FILTER
#define FC_LCD_FILTER "lcdfilter"
#endif
/* Some Ubuntu versions defined FC_LCD_FILTER without defining the following */
#ifndef FC_LCD_NONE
#define FC_LCD_NONE 0
#define FC_LCD_DEFAULT 1
#define FC_LCD_LIGHT 2
#define FC_LCD_LEGACY 3
#endif
/* FreeType version older than 2.3.5(?) didn't have these options */
#ifndef FT_LCD_FILTER_NONE
#define FT_LCD_FILTER_NONE 0
#define FT_LCD_FILTER_DEFAULT 1
#define FT_LCD_FILTER_LIGHT 2
#define FT_LCD_FILTER_LEGACY 16
#endif
#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
@ -67,11 +89,35 @@
/* This is the max number of FT_face objects we keep open at once
*/
#define MAX_OPEN_FACES 10
/* This is the maximum font size we allow to be passed to FT_Set_Char_Size
*/
#define MAX_FONT_SIZE 1000
/**
* SECTION:cairo-ft
* @Title: FreeType Fonts
* @Short_Description: Font support for FreeType
* @See_Also: #cairo_font_face_t
*
* The FreeType font backend is primarily used to render text on GNU/Linux
* systems, but can be used on other platforms too.
*/
/**
* CAIRO_HAS_FT_FONT:
*
* Defined if the FreeType font backend is available.
* This macro can be used to conditionally compile backend-specific code.
*/
/**
* CAIRO_HAS_FC_FONT:
*
* Defined if the Fontconfig-specific functions of the FreeType font backend
* are available.
* This macro can be used to conditionally compile backend-specific code.
*/
/*
* The simple 2x2 matrix is converted into separate scale and shape
* factors so that hinting works right
@ -180,6 +226,7 @@ typedef struct _cairo_ft_unscaled_font_map {
static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL;
static void
_font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map,
cairo_ft_unscaled_font_t *unscaled)
@ -779,23 +826,279 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
return CAIRO_STATUS_SUCCESS;
}
/* Empirically-derived subpixel filtering values thanks to Keith
* Packard and libXft. */
static const int filters[3][3] = {
/* red */
#if 0
{ 65538*4/7,65538*2/7,65538*1/7 },
/* green */
{ 65536*1/4, 65536*2/4, 65537*1/4 },
/* blue */
{ 65538*1/7,65538*2/7,65538*4/7 },
#endif
{ 65538*9/13,65538*3/13,65538*1/13 },
/* green */
{ 65538*1/6, 65538*4/6, 65538*1/6 },
/* blue */
{ 65538*1/13,65538*3/13,65538*9/13 },
};
/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot
* into a different format. For example, we want to convert a
* FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit
* ARGB or ABGR bitmap.
*
* this function prepares a target descriptor for this operation.
*
* input :: target bitmap descriptor. The function will set its
* 'width', 'rows' and 'pitch' fields, and only these
*
* slot :: the glyph slot containing the source bitmap. this
* function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP
*
* mode :: the requested final rendering mode. supported values are
* MONO, NORMAL (i.e. gray), LCD and LCD_V
*
* the function returns the size in bytes of the corresponding buffer,
* it's up to the caller to allocate the corresponding memory block
* before calling _fill_xrender_bitmap
*
* it also returns -1 in case of error (e.g. incompatible arguments,
* like trying to convert a gray bitmap into a monochrome one)
*/
static int
_compute_xrender_bitmap_size(FT_Bitmap *target,
FT_GlyphSlot slot,
FT_Render_Mode mode)
{
FT_Bitmap *ftbit;
int width, height, pitch;
if (slot->format != FT_GLYPH_FORMAT_BITMAP)
return -1;
/* compute the size of the final bitmap */
ftbit = &slot->bitmap;
width = ftbit->width;
height = ftbit->rows;
pitch = (width + 3) & ~3;
switch (ftbit->pixel_mode) {
case FT_PIXEL_MODE_MONO:
if (mode == FT_RENDER_MODE_MONO) {
pitch = (((width + 31) & ~31) >> 3);
break;
}
/* fall-through */
case FT_PIXEL_MODE_GRAY:
if (mode == FT_RENDER_MODE_LCD ||
mode == FT_RENDER_MODE_LCD_V)
{
/* each pixel is replicated into a 32-bit ARGB value */
pitch = width * 4;
}
break;
case FT_PIXEL_MODE_LCD:
if (mode != FT_RENDER_MODE_LCD)
return -1;
/* horz pixel triplets are packed into 32-bit ARGB values */
width /= 3;
pitch = width * 4;
break;
case FT_PIXEL_MODE_LCD_V:
if (mode != FT_RENDER_MODE_LCD_V)
return -1;
/* vert pixel triplets are packed into 32-bit ARGB values */
height /= 3;
pitch = width * 4;
break;
default: /* unsupported source format */
return -1;
}
target->width = width;
target->rows = height;
target->pitch = pitch;
target->buffer = NULL;
return pitch * height;
}
/* this functions converts the glyph bitmap found in a FT_GlyphSlot
* into a different format (see _compute_xrender_bitmap_size)
*
* you should call this function after _compute_xrender_bitmap_size
*
* target :: target bitmap descriptor. Note that its 'buffer' pointer
* must point to memory allocated by the caller
*
* slot :: the glyph slot containing the source bitmap
*
* mode :: the requested final rendering mode
*
* bgr :: boolean, set if BGR or VBGR pixel ordering is needed
*/
static void
_fill_xrender_bitmap(FT_Bitmap *target,
FT_GlyphSlot slot,
FT_Render_Mode mode,
int bgr)
{
FT_Bitmap *ftbit = &slot->bitmap;
unsigned char *srcLine = ftbit->buffer;
unsigned char *dstLine = target->buffer;
int src_pitch = ftbit->pitch;
int width = target->width;
int height = target->rows;
int pitch = target->pitch;
int subpixel;
int h;
subpixel = (mode == FT_RENDER_MODE_LCD ||
mode == FT_RENDER_MODE_LCD_V);
if (src_pitch < 0)
srcLine -= src_pitch * (ftbit->rows - 1);
target->pixel_mode = ftbit->pixel_mode;
switch (ftbit->pixel_mode) {
case FT_PIXEL_MODE_MONO:
if (subpixel) {
/* convert mono to ARGB32 values */
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
int x;
for (x = 0; x < width; x++) {
if (srcLine[(x >> 3)] & (0x80 >> (x & 7)))
((unsigned int *) dstLine)[x] = 0xffffffffU;
}
}
target->pixel_mode = FT_PIXEL_MODE_LCD;
} else if (mode == FT_RENDER_MODE_NORMAL) {
/* convert mono to 8-bit gray */
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
int x;
for (x = 0; x < width; x++) {
if (srcLine[(x >> 3)] & (0x80 >> (x & 7)))
dstLine[x] = 0xff;
}
}
target->pixel_mode = FT_PIXEL_MODE_GRAY;
} else {
/* copy mono to mono */
int bytes = (width + 7) >> 3;
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch)
memcpy (dstLine, srcLine, bytes);
}
break;
case FT_PIXEL_MODE_GRAY:
if (subpixel) {
/* convert gray to ARGB32 values */
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
int x;
unsigned int *dst = (unsigned int *) dstLine;
for (x = 0; x < width; x++) {
unsigned int pix = srcLine[x];
pix |= (pix << 8);
pix |= (pix << 16);
dst[x] = pix;
}
}
target->pixel_mode = FT_PIXEL_MODE_LCD;
} else {
/* copy gray into gray */
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch)
memcpy (dstLine, srcLine, width);
}
break;
case FT_PIXEL_MODE_LCD:
if (!bgr) {
/* convert horizontal RGB into ARGB32 */
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
int x;
unsigned char *src = srcLine;
unsigned int *dst = (unsigned int *) dstLine;
for (x = 0; x < width; x++, src += 3) {
unsigned int pix;
pix = ((unsigned int)src[0] << 16) |
((unsigned int)src[1] << 8) |
((unsigned int)src[2] ) |
((unsigned int)src[1] << 24) ;
dst[x] = pix;
}
}
} else {
/* convert horizontal BGR into ARGB32 */
for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
int x;
unsigned char *src = srcLine;
unsigned int *dst = (unsigned int *) dstLine;
for (x = 0; x < width; x++, src += 3) {
unsigned int pix;
pix = ((unsigned int)src[2] << 16) |
((unsigned int)src[1] << 8) |
((unsigned int)src[0] ) |
((unsigned int)src[1] << 24) ;
dst[x] = pix;
}
}
}
break;
default: /* FT_PIXEL_MODE_LCD_V */
/* convert vertical RGB into ARGB32 */
if (!bgr) {
for (h = height; h > 0; h--, srcLine += 3 * src_pitch, dstLine += pitch) {
int x;
unsigned char* src = srcLine;
unsigned int* dst = (unsigned int *) dstLine;
for (x = 0; x < width; x++, src += 1) {
unsigned int pix;
pix = ((unsigned int)src[0] << 16) |
((unsigned int)src[src_pitch] << 8) |
((unsigned int)src[src_pitch*2] ) |
((unsigned int)src[src_pitch] << 24) ;
dst[x] = pix;
}
}
} else {
for (h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch) {
int x;
unsigned char *src = srcLine;
unsigned int *dst = (unsigned int *) dstLine;
for (x = 0; x < width; x++, src += 1) {
unsigned int pix;
pix = ((unsigned int)src[src_pitch * 2] << 16) |
((unsigned int)src[src_pitch] << 8) |
((unsigned int)src[0] ) |
((unsigned int)src[src_pitch] << 24) ;
dst[x] = pix;
}
}
}
}
}
/* Fills in val->image with an image surface created from @bitmap
*/
@ -808,6 +1111,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
int width, height, stride;
unsigned char *data;
int format = CAIRO_FORMAT_A8;
cairo_image_surface_t *image;
width = bitmap->width;
height = bitmap->rows;
@ -864,11 +1168,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
case FT_PIXEL_MODE_LCD:
case FT_PIXEL_MODE_LCD_V:
case FT_PIXEL_MODE_GRAY:
switch (font_options->antialias) {
case CAIRO_ANTIALIAS_DEFAULT:
case CAIRO_ANTIALIAS_GRAY:
case CAIRO_ANTIALIAS_NONE:
default:
if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) {
stride = bitmap->pitch;
if (own_buffer) {
data = bitmap->buffer;
@ -879,104 +1179,18 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
memcpy (data, bitmap->buffer, stride * height);
}
format = CAIRO_FORMAT_A8;
break;
case CAIRO_ANTIALIAS_SUBPIXEL: {
int x, y;
unsigned char *in_line, *out_line, *in;
unsigned int *out;
unsigned int red, green, blue;
int rf, gf, bf;
int s;
int o, os;
unsigned char *data_rgba;
unsigned int width_rgba, stride_rgba;
int vmul = 1;
int hmul = 1;
switch (font_options->subpixel_order) {
case CAIRO_SUBPIXEL_ORDER_DEFAULT:
case CAIRO_SUBPIXEL_ORDER_RGB:
case CAIRO_SUBPIXEL_ORDER_BGR:
default:
width /= 3;
hmul = 3;
break;
case CAIRO_SUBPIXEL_ORDER_VRGB:
case CAIRO_SUBPIXEL_ORDER_VBGR:
vmul = 3;
height /= 3;
break;
}
/*
* Filter the glyph to soften the color fringes
*/
width_rgba = width;
stride = bitmap->pitch;
stride_rgba = (width_rgba * 4 + 3) & ~3;
data_rgba = calloc (stride_rgba, height);
if (unlikely (data_rgba == NULL)) {
if (own_buffer)
free (bitmap->buffer);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
format = CAIRO_FORMAT_A8;
} else {
/* if we get there, the data from the source bitmap
* really comes from _fill_xrender_bitmap, and is
* made of 32-bit ARGB or ABGR values */
assert (own_buffer != 0);
assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY);
os = 1;
switch (font_options->subpixel_order) {
case CAIRO_SUBPIXEL_ORDER_VRGB:
os = stride;
case CAIRO_SUBPIXEL_ORDER_DEFAULT:
case CAIRO_SUBPIXEL_ORDER_RGB:
default:
rf = 0;
gf = 1;
bf = 2;
break;
case CAIRO_SUBPIXEL_ORDER_VBGR:
os = stride;
case CAIRO_SUBPIXEL_ORDER_BGR:
bf = 0;
gf = 1;
rf = 2;
break;
}
in_line = bitmap->buffer;
out_line = data_rgba;
for (y = 0; y < height; y++)
{
in = in_line;
out = (unsigned int *) out_line;
in_line += stride * vmul;
out_line += stride_rgba;
for (x = 0; x < width * hmul; x += hmul)
{
red = green = blue = 0;
o = 0;
for (s = 0; s < 3; s++)
{
red += filters[rf][s]*in[x+o];
green += filters[gf][s]*in[x+o];
blue += filters[bf][s]*in[x+o];
o += os;
}
red = red / 65536;
green = green / 65536;
blue = blue / 65536;
*out++ = (green << 24) | (red << 16) | (green << 8) | blue;
}
}
/* Images here are stored in native format. The
* backend must convert to its own format as needed
*/
if (own_buffer)
free (bitmap->buffer);
data = data_rgba;
stride = stride_rgba;
format = CAIRO_FORMAT_ARGB32;
break;
}
data = bitmap->buffer;
stride = bitmap->pitch;
format = CAIRO_FORMAT_ARGB32;
}
break;
case FT_PIXEL_MODE_GRAY2:
@ -988,18 +1202,22 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
*surface = (cairo_image_surface_t *)
/* XXX */
*surface = image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (data,
format,
width, height, stride);
if ((*surface)->base.status) {
if (image->base.status) {
free (data);
return (*surface)->base.status;
}
_cairo_image_surface_assume_ownership_of_data ((*surface));
if (format == CAIRO_FORMAT_ARGB32)
pixman_image_set_component_alpha (image->pixman_image, TRUE);
_cairo_debug_check_image_surface_is_defined (&(*surface)->base);
_cairo_image_surface_assume_ownership_of_data (image);
_cairo_debug_check_image_surface_is_defined (&image->base);
return CAIRO_STATUS_SUCCESS;
}
@ -1024,16 +1242,59 @@ _render_glyph_outline (FT_Face face,
cairo_font_options_t *font_options,
cairo_image_surface_t **surface)
{
int rgba = FC_RGBA_UNKNOWN;
int lcd_filter = FT_LCD_FILTER_LEGACY;
FT_GlyphSlot glyphslot = face->glyph;
FT_Outline *outline = &glyphslot->outline;
FT_Bitmap bitmap;
FT_BBox cbox;
FT_Matrix matrix;
int hmul = 1;
int vmul = 1;
unsigned int width, height, stride;
cairo_bool_t subpixel = FALSE;
unsigned int width, height;
cairo_status_t status;
FT_Error fterror;
FT_Library library = glyphslot->library;
FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
switch (font_options->antialias) {
case CAIRO_ANTIALIAS_NONE:
render_mode = FT_RENDER_MODE_MONO;
break;
case CAIRO_ANTIALIAS_SUBPIXEL:
switch (font_options->subpixel_order) {
case CAIRO_SUBPIXEL_ORDER_DEFAULT:
case CAIRO_SUBPIXEL_ORDER_RGB:
case CAIRO_SUBPIXEL_ORDER_BGR:
render_mode = FT_RENDER_MODE_LCD;
break;
case CAIRO_SUBPIXEL_ORDER_VRGB:
case CAIRO_SUBPIXEL_ORDER_VBGR:
render_mode = FT_RENDER_MODE_LCD_V;
break;
}
switch (font_options->lcd_filter) {
case CAIRO_LCD_FILTER_NONE:
lcd_filter = FT_LCD_FILTER_NONE;
break;
case CAIRO_LCD_FILTER_DEFAULT:
case CAIRO_LCD_FILTER_INTRA_PIXEL:
lcd_filter = FT_LCD_FILTER_LEGACY;
break;
case CAIRO_LCD_FILTER_FIR3:
lcd_filter = FT_LCD_FILTER_LIGHT;
break;
case CAIRO_LCD_FILTER_FIR5:
lcd_filter = FT_LCD_FILTER_DEFAULT;
break;
}
break;
case CAIRO_ANTIALIAS_DEFAULT:
case CAIRO_ANTIALIAS_GRAY:
render_mode = FT_RENDER_MODE_NORMAL;
}
FT_Outline_Get_CBox (outline, &cbox);
@ -1044,20 +1305,21 @@ _render_glyph_outline (FT_Face face,
width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
stride = (width * hmul + 3) & ~3;
if (width * height == 0) {
cairo_format_t format;
/* Looks like fb handles zero-sized images just fine */
switch (font_options->antialias) {
case CAIRO_ANTIALIAS_NONE:
switch (render_mode) {
case FT_RENDER_MODE_MONO:
format = CAIRO_FORMAT_A1;
break;
case CAIRO_ANTIALIAS_SUBPIXEL:
case FT_RENDER_MODE_LCD:
case FT_RENDER_MODE_LCD_V:
format= CAIRO_FORMAT_ARGB32;
break;
case CAIRO_ANTIALIAS_DEFAULT:
case CAIRO_ANTIALIAS_GRAY:
case FT_RENDER_MODE_LIGHT:
case FT_RENDER_MODE_NORMAL:
case FT_RENDER_MODE_MAX:
default:
format = CAIRO_FORMAT_A8;
break;
@ -1067,75 +1329,74 @@ _render_glyph_outline (FT_Face face,
cairo_image_surface_create_for_data (NULL, format, 0, 0, 0);
if ((*surface)->base.status)
return (*surface)->base.status;
} else {
} else {
matrix.xx = matrix.yy = 0x10000L;
matrix.xy = matrix.yx = 0;
int bitmap_size;
switch (font_options->antialias) {
case CAIRO_ANTIALIAS_NONE:
bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
bitmap.num_grays = 1;
stride = ((width + 31) & -32) >> 3;
break;
case CAIRO_ANTIALIAS_DEFAULT:
case CAIRO_ANTIALIAS_GRAY:
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
bitmap.num_grays = 256;
stride = (width + 3) & -4;
break;
case CAIRO_ANTIALIAS_SUBPIXEL:
switch (font_options->subpixel_order) {
case CAIRO_SUBPIXEL_ORDER_RGB:
case CAIRO_SUBPIXEL_ORDER_BGR:
case CAIRO_SUBPIXEL_ORDER_DEFAULT:
default:
matrix.xx *= 3;
hmul = 3;
subpixel = TRUE;
break;
case CAIRO_SUBPIXEL_ORDER_VRGB:
case CAIRO_SUBPIXEL_ORDER_VBGR:
matrix.yy *= 3;
vmul = 3;
subpixel = TRUE;
break;
switch (render_mode) {
case FT_RENDER_MODE_LCD:
if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) {
rgba = FC_RGBA_BGR;
} else {
rgba = FC_RGBA_RGB;
}
case FT_RENDER_MODE_LCD_V:
if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) {
rgba = FC_RGBA_VBGR;
} else {
rgba = FC_RGBA_VRGB;
}
break;
case FT_RENDER_MODE_MONO:
case FT_RENDER_MODE_LIGHT:
case FT_RENDER_MODE_NORMAL:
case FT_RENDER_MODE_MAX:
default:
break;
}
FT_Outline_Transform (outline, &matrix);
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
bitmap.num_grays = 256;
stride = (width * hmul + 3) & -4;
}
#if HAVE_FT_LIBRARY_SETLCDFILTER
FT_Library_SetLcdFilter (library, lcd_filter);
#endif
bitmap.pitch = stride;
bitmap.width = width * hmul;
bitmap.rows = height * vmul;
bitmap.buffer = calloc (stride, bitmap.rows);
if (unlikely (bitmap.buffer == NULL))
fterror = FT_Render_Glyph (face->glyph, render_mode);
#if HAVE_FT_LIBRARY_SETLCDFILTER
FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE);
#endif
if (fterror != 0)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
bitmap_size = _compute_xrender_bitmap_size (&bitmap,
face->glyph,
render_mode);
if (bitmap_size < 0)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
bitmap.buffer = calloc (1, bitmap_size);
if (bitmap.buffer == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
free (bitmap.buffer);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
_fill_xrender_bitmap (&bitmap, face->glyph, render_mode,
(rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR));
/* Note:
* _get_bitmap_surface will free bitmap.buffer if there is an error
*/
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface);
if (unlikely (status))
return status;
}
/*
* Note: the font's coordinate system is upside down from ours, so the
* Y coordinate of the control box needs to be negated. Moreover, device
* offsets are position of glyph origin relative to top left while xMin
* and yMax are offsets of top left relative to origin. Another negation.
*/
cairo_surface_set_device_offset (&(*surface)->base,
floor (-(double) cbox.xMin / 64.0),
floor (+(double) cbox.yMax / 64.0));
/* Note: the font's coordinate system is upside down from ours, so the
* Y coordinate of the control box needs to be negated. Moreover, device
* offsets are position of glyph origin relative to top left while xMin
* and yMax are offsets of top left relative to origin. Another negation.
*/
cairo_surface_set_device_offset (&(*surface)->base,
(double)-glyphslot->bitmap_left,
(double)+glyphslot->bitmap_top);
}
return CAIRO_STATUS_SUCCESS;
}
@ -1207,8 +1468,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
original_to_transformed = *shape;
cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y);
orig_width = cairo_image_surface_get_width (&(*surface)->base);
orig_height = cairo_image_surface_get_height (&(*surface)->base);
orig_width = (*surface)->width;
orig_height = (*surface)->height;
cairo_matrix_translate (&original_to_transformed,
-origin_x, -origin_y);
@ -1246,9 +1507,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
original_to_transformed.x0 -= x_min;
original_to_transformed.y0 -= y_min;
/* Create the transformed bitmap
*/
width = x_max - x_min;
/* Create the transformed bitmap */
width = x_max - x_min;
height = y_max - y_min;
transformed_to_original = original_to_transformed;
@ -1256,30 +1516,19 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
if (unlikely (status))
return status;
/* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */
width = (width + 3) & ~3;
image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
if (unlikely (image->status))
return image->status;
/* Initialize it to empty
*/
status = _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR,
CAIRO_COLOR_TRANSPARENT,
0, 0,
width, height);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
/* Draw the original bitmap transformed into the new bitmap
*/
_cairo_pattern_init_for_surface (&pattern, &(*surface)->base);
cairo_pattern_set_matrix (&pattern.base, &transformed_to_original);
status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER,
&pattern.base, NULL);
status = _cairo_surface_paint (image,
CAIRO_OPERATOR_SOURCE,
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
@ -1355,6 +1604,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
if (antialias) {
cairo_subpixel_order_t subpixel_order;
int lcd_filter;
/* disable hinting if requested */
if (FcPatternGetBool (pattern,
@ -1390,6 +1640,25 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
}
if (FcPatternGetInteger (pattern,
FC_LCD_FILTER, 0, &lcd_filter) == FcResultMatch)
{
switch (lcd_filter) {
case FC_LCD_NONE:
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE;
break;
case FC_LCD_DEFAULT:
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5;
break;
case FC_LCD_LIGHT:
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3;
break;
case FC_LCD_LEGACY:
ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL;
break;
}
}
#ifdef FC_HINT_STYLE
if (FcPatternGetInteger (pattern,
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
@ -1491,6 +1760,12 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
if (other->base.hint_style == CAIRO_HINT_STYLE_NONE)
options->base.hint_style = CAIRO_HINT_STYLE_NONE;
if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT)
options->base.lcd_filter = other->base.lcd_filter;
if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE)
options->base.lcd_filter = CAIRO_LCD_FILTER_NONE;
if (options->base.antialias == CAIRO_ANTIALIAS_NONE) {
if (options->base.hint_style == CAIRO_HINT_STYLE_NONE)
load_flags |= FT_LOAD_NO_HINTING;
@ -1514,11 +1789,11 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
case CAIRO_SUBPIXEL_ORDER_DEFAULT:
case CAIRO_SUBPIXEL_ORDER_RGB:
case CAIRO_SUBPIXEL_ORDER_BGR:
load_target |= FT_LOAD_TARGET_LCD;
load_target = FT_LOAD_TARGET_LCD;
break;
case CAIRO_SUBPIXEL_ORDER_VRGB:
case CAIRO_SUBPIXEL_ORDER_VBGR:
load_target |= FT_LOAD_TARGET_LCD_V;
load_target = FT_LOAD_TARGET_LCD_V;
break;
}
}
@ -2517,6 +2792,34 @@ _cairo_ft_font_options_substitute (const cairo_font_options_t *options,
}
}
if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
{
if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch)
{
int lcd_filter;
switch (options->lcd_filter) {
case CAIRO_LCD_FILTER_NONE:
lcd_filter = FT_LCD_FILTER_NONE;
break;
case CAIRO_LCD_FILTER_DEFAULT:
case CAIRO_LCD_FILTER_INTRA_PIXEL:
lcd_filter = FT_LCD_FILTER_LEGACY;
break;
case CAIRO_LCD_FILTER_FIR3:
lcd_filter = FT_LCD_FILTER_LIGHT;
break;
default:
case CAIRO_LCD_FILTER_FIR5:
lcd_filter = FT_LCD_FILTER_DEFAULT;
break;
}
if (! FcPatternAddInteger (pattern, FC_LCD_FILTER, lcd_filter))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT)
{
if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
@ -2638,13 +2941,11 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
}
status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled);
if (unlikely (status)) {
if (unlikely (status || unscaled == NULL)) {
font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
goto FREE_RESOLVED;
}
assert (unscaled != NULL);
_get_pattern_ft_options (resolved, &ft_options);
font_face = _cairo_ft_font_face_create (unscaled, &ft_options);
_cairo_unscaled_font_destroy (&unscaled->base);

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -1,6 +1,8 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
* Copyright © 2010 Intel Corporation
* Copyright © 2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -12,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -28,11 +30,17 @@
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributors:
* Benjamin Otte <otte@gnome.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
#define GLYPH_CACHE_WIDTH 1024
@ -47,40 +55,16 @@ typedef struct _cairo_gl_glyph_private {
} cairo_gl_glyph_private_t;
static cairo_status_t
_cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_gl_surface_t *cache_surface;
cairo_gl_glyph_private_t *glyph_private;
cairo_rtree_node_t *node = NULL;
cairo_image_surface_t *clone = NULL;
cairo_status_t status;
int width, height;
GLenum internal_format, format, type;
cairo_bool_t has_alpha;
if (! _cairo_gl_get_image_format_and_type (glyph_surface->pixman_format,
&internal_format,
&format,
&type,
&has_alpha))
{
cairo_bool_t is_supported;
clone = _cairo_image_surface_coerce (glyph_surface,
_cairo_format_from_content (glyph_surface->base.content));
if (unlikely (clone->base.status))
return clone->base.status;
is_supported =
_cairo_gl_get_image_format_and_type (clone->pixman_format,
&internal_format,
&format,
&type,
&has_alpha);
assert (is_supported);
glyph_surface = clone;
}
width = glyph_surface->width;
if (width < GLYPH_CACHE_MIN_SIZE)
@ -103,16 +87,17 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
if (status)
return status;
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_ROW_LENGTH,
glyph_surface->stride /
(PIXMAN_FORMAT_BPP (glyph_surface->pixman_format) / 8));
glTexSubImage2D (GL_TEXTURE_2D, 0,
node->x, node->y,
glyph_surface->width, glyph_surface->height,
format, type,
glyph_surface->data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
cache_surface = (cairo_gl_surface_t *) cache->pattern.surface;
/* XXX: Make sure we use the mask texture. This should work automagically somehow */
glActiveTexture (GL_TEXTURE1);
status = _cairo_gl_surface_draw_image (cache_surface,
glyph_surface,
0, 0,
glyph_surface->width, glyph_surface->height,
node->x, node->y);
if (unlikely (status))
return status;
scaled_glyph->surface_private = node;
node->owner = &scaled_glyph->surface_private;
@ -121,14 +106,16 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
glyph_private->cache = cache;
/* compute tex coords */
glyph_private->p1.x = node->x / (double) cache->width;
glyph_private->p1.y = node->y / (double) cache->height;
glyph_private->p2.x =
(node->x + glyph_surface->width) / (double) cache->width;
glyph_private->p2.y =
(node->y + glyph_surface->height) / (double) cache->height;
cairo_surface_destroy (&clone->base);
glyph_private->p1.x = node->x;
glyph_private->p1.y = node->y;
glyph_private->p2.x = node->x + glyph_surface->width;
glyph_private->p2.y = node->y + glyph_surface->height;
if (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base)) {
glyph_private->p1.x /= cache_surface->width;
glyph_private->p1.y /= cache_surface->height;
glyph_private->p2.x /= cache_surface->width;
glyph_private->p2.y /= cache_surface->height;
}
return CAIRO_STATUS_SUCCESS;
}
@ -140,53 +127,50 @@ _cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private);
}
static cairo_gl_glyph_cache_t *
static cairo_status_t
cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
cairo_format_t format)
cairo_format_t format,
cairo_gl_glyph_cache_t **cache_out)
{
cairo_gl_glyph_cache_t *cache;
cairo_content_t content;
switch (format) {
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
cache = &ctx->glyph_cache[0];
format = CAIRO_FORMAT_ARGB32;
content = CAIRO_CONTENT_COLOR_ALPHA;
break;
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
cache = &ctx->glyph_cache[1];
format = CAIRO_FORMAT_A8;
content = CAIRO_CONTENT_ALPHA;
break;
case CAIRO_FORMAT_INVALID:
ASSERT_NOT_REACHED;
return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
}
if (unlikely (cache->tex == 0)) {
GLenum internal_format;
cache->width = GLYPH_CACHE_WIDTH;
cache->height = GLYPH_CACHE_HEIGHT;
switch (format) {
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_RGB24:
ASSERT_NOT_REACHED;
case CAIRO_FORMAT_ARGB32:
internal_format = GL_RGBA;
break;
case CAIRO_FORMAT_A8:
internal_format = GL_ALPHA;
break;
}
glGenTextures (1, &cache->tex);
glBindTexture (GL_TEXTURE_2D, cache->tex);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D (GL_TEXTURE_2D, 0, internal_format,
GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, 0,
internal_format, GL_FLOAT, NULL);
if (unlikely (cache->pattern.surface == NULL)) {
cairo_surface_t *surface;
surface = cairo_gl_surface_create (&ctx->base,
content,
GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT);
if (unlikely (surface->status)) {
cairo_status_t status = surface->status;
cairo_surface_destroy (surface);
return status;
}
_cairo_surface_release_device_reference (surface);
_cairo_pattern_init_for_surface (&cache->pattern, surface);
cairo_surface_destroy (surface);
cache->pattern.base.has_component_alpha = (content == CAIRO_CONTENT_COLOR_ALPHA);
}
return cache;
*cache_out = cache;
return CAIRO_STATUS_SUCCESS;
}
static void
@ -199,12 +183,12 @@ static cairo_bool_t
_cairo_gl_surface_owns_font (cairo_gl_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
cairo_gl_context_t *font_private;
cairo_device_t *font_private;
font_private = scaled_font->surface_private;
if ((scaled_font->surface_backend != NULL &&
scaled_font->surface_backend != &_cairo_gl_surface_backend) ||
(font_private != NULL && font_private != surface->ctx))
(font_private != NULL && font_private != surface->base.device))
{
return FALSE;
}
@ -212,6 +196,12 @@ _cairo_gl_surface_owns_font (cairo_gl_surface_t *surface,
return TRUE;
}
void
_cairo_gl_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
cairo_list_del (&scaled_font->link);
}
void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font)
@ -229,109 +219,6 @@ _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
}
}
typedef struct _cairo_gl_glyphs_setup
{
unsigned int vbo_size; /* units of floats */
unsigned int vb_offset; /* units of floats */
unsigned int vertex_size; /* units of floats */
unsigned int num_prims;
float *vb;
cairo_gl_composite_setup_t *composite;
cairo_region_t *clip;
cairo_gl_surface_t *dst;
} cairo_gl_glyphs_setup_t;
static void
_cairo_gl_flush_glyphs (cairo_gl_context_t *ctx,
cairo_gl_glyphs_setup_t *setup)
{
int i;
if (setup->vb != NULL) {
glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
setup->vb = NULL;
if (setup->num_prims != 0) {
if (setup->clip) {
int num_rectangles = cairo_region_num_rectangles (setup->clip);
glEnable (GL_SCISSOR_TEST);
for (i = 0; i < num_rectangles; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (setup->clip, i, &rect);
glScissor (rect.x,
_cairo_gl_y_flip (setup->dst, rect.y),
rect.x + rect.width,
_cairo_gl_y_flip (setup->dst,
rect.y + rect.height));
glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
}
glDisable (GL_SCISSOR_TEST);
} else {
glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
}
setup->num_prims = 0;
}
}
}
static void
_cairo_gl_glyphs_emit_vertex (cairo_gl_glyphs_setup_t *setup,
int x, int y, float glyph_x, float glyph_y)
{
int i = 0;
float *vb = &setup->vb[setup->vb_offset];
cairo_surface_attributes_t *src_attributes;
src_attributes = &setup->composite->src.operand.texture.attributes;
vb[i++] = x;
vb[i++] = y;
vb[i++] = glyph_x;
vb[i++] = glyph_y;
if (setup->composite->src.type == OPERAND_TEXTURE) {
double s = x;
double t = y;
cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
vb[i++] = s;
vb[i++] = t;
}
setup->vb_offset += setup->vertex_size;
}
static void
_cairo_gl_emit_glyph_rectangle (cairo_gl_context_t *ctx,
cairo_gl_glyphs_setup_t *setup,
int x1, int y1,
int x2, int y2,
cairo_gl_glyph_private_t *glyph)
{
if (setup->vb != NULL &&
setup->vb_offset + 4 * setup->vertex_size > setup->vbo_size) {
_cairo_gl_flush_glyphs (ctx, setup);
}
if (setup->vb == NULL) {
glBufferDataARB (GL_ARRAY_BUFFER_ARB,
setup->vbo_size * sizeof (GLfloat),
NULL, GL_STREAM_DRAW_ARB);
setup->vb = glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
setup->vb_offset = 0;
}
_cairo_gl_glyphs_emit_vertex (setup, x1, y1, glyph->p1.x, glyph->p1.y);
_cairo_gl_glyphs_emit_vertex (setup, x2, y1, glyph->p2.x, glyph->p1.y);
_cairo_gl_glyphs_emit_vertex (setup, x2, y2, glyph->p2.x, glyph->p2.y);
_cairo_gl_glyphs_emit_vertex (setup, x1, y2, glyph->p1.x, glyph->p2.y);
setup->num_prims++;
}
static cairo_status_t
_render_glyphs (cairo_gl_surface_t *dst,
int dst_x, int dst_y,
@ -345,106 +232,51 @@ _render_glyphs (cairo_gl_surface_t *dst,
cairo_region_t *clip_region,
int *remaining_glyphs)
{
cairo_format_t last_format = (cairo_format_t) -1;
cairo_format_t last_format = CAIRO_FORMAT_INVALID;
cairo_gl_glyph_cache_t *cache = NULL;
cairo_gl_context_t *ctx;
cairo_gl_glyphs_setup_t setup;
cairo_gl_composite_setup_t composite_setup;
cairo_gl_composite_t setup;
cairo_status_t status;
int i = 0;
GLuint vbo = 0;
*has_component_alpha = FALSE;
status = _cairo_gl_operand_init (&composite_setup.src, source, dst,
glyph_extents->x, glyph_extents->y,
dst_x, dst_y,
glyph_extents->width,
glyph_extents->height);
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
return status;
ctx = _cairo_gl_context_acquire (dst->ctx);
/* Set up the IN operator for source IN mask.
*
* IN (normal, any op): dst.argb = src.argb * mask.aaaa
* IN (component, ADD): dst.argb = src.argb * mask.argb
*
* The mask channel selection for component alpha ADD will be updated in
* the loop over glyphs below.
*/
glActiveTexture (GL_TEXTURE1);
glEnable (GL_TEXTURE_2D);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
_cairo_gl_set_destination (dst);
/* If we're doing some CA glyphs, we're only doing it for ADD,
* which doesn't require the source alpha value in blending.
*/
_cairo_gl_set_operator (dst, op, FALSE);
_cairo_gl_set_src_operand (ctx, &composite_setup);
_cairo_scaled_font_freeze_cache (scaled_font);
status = _cairo_gl_composite_init (&setup, op, dst,
TRUE, glyph_extents);
if (unlikely (status))
goto FINISH;
if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP_FONT;
goto FINISH;
}
status = _cairo_gl_composite_set_source (&setup, source,
glyph_extents->x, glyph_extents->y,
dst_x, dst_y,
glyph_extents->width,
glyph_extents->height);
if (unlikely (status))
goto FINISH;
if (scaled_font->surface_private == NULL) {
/* XXX couple into list to remove on context destruction */
scaled_font->surface_private = ctx;
scaled_font->surface_backend = &_cairo_gl_surface_backend;
cairo_list_add (&scaled_font->link, &ctx->fonts);
}
/* Create our VBO so that we can accumulate a bunch of glyph primitives
* into one giant DrawArrays.
*/
memset(&setup, 0, sizeof(setup));
setup.composite = &composite_setup;
setup.clip = clip_region;
setup.dst = dst;
setup.vertex_size = 4;
if (composite_setup.src.type == OPERAND_TEXTURE)
setup.vertex_size += 2;
setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
if (setup.vbo_size > 4096)
setup.vbo_size = 4096;
glGenBuffersARB (1, &vbo);
glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo);
glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
(void *)(uintptr_t)(0));
glEnableClientState (GL_VERTEX_ARRAY);
if (composite_setup.src.type == OPERAND_TEXTURE) {
/* Note that we're packing texcoord 0 after texcoord 1, for
* convenience.
*/
glClientActiveTexture (GL_TEXTURE0);
glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
(void *)(uintptr_t)(4 * sizeof (GLfloat)));
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
}
glClientActiveTexture (GL_TEXTURE1);
glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
(void *)(uintptr_t)(2 * sizeof (GLfloat)));
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
_cairo_gl_composite_set_clip_region (&setup, clip_region);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
cairo_gl_glyph_private_t *glyph;
double x_offset, y_offset;
double x1, x2, y1, y2;
@ -468,39 +300,40 @@ _render_glyphs (cairo_gl_surface_t *dst,
}
if (scaled_glyph->surface->format != last_format) {
/* Switching textures, so flush any queued prims. */
_cairo_gl_flush_glyphs (ctx, &setup);
glActiveTexture (GL_TEXTURE1);
cache = cairo_gl_context_get_glyph_cache (ctx,
scaled_glyph->surface->format);
glBindTexture (GL_TEXTURE_2D, cache->tex);
status = cairo_gl_context_get_glyph_cache (ctx,
scaled_glyph->surface->format,
&cache);
if (unlikely (status))
goto FINISH;
last_format = scaled_glyph->surface->format;
/* If we're doing component alpha in this function, it should
* only be in the case of CAIRO_OPERATOR_ADD. In that case, we just
* need to make sure we send the rgb bits down to the destination.
*/
if (last_format == CAIRO_FORMAT_ARGB32) {
assert (op == CAIRO_OPERATOR_ADD);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
*has_component_alpha = TRUE;
} else {
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
}
/* XXX component alpha */
status = _cairo_gl_composite_set_mask (&setup,
&cache->pattern.base,
0, 0, 0, 0, 0, 0);
if (unlikely (status))
goto FINISH;
*has_component_alpha |= cache->pattern.base.has_component_alpha;
/* XXX: _cairo_gl_composite_begin() acquires the context a
* second time. Need to refactor this loop so this doesn't happen.
*/
status = _cairo_gl_composite_begin (&setup, &ctx);
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status))
goto FINISH;
}
if (scaled_glyph->surface_private == NULL) {
status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
/* Cache is full, so flush existing prims and try again. */
_cairo_gl_flush_glyphs (ctx, &setup);
_cairo_gl_composite_flush (ctx);
_cairo_gl_glyph_cache_unlock (cache);
status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
}
if (unlikely (_cairo_status_is_error (status)))
@ -515,40 +348,20 @@ _render_glyphs (cairo_gl_surface_t *dst,
x2 = x1 + scaled_glyph->surface->width;
y2 = y1 + scaled_glyph->surface->height;
_cairo_gl_emit_glyph_rectangle (ctx, &setup,
glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
_cairo_gl_composite_emit_glyph (ctx,
x1, y1, x2, y2,
_cairo_gl_glyph_cache_lock (cache, scaled_glyph));
glyph->p1.x, glyph->p1.y,
glyph->p2.x, glyph->p2.y);
}
status = CAIRO_STATUS_SUCCESS;
FINISH:
_cairo_gl_flush_glyphs (ctx, &setup);
CLEANUP_FONT:
_cairo_scaled_font_thaw_cache (scaled_font);
glDisable (GL_BLEND);
glDisable (GL_SCISSOR_TEST);
status = _cairo_gl_context_release (ctx, status);
glDisableClientState (GL_VERTEX_ARRAY);
glClientActiveTexture (GL_TEXTURE0);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glActiveTexture (GL_TEXTURE0);
glDisable (GL_TEXTURE_2D);
glClientActiveTexture (GL_TEXTURE1);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glActiveTexture (GL_TEXTURE1);
glDisable (GL_TEXTURE_2D);
if (vbo != 0) {
glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
glDeleteBuffersARB (1, &vbo);
}
_cairo_gl_context_release (ctx);
_cairo_gl_operand_destroy (&composite_setup.src);
_cairo_gl_composite_fini (&setup);
*remaining_glyphs = num_glyphs - i;
return status;
@ -567,26 +380,25 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
{
cairo_surface_t *mask;
cairo_status_t status;
cairo_solid_pattern_t solid;
cairo_bool_t has_component_alpha;
int i;
/* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
mask = cairo_gl_surface_create (dst->ctx,
CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents->width,
glyph_extents->height);
mask = cairo_gl_surface_create (dst->base.device,
CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents->width,
glyph_extents->height);
if (unlikely (mask->status))
return mask->status;
return mask->status;
for (i = 0; i < num_glyphs; i++) {
glyphs[i].x -= glyph_extents->x;
glyphs[i].y -= glyph_extents->y;
}
_cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR_ALPHA);
status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
CAIRO_OPERATOR_ADD, &solid.base,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
glyphs, num_glyphs, glyph_extents,
scaled_font, &has_component_alpha,
NULL, remaining_glyphs);
@ -610,6 +422,7 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
}
cairo_surface_destroy (mask);
return status;
}
@ -627,15 +440,11 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_rectangle_int_t surface_extents;
cairo_rectangle_int_t extents;
cairo_region_t *clip_region = NULL;
cairo_solid_pattern_t solid_pattern;
cairo_bool_t overlap, use_mask = FALSE;
cairo_bool_t has_component_alpha;
cairo_status_t status;
int i;
if (! GLEW_ARB_vertex_buffer_object)
return UNSUPPORTED ("requires ARB_vertex_buffer_object");
if (! _cairo_gl_operator_is_supported (op))
return UNSUPPORTED ("unsupported operator");
@ -646,18 +455,20 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst,
* since only _cairo_gl_surface_composite() currently supports component
* alpha.
*/
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
if (!use_mask && op != CAIRO_OPERATOR_OVER) {
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (!_cairo_status_is_error (status) &&
scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
{
use_mask = TRUE;
break;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (!_cairo_status_is_error (status) &&
scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
{
use_mask = TRUE;
break;
}
}
}
@ -682,9 +493,7 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst,
* mask IN clip ? 0 : dest
*/
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
source = &solid_pattern.base;
source = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
@ -772,26 +581,25 @@ EMPTY:
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache)
{
if (cache->tex == 0)
return;
glDeleteTextures (1, &cache->tex);
_cairo_rtree_fini (&cache->rtree);
}
void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
{
cache->tex = 0;
_cairo_rtree_init (&cache->rtree,
GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT,
GLYPH_CACHE_MIN_SIZE,
sizeof (cairo_gl_glyph_private_t),
NULL);
sizeof (cairo_gl_glyph_private_t));
}
void
_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache)
{
_cairo_rtree_fini (&cache->rtree);
if (cache->pattern.surface) {
_cairo_pattern_fini (&cache->pattern.base);
cache->pattern.surface = NULL;
}
}

View File

@ -2,7 +2,7 @@
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005 Red Hat, Inc
* Copyright © 2005,2010 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -32,16 +32,26 @@
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
* T. Zachary Laine <whatwasthataddress@gmail.com>
*/
#ifndef CAIRO_GL_PRIVATE_H
#define CAIRO_GL_PRIVATE_H
#include "cairoint.h"
#include "cairo-gl-gradient-private.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
#include <assert.h>
#include <GL/glew.h>
#include "cairo-gl.h"
@ -63,51 +73,75 @@
#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
#endif
/* maximal number of shaders we keep in the cache.
* Random number that is hopefully big enough to not cause many cache evictions. */
#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
/* VBO size that we allocate, smaller size means we gotta flush more often */
#define CAIRO_GL_VBO_SIZE 16384
typedef struct _cairo_gl_surface {
cairo_surface_t base;
cairo_gl_context_t *ctx;
int width, height;
GLuint tex; /* GL texture object containing our data. */
GLuint fb; /* GL framebuffer object wrapping our data. */
GLuint depth; /* GL framebuffer object holding depth */
int owns_tex;
} cairo_gl_surface_t;
typedef struct cairo_gl_glyph_cache {
cairo_rtree_t rtree;
GLuint tex;
unsigned int width, height;
cairo_surface_pattern_t pattern;
} cairo_gl_glyph_cache_t;
struct _cairo_gl_context {
cairo_reference_count_t ref_count;
cairo_status_t status;
typedef enum cairo_gl_tex {
CAIRO_GL_TEX_SOURCE = 0,
CAIRO_GL_TEX_MASK = 1,
CAIRO_GL_TEX_TEMP = 2
} cairo_gl_tex_t;
cairo_mutex_t mutex; /* needed? */
GLuint dummy_tex;
GLint fill_rectangles_shader;
GLint fill_rectangles_color_uniform;
GLint max_framebuffer_size;
GLint max_texture_size;
typedef enum cairo_gl_operand_type {
CAIRO_GL_OPERAND_NONE,
CAIRO_GL_OPERAND_CONSTANT,
CAIRO_GL_OPERAND_TEXTURE,
CAIRO_GL_OPERAND_LINEAR_GRADIENT,
CAIRO_GL_OPERAND_RADIAL_GRADIENT,
CAIRO_GL_OPERAND_SPANS,
cairo_gl_surface_t *current_target;
cairo_gl_glyph_cache_t glyph_cache[2];
CAIRO_GL_OPERAND_COUNT
} cairo_gl_operand_type_t;
void (*make_current)(void *ctx, cairo_gl_surface_t *surface);
void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
void (*destroy) (void *ctx);
};
typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t;
enum cairo_gl_composite_operand_type {
OPERAND_CONSTANT,
OPERAND_TEXTURE,
};
typedef struct cairo_gl_shader {
GLuint fragment_shader;
GLuint program;
} cairo_gl_shader_t;
typedef enum cairo_gl_shader_in {
CAIRO_GL_SHADER_IN_NORMAL,
CAIRO_GL_SHADER_IN_CA_SOURCE,
CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
CAIRO_GL_SHADER_IN_COUNT
} cairo_gl_shader_in_t;
typedef enum cairo_gl_var_type {
CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_TEXCOORDS,
CAIRO_GL_VAR_COVERAGE
} cairo_gl_var_type_t;
#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest))
#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
/* This union structure describes a potential source or mask operand to the
* compositing equation.
*/
typedef struct cairo_gl_composite_operand {
enum cairo_gl_composite_operand_type type;
typedef struct cairo_gl_operand {
cairo_gl_operand_type_t type;
union {
struct {
GLuint tex;
@ -117,30 +151,111 @@ typedef struct cairo_gl_composite_operand {
struct {
GLfloat color[4];
} constant;
} operand;
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
float segment_x;
float segment_y;
cairo_extend_t extend;
} linear;
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
float circle_1_x;
float circle_1_y;
float radius_0;
float radius_1;
cairo_extend_t extend;
} radial;
};
unsigned int vertex_offset;
} cairo_gl_operand_t;
const cairo_pattern_t *pattern;
} cairo_gl_composite_operand_t;
struct _cairo_gl_context {
cairo_device_t base;
typedef struct _cairo_gl_composite_setup {
cairo_gl_composite_operand_t src;
cairo_gl_composite_operand_t mask;
} cairo_gl_composite_setup_t;
GLuint dummy_tex;
GLuint texture_load_pbo;
GLuint vbo;
GLint max_framebuffer_size;
GLint max_texture_size;
GLint max_textures;
GLenum tex_target;
const cairo_gl_shader_impl_t *shader_impl;
GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
cairo_gl_shader_t fill_rectangles_shader;
cairo_cache_t shaders;
cairo_cache_t gradients;
cairo_gl_glyph_cache_t glyph_cache[2];
cairo_list_t fonts;
cairo_gl_surface_t *current_target;
cairo_operator_t current_operator;
cairo_gl_shader_t *pre_shader; /* for component alpha */
cairo_gl_shader_t *current_shader;
cairo_gl_operand_t operands[2];
char *vb;
unsigned int vb_offset;
unsigned int vertex_size;
cairo_region_t *clip_region;
void (*acquire) (void *ctx);
void (*release) (void *ctx);
void (*make_current) (void *ctx, cairo_gl_surface_t *surface);
void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
void (*destroy) (void *ctx);
};
typedef struct _cairo_gl_composite {
cairo_gl_surface_t *dst;
cairo_operator_t op;
cairo_region_t *clip_region;
cairo_gl_operand_t src;
cairo_gl_operand_t mask;
} cairo_gl_composite_t;
cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
cairo_private cairo_gl_context_t *
_cairo_gl_context_create_in_error (cairo_status_t status);
static cairo_always_inline GLenum
_cairo_gl_get_error (void)
{
GLenum err = glGetError();
if (unlikely (err))
while (glGetError ());
return err;
}
static inline cairo_device_t *
_cairo_gl_context_create_in_error (cairo_status_t status)
{
return (cairo_device_t *) _cairo_device_create_in_error (status);
}
cairo_private cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_surface_init (cairo_gl_context_t *ctx,
_cairo_gl_surface_init (cairo_device_t *device,
cairo_gl_surface_t *surface,
cairo_content_t content,
int width, int height);
static cairo_always_inline cairo_bool_t cairo_warn
_cairo_gl_surface_is_texture (cairo_gl_surface_t *surface)
{
return surface->tex != 0;
}
cairo_private cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
@ -148,42 +263,133 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
int width, int height,
int dst_x, int dst_y);
cairo_private cairo_int_status_t
_cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
static cairo_always_inline cairo_bool_t
_cairo_gl_device_has_glsl (cairo_device_t *device)
{
return ((cairo_gl_context_t *) device)->shader_impl != NULL;
}
cairo_private cairo_gl_context_t *
_cairo_gl_context_acquire (cairo_gl_context_t *ctx);
static cairo_always_inline cairo_bool_t
_cairo_gl_device_requires_power_of_two_textures (cairo_device_t *device)
{
return ((cairo_gl_context_t *) device)->tex_target == GL_TEXTURE_RECTANGLE_EXT;
}
static cairo_always_inline cairo_status_t cairo_warn
_cairo_gl_context_acquire (cairo_device_t *device,
cairo_gl_context_t **ctx)
{
cairo_status_t status;
status = cairo_device_acquire (device);
if (unlikely (status))
return status;
/* clear potential previous GL errors */
_cairo_gl_get_error ();
*ctx = (cairo_gl_context_t *) device;
return CAIRO_STATUS_SUCCESS;
}
static cairo_always_inline cairo_warn cairo_status_t
_cairo_gl_context_release (cairo_gl_context_t *ctx, cairo_status_t status)
{
GLenum err;
err = _cairo_gl_get_error ();
if (unlikely (err)) {
cairo_status_t new_status;
new_status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
if (status == CAIRO_STATUS_SUCCESS)
status = new_status;
}
cairo_device_release (&(ctx)->base);
return status;
}
cairo_private void
_cairo_gl_context_release (cairo_gl_context_t *ctx);
_cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface);
cairo_private void
_cairo_gl_set_destination (cairo_gl_surface_t *surface);
_cairo_gl_context_activate (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
cairo_private cairo_bool_t
_cairo_gl_operator_is_supported (cairo_operator_t op);
cairo_private void
_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
cairo_bool_t component_alpha);
cairo_private cairo_status_t
_cairo_gl_composite_init (cairo_gl_composite_t *setup,
cairo_operator_t op,
cairo_gl_surface_t *dst,
cairo_bool_t has_component_alpha,
const cairo_rectangle_int_t *rect);
cairo_private void
_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
cairo_gl_composite_setup_t *setup);
_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
cairo_private void
_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand);
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
cairo_region_t *clip_region);
cairo_private cairo_int_status_t
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
cairo_private cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
cairo_private void
_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup);
cairo_private cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
cairo_gl_context_t **ctx);
cairo_private void
_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
GLfloat x1,
GLfloat y1,
GLfloat x2,
GLfloat y2,
uint8_t alpha);
cairo_private void
_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
GLfloat x1,
GLfloat y1,
GLfloat x2,
GLfloat y2,
GLfloat glyph_x1,
GLfloat glyph_y1,
GLfloat glyph_x2,
GLfloat glyph_y2);
cairo_private void
_cairo_gl_composite_flush (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
cairo_private cairo_bool_t
_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
GLenum *internal_format, GLenum *format,
GLenum *type, cairo_bool_t *has_alpha);
cairo_private void
_cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t *scaled_font);
cairo_private void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
@ -191,6 +397,10 @@ _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_private void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
cairo_private void
_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cairo_gl_glyph_cache_t *cache);
cairo_private cairo_int_status_t
_cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_operator_t op,
@ -201,13 +411,6 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_clip_t *clip,
int *remaining_glyphs);
cairo_private void
_cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache);
cairo_private cairo_status_t
_cairo_gl_load_glsl (GLint *shader,
const char *vs_source, const char *fs_source);
static inline int
_cairo_gl_y_flip (cairo_gl_surface_t *surface, int y)
{
@ -217,6 +420,66 @@ _cairo_gl_y_flip (cairo_gl_surface_t *surface, int y)
return (surface->height - 1) - y;
}
cairo_private cairo_status_t
_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
static cairo_always_inline cairo_bool_t
_cairo_gl_context_is_flushed (cairo_gl_context_t *ctx)
{
return ctx->vb == NULL;
}
cairo_private cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_type_t source,
cairo_gl_operand_type_t mask,
cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader);
cairo_private void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
const char *name,
float value);
cairo_private void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
const char *name,
float value0, float value1);
cairo_private void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
const char *name,
float value0,
float value1,
float value2);
cairo_private void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
const char *name,
float value0, float value1,
float value2, float value3);
cairo_private void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
const char *name,
cairo_matrix_t* m);
cairo_private void
_cairo_gl_shader_bind_texture (cairo_gl_context_t *ctx,
const char *name,
GLuint tex_unit);
cairo_private void
_cairo_gl_set_shader (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader);
cairo_private void
_cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader);
slim_hidden_proto (cairo_gl_surface_create);
slim_hidden_proto (cairo_gl_surface_create_for_texture);
#endif /* CAIRO_GL_PRIVATE_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -40,19 +40,16 @@
CAIRO_BEGIN_DECLS
typedef struct _cairo_gl_context cairo_gl_context_t;
cairo_public cairo_gl_context_t *
cairo_gl_context_reference (cairo_gl_context_t *context);
cairo_public void
cairo_gl_context_destroy (cairo_gl_context_t *context);
cairo_public cairo_surface_t *
cairo_gl_surface_create (cairo_gl_context_t *ctx,
cairo_gl_surface_create (cairo_device_t *device,
cairo_content_t content,
int width, int height);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
cairo_content_t content,
unsigned int tex,
int width, int height);
cairo_public void
cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
@ -65,31 +62,52 @@ cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
cairo_public void
cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_gl_surface_glfinish (cairo_surface_t *surface);
#if CAIRO_HAS_GLX_FUNCTIONS
#include <GL/glx.h>
cairo_public cairo_gl_context_t *
cairo_glx_context_create (Display *dpy, GLXContext gl_ctx);
cairo_public cairo_device_t *
cairo_glx_device_create (Display *dpy, GLXContext gl_ctx);
cairo_public Display *
cairo_glx_device_get_display (cairo_device_t *device);
cairo_public GLXContext
cairo_glx_device_get_context (cairo_device_t *device);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
cairo_gl_surface_create_for_window (cairo_device_t *device,
Window win,
int width, int height);
#endif
#if CAIRO_HAS_EAGLE_FUNCTIONS
#include <eagle.h>
#if CAIRO_HAS_WGL_FUNCTIONS
#include <windows.h>
cairo_public cairo_gl_context_t *
cairo_eagle_context_create (EGLDisplay display, EGLContext context);
cairo_public cairo_device_t *
cairo_wgl_device_create (HGLRC rc);
cairo_public HGLRC
cairo_wgl_device_get_context (cairo_device_t *device);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
EGLSurface surface,
int width, int height);
cairo_gl_surface_create_for_dc (cairo_device_t *device,
HDC dc,
int width,
int height);
#endif
#if CAIRO_HAS_EGL_FUNCTIONS
#include <EGL/egl.h>
cairo_public cairo_device_t *
cairo_egl_device_create (EGLDisplay dpy, EGLContext egl);
cairo_public cairo_surface_t *
cairo_gl_surface_create_for_egl (cairo_device_t *device,
EGLSurface egl,
int width,
int height);
#endif
CAIRO_END_DECLS

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -40,6 +40,8 @@
#include "cairo-gl-private.h"
#include "cairo-error-private.h"
#include <X11/Xutil.h>
/* XXX needs hooking into XCloseDisplay() */
@ -59,8 +61,24 @@ typedef struct _cairo_glx_surface {
} cairo_glx_surface_t;
static void
_glx_make_current (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
_glx_acquire (void *abstract_ctx)
{
cairo_glx_context_t *ctx = abstract_ctx;
GLXDrawable current_drawable;
if (ctx->base.current_target == NULL ||
_cairo_gl_surface_is_texture (ctx->base.current_target)) {
current_drawable = ctx->dummy_window;
} else {
cairo_glx_surface_t *surface = (cairo_glx_surface_t *) ctx->base.current_target;
current_drawable = surface->win;
}
glXMakeCurrent (ctx->display, current_drawable, ctx->context);
}
static void
_glx_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface)
{
cairo_glx_context_t *ctx = abstract_ctx;
cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
@ -69,6 +87,14 @@ _glx_make_current (void *abstract_ctx,
glXMakeCurrent (ctx->display, surface->win, ctx->context);
}
static void
_glx_release (void *abstract_ctx)
{
cairo_glx_context_t *ctx = abstract_ctx;
glXMakeCurrent (ctx->display, None, None);
}
static void
_glx_swap_buffers (void *abstract_ctx,
cairo_gl_surface_t *abstract_surface)
@ -86,6 +112,8 @@ _glx_destroy (void *abstract_ctx)
if (ctx->dummy_window != None)
XDestroyWindow (ctx->display, ctx->dummy_window);
glXMakeCurrent (ctx->display, 0, 0);
}
static cairo_status_t
@ -140,8 +168,8 @@ _glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy)
return CAIRO_STATUS_SUCCESS;
}
cairo_gl_context_t *
cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
cairo_device_t *
cairo_glx_device_create (Display *dpy, GLXContext gl_ctx)
{
cairo_glx_context_t *ctx;
cairo_status_t status;
@ -159,6 +187,8 @@ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
ctx->dummy_window = dummy;
ctx->context = gl_ctx;
ctx->base.acquire = _glx_acquire;
ctx->base.release = _glx_release;
ctx->base.make_current = _glx_make_current;
ctx->base.swap_buffers = _glx_swap_buffers;
ctx->base.destroy = _glx_destroy;
@ -169,25 +199,60 @@ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
return _cairo_gl_context_create_in_error (status);
}
return &ctx->base;
ctx->base.release (ctx);
return &ctx->base.base;
}
Display *
cairo_glx_device_get_display (cairo_device_t *device)
{
cairo_glx_context_t *ctx;
if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
return NULL;
}
ctx = (cairo_glx_context_t *) device;
return ctx->display;
}
GLXContext
cairo_glx_device_get_context (cairo_device_t *device)
{
cairo_glx_context_t *ctx;
if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
return NULL;
}
ctx = (cairo_glx_context_t *) device;
return ctx->context;
}
cairo_surface_t *
cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
Window win,
int width,
int height)
cairo_gl_surface_create_for_window (cairo_device_t *device,
Window win,
int width,
int height)
{
cairo_glx_surface_t *surface;
if (unlikely (ctx->status))
return _cairo_surface_create_in_error (ctx->status);
if (unlikely (device->status))
return _cairo_surface_create_in_error (device->status);
if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
surface = calloc (1, sizeof (cairo_glx_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_gl_surface_init (ctx, &surface->base,
_cairo_gl_surface_init (device, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA, width, height);
surface->win = win;

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -60,13 +60,326 @@ struct _cairo_gstate {
cairo_surface_t *parent_target; /* The previous target which was receiving rendering */
cairo_surface_t *original_target; /* The original target the initial gstate was created with */
/* the user is allowed to update the device after we have cached the matrices... */
cairo_observer_t device_transform_observer;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */
cairo_bool_t is_identity;
cairo_pattern_t *source;
struct _cairo_gstate *next;
};
/* cairo-gstate.c */
cairo_private cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target);
cairo_private void
_cairo_gstate_fini (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
cairo_private cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
cairo_private cairo_bool_t
_cairo_gstate_is_redirected (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child);
cairo_private cairo_surface_t *
_cairo_gstate_get_target (cairo_gstate_t *gstate);
cairo_private cairo_surface_t *
_cairo_gstate_get_parent_target (cairo_gstate_t *gstate);
cairo_private cairo_surface_t *
_cairo_gstate_get_original_target (cairo_gstate_t *gstate);
cairo_private cairo_clip_t *
_cairo_gstate_get_clip (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source);
cairo_private cairo_pattern_t *
_cairo_gstate_get_source (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op);
cairo_private cairo_operator_t
_cairo_gstate_get_operator (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
cairo_private double
_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
cairo_private cairo_fill_rule_t
_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
cairo_private double
_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
cairo_private cairo_line_cap_t
_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
cairo_private cairo_line_join_t
_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset);
cairo_private void
_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset);
cairo_private cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
cairo_private double
_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
cairo_private void
_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
cairo_private cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
cairo_private cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
cairo_private cairo_status_t
_cairo_gstate_transform (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix);
cairo_private void
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
cairo_private void
_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y);
cairo_private void
_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy);
cairo_private void
_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y);
cairo_private void
_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy);
cairo_private void
_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y);
static inline void
_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
if (! gstate->is_identity)
_do_cairo_gstate_user_to_backend (gstate, x, y);
}
cairo_private void
_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
static inline void
_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
if (! gstate->is_identity)
_do_cairo_gstate_backend_to_user (gstate, x, y);
}
cairo_private void
_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight);
cairo_private void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask);
cairo_private cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret);
cairo_private cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y);
cairo_private cairo_bool_t
_cairo_gstate_in_clip (cairo_gstate_t *gstate,
double x,
double y);
cairo_private cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
cairo_private cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
double *x2,
double *y2);
cairo_private cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
cairo_surface_t *surface,
double x,
double y,
double width,
double height);
cairo_private cairo_status_t
_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
cairo_private cairo_status_t
_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
double size);
cairo_private void
_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix);
cairo_private void
_cairo_gstate_get_font_options (cairo_gstate_t *gstate,
cairo_font_options_t *options);
cairo_private void
_cairo_gstate_set_font_options (cairo_gstate_t *gstate,
const cairo_font_options_t *options);
cairo_private cairo_status_t
_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
cairo_font_face_t **font_face);
cairo_private cairo_status_t
_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
cairo_scaled_font_t **scaled_font);
cairo_private cairo_status_t
_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents);
cairo_private cairo_status_t
_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face);
cairo_private cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
double x,
double y,
const char *utf8,
int utf8_len,
cairo_glyph_t **glyphs,
int *num_glyphs,
cairo_text_cluster_t **clusters,
int *num_clusters,
cairo_text_cluster_flags_t *cluster_flags);
cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
cairo_private cairo_status_t
_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags);
cairo_private cairo_status_t
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
cairo_antialias_t antialias);
cairo_private cairo_antialias_t
_cairo_gstate_get_antialias (cairo_gstate_t *gstate);
#endif /* CAIRO_GSTATE_PRIVATE_H */

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,11 +35,10 @@
* Carl D. Worth <cworth@cworth.org>
*/
#define _GNU_SOURCE
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-gstate-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
@ -71,6 +70,18 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
int *num_transformed_glyphs,
cairo_text_cluster_t *transformed_clusters);
static void
_cairo_gstate_update_device_transform (cairo_observer_t *observer,
void *arg)
{
cairo_gstate_t *gstate = cairo_container_of (observer,
cairo_gstate_t,
device_transform_observer);
gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) &&
_cairo_matrix_is_identity (&gstate->target->device_transform));
}
cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target)
@ -106,6 +117,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
gstate->parent_target = NULL;
gstate->original_target = cairo_surface_reference (target);
gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
cairo_list_add (&gstate->device_transform_observer.link,
&gstate->target->device_transform_observers);
gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
cairo_matrix_init_identity (&gstate->ctm);
gstate->ctm_inverse = gstate->ctm;
gstate->source_ctm_inverse = gstate->ctm;
@ -115,10 +131,6 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
/* Now that the gstate is fully initialized and ready for the eventual
* _cairo_gstate_fini(), we can check for errors (and not worry about
* the resource deallocation). */
if (target == NULL)
return _cairo_error (CAIRO_STATUS_NULL_POINTER);
status = target->status;
if (unlikely (status))
return status;
@ -171,6 +183,11 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
gstate->parent_target = NULL;
gstate->original_target = cairo_surface_reference (other->original_target);
gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
cairo_list_add (&gstate->device_transform_observer.link,
&gstate->target->device_transform_observers);
gstate->is_identity = other->is_identity;
gstate->ctm = other->ctm;
gstate->ctm_inverse = other->ctm_inverse;
gstate->source_ctm_inverse = other->source_ctm_inverse;
@ -198,6 +215,8 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
_cairo_clip_reset (&gstate->clip);
cairo_list_del (&gstate->device_transform_observer.link);
cairo_surface_destroy (gstate->target);
gstate->target = NULL;
@ -307,6 +326,9 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
/* Now set up our new target; we overwrite gstate->target directly,
* since its ref is now owned by gstate->parent_target */
gstate->target = cairo_surface_reference (child);
gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
cairo_list_move (&gstate->device_transform_observer.link,
&gstate->target->device_transform_observers);
/* The clip is in surface backend coordinates for the previous target;
* translate it into the child's backend coordinates. */
@ -413,8 +435,7 @@ _cairo_gstate_get_source (cairo_gstate_t *gstate)
{
if (gstate->source == &_cairo_pattern_black.base) {
/* do not expose the static object to the user */
gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK,
CAIRO_CONTENT_COLOR);
gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
}
return gstate->source;
@ -533,6 +554,7 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash
for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
if (gstate->stroke_style.dash[i] < 0)
return _cairo_error (CAIRO_STATUS_INVALID_DASH);
dash_total += gstate->stroke_style.dash[i];
}
@ -563,10 +585,11 @@ _cairo_gstate_get_dash (cairo_gstate_t *gstate,
int *num_dashes,
double *offset)
{
if (dashes)
if (dashes) {
memcpy (dashes,
gstate->stroke_style.dash,
sizeof (double) * gstate->stroke_style.num_dashes);
}
if (num_dashes)
*num_dashes = gstate->stroke_style.num_dashes;
@ -607,6 +630,7 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
cairo_matrix_init_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
gstate->is_identity = FALSE;
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
@ -632,6 +656,7 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
cairo_matrix_init_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
gstate->is_identity = FALSE;
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
@ -658,6 +683,7 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
cairo_matrix_init_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
gstate->is_identity = FALSE;
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
@ -676,6 +702,9 @@ _cairo_gstate_transform (cairo_gstate_t *gstate,
cairo_matrix_t tmp;
cairo_status_t status;
if (! _cairo_matrix_is_invertible (matrix))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (_cairo_matrix_is_identity (matrix))
return CAIRO_STATUS_SUCCESS;
@ -688,6 +717,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
gstate->is_identity = FALSE;
/* paranoid check against gradual numerical instability */
if (! _cairo_matrix_is_invertible (&gstate->ctm))
@ -708,12 +738,18 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
if (! _cairo_matrix_is_invertible (matrix))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (_cairo_matrix_is_identity (matrix)) {
_cairo_gstate_identity_matrix (gstate);
return CAIRO_STATUS_SUCCESS;
}
_cairo_gstate_unset_scaled_font (gstate);
gstate->ctm = *matrix;
gstate->ctm_inverse = *matrix;
status = cairo_matrix_invert (&gstate->ctm_inverse);
assert (status == CAIRO_STATUS_SUCCESS);
gstate->is_identity = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@ -728,6 +764,7 @@ _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
cairo_matrix_init_identity (&gstate->ctm);
cairo_matrix_init_identity (&gstate->ctm_inverse);
gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
}
void
@ -757,14 +794,14 @@ _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
}
void
_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm, x, y);
cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
}
void
_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
@ -802,14 +839,25 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_box_t box;
double px1, py1, px2, py2;
_cairo_path_fixed_bounds (path,
&px1, &py1, &px2, &py2);
if (_cairo_path_fixed_extents (path, &box)) {
px1 = _cairo_fixed_to_double (box.p1.x);
py1 = _cairo_fixed_to_double (box.p1.y);
px2 = _cairo_fixed_to_double (box.p2.x);
py2 = _cairo_fixed_to_double (box.p2.y);
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
} else {
px1 = 0.0;
py1 = 0.0;
px2 = 0.0;
py2 = 0.0;
}
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
if (x1)
*x1 = px1;
if (y1)
@ -820,70 +868,32 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
*y2 = py2;
}
static void
_init_solid_for_color_stop (cairo_solid_pattern_t *solid,
const cairo_color_t *color)
{
cairo_color_t premult;
/* Color stops aren't premultiplied, so fix that here */
_cairo_color_init_rgba (&premult,
color->red,
color->green,
color->blue,
color->alpha);
_cairo_pattern_init_solid (solid, &premult, CAIRO_CONTENT_COLOR_ALPHA);
}
static void
_cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original)
{
/* First check if the we can replace the original with a much simpler
* pattern. For example, gradients that are uniform or just have a single
* stop can be replace with a solid.
* stop can sometimes be replaced with a solid.
*/
switch (original->type) {
case CAIRO_PATTERN_TYPE_SOLID:
case CAIRO_PATTERN_TYPE_SURFACE:
break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
if (_cairo_pattern_is_clear (original)) {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
CAIRO_COLOR_TRANSPARENT);
return;
}
if (original->type == CAIRO_PATTERN_TYPE_LINEAR ||
original->type == CAIRO_PATTERN_TYPE_RADIAL)
{
cairo_color_t color;
if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original,
NULL,
&color))
{
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) original;
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2) {
if (src->n_stops) {
_init_solid_for_color_stop ((cairo_solid_pattern_t *) pattern,
&src->stops->color);
} else {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_ALPHA);
}
return;
} else {
unsigned int i;
/* Is the gradient a uniform colour?
* Happens more often than you would believe.
*/
for (i = 1; i < src->n_stops; i++) {
if (! _cairo_color_equal (&src->stops[0].color,
&src->stops[i].color))
{
break;
}
}
if (i == src->n_stops) {
_init_solid_for_color_stop ((cairo_solid_pattern_t *) pattern,
&src->stops->color);
return;
}
}
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
&color);
return;
}
}
@ -913,9 +923,10 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
if (_cairo_surface_has_device_transform (gstate->target))
if (_cairo_surface_has_device_transform (gstate->target)) {
_cairo_pattern_transform (pattern,
&gstate->target->device_transform_inverse);
}
}
static void
@ -970,24 +981,73 @@ _clipped (cairo_gstate_t *gstate)
return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
}
static cairo_operator_t
_reduce_op (cairo_gstate_t *gstate)
{
cairo_operator_t op;
const cairo_pattern_t *pattern;
op = gstate->op;
if (op != CAIRO_OPERATOR_SOURCE)
return op;
pattern = gstate->source;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
if (solid->color.alpha_short <= 0x00ff) {
op = CAIRO_OPERATOR_CLEAR;
} else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
if ((solid->color.red_short |
solid->color.green_short |
solid->color.blue_short) <= 0x00ff)
{
op = CAIRO_OPERATOR_CLEAR;
}
}
} else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
if (surface->surface->is_clear &&
surface->surface->content & CAIRO_CONTENT_ALPHA)
{
op = CAIRO_OPERATOR_CLEAR;
}
} else {
const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
if (gradient->n_stops == 0)
op = CAIRO_OPERATOR_CLEAR;
}
return op;
}
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
cairo_pattern_union_t pattern;
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_clip_t clip;
cairo_status_t status;
cairo_operator_t op;
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
pattern = &source_pattern.base;
}
status = _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
op, pattern,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
@ -999,6 +1059,8 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_pattern_union_t source_pattern, mask_pattern;
const cairo_pattern_t *source;
cairo_operator_t op;
cairo_clip_t clip;
cairo_status_t status;
@ -1008,46 +1070,59 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
if (_cairo_pattern_is_opaque (mask))
if (_cairo_pattern_is_opaque (mask, NULL))
return _cairo_gstate_paint (gstate);
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
if (_cairo_pattern_is_clear (mask) &&
_cairo_operator_bounded_by_mask (gstate->op))
{
return CAIRO_STATUS_SUCCESS;
}
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
source = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
source = &source_pattern.base;
}
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
if (source_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID)
if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
_cairo_operator_bounded_by_source (op))
{
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
cairo_color_t combined;
if (mask_pattern.base.has_component_alpha) {
#define M(R, A, B, c) R.c = A.c * B.c
M(combined, source_pattern.solid.color, mask_pattern.solid.color, red);
M(combined, source_pattern.solid.color, mask_pattern.solid.color, green);
M(combined, source_pattern.solid.color, mask_pattern.solid.color, blue);
M(combined, source_pattern.solid.color, mask_pattern.solid.color, alpha);
M(combined, solid->color, mask_pattern.solid.color, red);
M(combined, solid->color, mask_pattern.solid.color, green);
M(combined, solid->color, mask_pattern.solid.color, blue);
M(combined, solid->color, mask_pattern.solid.color, alpha);
#undef M
} else {
combined = source_pattern.solid.color;
combined = solid->color;
_cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
}
_cairo_pattern_init_solid (&source_pattern.solid, &combined,
source_pattern.solid.content |
mask_pattern.solid.content);
_cairo_pattern_init_solid (&source_pattern.solid, &combined);
status = _cairo_surface_paint (gstate->target,
gstate->op,
status = _cairo_surface_paint (gstate->target, op,
&source_pattern.base,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_mask (gstate->target,
gstate->op,
&source_pattern.base,
status = _cairo_surface_mask (gstate->target, op,
source,
&mask_pattern.base,
_gstate_get_clip (gstate, &clip));
}
@ -1060,25 +1135,39 @@ cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t source_pattern;
cairo_stroke_style_t style;
double dash[2];
cairo_clip_t clip;
cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
style.dash = dash;
_cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
&style.dash_offset,
style.dash,
&style.num_dashes);
}
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
status = _cairo_surface_stroke (gstate->target,
gstate->op,
&source_pattern.base,
path,
&gstate->stroke_style,
&style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
@ -1150,13 +1239,15 @@ BAIL:
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t pattern;
cairo_clip_t clip;
cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
@ -1164,24 +1255,45 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
if (_cairo_operator_bounded_by_mask (gstate->op))
return CAIRO_STATUS_SUCCESS;
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_COLOR_ALPHA);
status = _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
&pattern.base,
&_cairo_pattern_clear.base,
_gstate_get_clip (gstate, &clip));
} else {
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_operator_t op;
cairo_rectangle_int_t extents;
cairo_box_t box;
status = _cairo_surface_fill (gstate->target,
gstate->op,
&pattern.base,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
pattern = &source_pattern.base;
}
/* Toolkits often paint the entire background with a fill */
if (_cairo_surface_get_extents (gstate->target, &extents) &&
_cairo_path_fixed_is_box (path, &box) &&
box.p1.x <= _cairo_fixed_from_int (extents.x) &&
box.p1.y <= _cairo_fixed_from_int (extents.y) &&
box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
{
status = _cairo_surface_paint (gstate->target, op, pattern,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_fill (gstate->target, op, pattern,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
}
}
_cairo_clip_fini (&clip);
@ -1793,16 +1905,21 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
cairo_text_cluster_flags_t cluster_flags)
{
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
cairo_glyph_t *transformed_glyphs;
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
cairo_text_cluster_t *transformed_clusters;
cairo_operator_t op;
cairo_status_t status;
cairo_clip_t clip;
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
@ -1845,7 +1962,13 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
if (status || num_glyphs == 0)
goto CLEANUP_GLYPHS;
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
op = _reduce_op (gstate);
if (op == CAIRO_OPERATOR_CLEAR) {
pattern = &_cairo_pattern_clear.base;
} else {
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
pattern = &source_pattern.base;
}
_cairo_clip_init(&clip);
/* For really huge font sizes, we can just do path;fill instead of
@ -1864,10 +1987,9 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
* Needless to say, do this only if show_text_glyphs is not available. */
if (cairo_surface_has_show_text_glyphs (gstate->target) ||
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <=
_cairo_surface_get_text_path_fill_threshold (gstate->target)) {
status = _cairo_surface_show_text_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
_cairo_surface_get_text_path_fill_threshold (gstate->target))
{
status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
utf8, utf8_len,
transformed_glyphs, num_glyphs,
transformed_clusters, num_clusters,
@ -1886,9 +2008,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
&path);
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
status = _cairo_surface_fill (gstate->target, op, pattern,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
@ -2044,6 +2164,7 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
if (! drop) {
memcpy (transformed_glyphs, glyphs,
num_glyphs * sizeof (cairo_glyph_t));
j = num_glyphs;
} else if (num_clusters == 0) {
for (i = 0; i < num_glyphs; i++) {
transformed_glyphs[j].index = glyphs[i].index;

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,6 +37,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
/*
* An entry can be in one of three states:

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -36,6 +36,7 @@
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-slope-private.h"
typedef struct cairo_hull {
@ -94,6 +95,13 @@ _cairo_hull_vertex_compare (const void *av, const void *bv)
cairo_hull_t *b = (cairo_hull_t *) bv;
int ret;
/* Some libraries are reported to actually compare identical
* pointers and require the result to be 0. This is the crazy world we
* have to live in.
*/
if (a == b)
return 0;
ret = _cairo_slope_compare (&a->slope, &b->slope);
/*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -53,11 +53,11 @@ _cairo_image_info_get_jpeg_info (cairo_image_info_t *info,
cairo_private cairo_int_status_t
_cairo_image_info_get_jpx_info (cairo_image_info_t *info,
const unsigned char *data,
long length);
unsigned long length);
cairo_private cairo_int_status_t
_cairo_image_info_get_png_info (cairo_image_info_t *info,
_cairo_image_info_get_png_info (cairo_image_info_t *info,
const unsigned char *data,
long length);
unsigned long length);
#endif /* CAIRO_IMAGE_INFO_PRIVATE_H */

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -214,7 +214,7 @@ _jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
cairo_int_status_t
_cairo_image_info_get_jpx_info (cairo_image_info_t *info,
const unsigned char *data,
long length)
unsigned long length)
{
const unsigned char *p = data;
const unsigned char *end = data + length;
@ -262,7 +262,7 @@ static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
cairo_int_status_t
_cairo_image_info_get_png_info (cairo_image_info_t *info,
const unsigned char *data,
long length)
unsigned long length)
{
const unsigned char *p = data;
const unsigned char *end = data + length;

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -73,19 +73,38 @@ typedef struct _cairo_list {
&pos->member != (head); \
pos = cairo_list_entry(pos->member.prev, type, member))
#define cairo_list_foreach_entry_reverse_safe(pos, n, type, head, member) \
for (pos = cairo_list_entry((head)->prev, type, member),\
n = cairo_list_entry (pos->member.prev, type, member);\
&pos->member != (head); \
pos = n, n = cairo_list_entry (n->member.prev, type, member))
#ifdef CAIRO_LIST_DEBUG
static inline void
_cairo_list_validate (const cairo_list_t *link)
{
assert (link->next->prev == link);
assert (link->prev->next == link);
}
static inline void
cairo_list_validate (const cairo_list_t *head)
{
cairo_list_t *link;
cairo_list_foreach (link, head) {
assert (link->next->prev == link);
assert (link->prev->next == link);
}
cairo_list_foreach (link, head)
_cairo_list_validate (link);
}
static inline cairo_bool_t
cairo_list_is_empty (const cairo_list_t *head);
static inline void
cairo_list_validate_is_empty (const cairo_list_t *head)
{
assert (head->next == NULL || (cairo_list_is_empty (head) && head->next == head->prev));
}
#else
#define _cairo_list_validate(link)
#define cairo_list_validate(head)
#define cairo_list_validate_is_empty(head)
#endif
static inline void
@ -110,6 +129,7 @@ static inline void
cairo_list_add (cairo_list_t *entry, cairo_list_t *head)
{
cairo_list_validate (head);
cairo_list_validate_is_empty (entry);
__cairo_list_add (entry, head, head->next);
cairo_list_validate (head);
}
@ -118,6 +138,7 @@ static inline void
cairo_list_add_tail (cairo_list_t *entry, cairo_list_t *head)
{
cairo_list_validate (head);
cairo_list_validate_is_empty (entry);
__cairo_list_add (entry, head->prev, head);
cairo_list_validate (head);
}
@ -157,10 +178,8 @@ cairo_list_move_tail (cairo_list_t *entry, cairo_list_t *head)
static inline void
cairo_list_swap (cairo_list_t *entry, cairo_list_t *other)
{
cairo_list_validate (head);
__cairo_list_add (entry, other->prev, other->next);
cairo_list_init (other);
cairo_list_validate (head);
}
static inline cairo_bool_t
@ -186,4 +205,11 @@ cairo_list_is_empty (const cairo_list_t *head)
return head->next == head;
}
static inline cairo_bool_t
cairo_list_is_singular (const cairo_list_t *head)
{
cairo_list_validate (head);
return head->next == head || head->next == head->prev;
}
#endif /* CAIRO_LIST_PRIVATE_H */

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,6 +35,7 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
typedef struct _lzw_buf {
cairo_status_t status;

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -34,9 +34,8 @@
* Carl D. Worth <cworth@cworth.org>
*/
#define _GNU_SOURCE
#include "cairoint.h"
#include "cairo-error-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
@ -44,6 +43,29 @@
#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
#endif
/**
* SECTION:cairo-matrix
* @Title: cairo_matrix_t
* @Short_Description: Generic matrix operations
* @See_Also: #cairo_t
*
* #cairo_matrix_t is used throughout cairo to convert between different
* coordinate spaces. A #cairo_matrix_t holds an affine transformation,
* such as a scale, rotation, shear, or a combination of these.
* The transformation of a point (<literal>x</literal>,<literal>y</literal>)
* is given by:
*
* <programlisting>
* x_new = xx * x + xy * y + x0;
* y_new = yx * x + yy * y + y0;
* </programlisting>
*
* The current transformation matrix of a #cairo_t, represented as a
* #cairo_matrix_t, defines the transformation from user-space
* coordinates to device-space coordinates. See cairo_get_matrix() and
* cairo_set_matrix().
*/
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
@ -579,6 +601,15 @@ _cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
return ISFINITE (det) && det != 0.;
}
cairo_bool_t
_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix)
{
return matrix->xx == 0. &&
matrix->xy == 0. &&
matrix->yx == 0. &&
matrix->yy == 0.;
}
double
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix)
{
@ -916,7 +947,7 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
* that point.
*/
if (_cairo_matrix_is_translation (matrix))
if (_cairo_matrix_has_unity_scale (matrix))
return;
/* Note: If we can't invert the transformation, skip the adjustment. */

View File

@ -15,7 +15,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -39,10 +39,31 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
/**
* SECTION:cairo-status
* @Title: Error handling
* @Short_Description: Decoding cairo's status
* @See_Also: cairo_status(), cairo_surface_status(), cairo_pattern_status(),
* cairo_font_face_status(), cairo_scaled_font_status(),
* cairo_region_status()
*
* Cairo uses a single status type to represent all kinds of errors. A status
* value of %CAIRO_STATUS_SUCCESS represents no error and has an integer value
* of zero. All other status values represent an error.
*
* Cairo's error handling is designed to be easy to use and safe. All major
* cairo objects <firstterm>retain</firstterm> an error status internally which
* can be queried anytime by the users using cairo*_status() calls. In
* the mean time, it is safe to call all cairo functions normally even if the
* underlying object is in an error status. This means that no error handling
* code is required before or after each individual cairo function call.
*/
/* Public stuff */
/**
@ -125,6 +146,10 @@ cairo_status_to_string (cairo_status_t status)
return "invalid value (typically too big) for the size of the input (surface, pattern, etc.)";
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
return "user-font method not implemented";
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return "the device type is not appropriate for the operation";
case CAIRO_STATUS_DEVICE_ERROR:
return "an operation to the device caused an unspecified error";
default:
case CAIRO_STATUS_LAST_STATUS:
return "<unknown error status>";
@ -416,7 +441,49 @@ _cairo_operator_bounded_by_source (cairo_operator_t op)
return FALSE;
}
uint32_t
_cairo_operator_bounded_by_either (cairo_operator_t op)
{
switch (op) {
default:
ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE;
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
return CAIRO_OPERATOR_BOUND_BY_MASK;
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_ATOP:
return 0;
}
}
#if DISABLE_SOME_FLOATING_POINT
/* This function is identical to the C99 function lround(), except that it
* performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and
* has a valid input range of (INT_MIN, INT_MAX] instead of
@ -627,6 +694,64 @@ _cairo_lround (double d)
#undef MSW
#undef LSW
}
#endif
/* Convert a 32-bit IEEE single precision floating point number to a
* 'half' representation (s10.5)
*/
uint16_t
_cairo_half_from_float (float f)
{
union {
uint32_t ui;
float f;
} u;
int s, e, m;
u.f = f;
s = (u.ui >> 16) & 0x00008000;
e = ((u.ui >> 23) & 0x000000ff) - (127 - 15);
m = u.ui & 0x007fffff;
if (e <= 0) {
if (e < -10) {
/* underflow */
return 0;
}
m = (m | 0x00800000) >> (1 - e);
/* round to nearest, round 0.5 up. */
if (m & 0x00001000)
m += 0x00002000;
return s | (m >> 13);
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
/* infinity */
return s | 0x7c00;
} else {
/* nan */
m >>= 13;
return s | 0x7c00 | m | (m == 0);
}
} else {
/* round to nearest, round 0.5 up. */
if (m & 0x00001000) {
m += 0x00002000;
if (m & 0x00800000) {
m = 0;
e += 1;
}
}
if (e > 30) {
/* overflow -> infinity */
return s | 0x7c00;
}
return s | (e << 10) | (m >> 13);
}
}
#ifdef _WIN32

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -168,6 +168,13 @@
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
typedef int cairo_recursive_mutex_impl_t;
# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex)
# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER 0
#elif defined(_WIN32) /******************************************************/
#define WIN32_LEAN_AND_MEAN
@ -221,6 +228,7 @@
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
typedef pthread_mutex_t cairo_recursive_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_PTHREAD 1
#if HAVE_LOCKDEP
@ -239,11 +247,31 @@
#endif
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) do { \
pthread_mutexattr_t attr; \
pthread_mutexattr_init (&attr); \
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); \
pthread_mutex_init (&(mutex), &attr); \
pthread_mutexattr_destroy (&attr); \
} while (0)
# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
#endif
/* By default mutex implementations are assumed to be recursive */
#if ! CAIRO_MUTEX_HAS_RECURSIVE_IMPL
# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
typedef cairo_mutex_impl_t cairo_recursive_mutex_impl_t;
# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) CAIRO_MUTEX_IMPL_INIT(mutex)
# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
#endif

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -38,6 +38,9 @@
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
CAIRO_MUTEX_DECLARE (_cairo_image_solid_cache_mutex)
CAIRO_MUTEX_DECLARE (_cairo_error_mutex)
CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex)
CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
@ -52,6 +55,10 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
#endif
#if CAIRO_HAS_XCB_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex)
#endif
#if CAIRO_HAS_GL_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
#endif

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -44,7 +44,7 @@
#include "cairo-compiler-private.h"
#include "cairo-mutex-impl-private.h"
/* Only the following three are mandatory at this point */
/* Only the following four are mandatory at this point */
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h."
#endif
@ -54,6 +54,9 @@
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_RECURSIVE_MUTEX_IMPL_INIT
# error "CAIRO_RECURSIVE_MUTEX_IMPL_INIT not defined. Check cairo-mutex-impl-private.h."
#endif
/* make sure implementations don't fool us: we decide these ourself */
@ -156,6 +159,7 @@
#ifndef CAIRO_MUTEX_DEBUG
typedef cairo_mutex_impl_t cairo_mutex_t;
typedef cairo_recursive_mutex_impl_t cairo_recursive_mutex_t;
#else
# define cairo_mutex_t cairo_mutex_impl_t
#endif
@ -168,6 +172,9 @@ typedef cairo_mutex_impl_t cairo_mutex_t;
#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI
#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
#define CAIRO_RECURSIVE_MUTEX_INIT CAIRO_RECURSIVE_MUTEX_IMPL_INIT
#define CAIRO_RECURSIVE_MUTEX_NIL_INITIALIZER CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER
#ifndef CAIRO_MUTEX_IS_LOCKED
# define CAIRO_MUTEX_IS_LOCKED(name) 1
#endif

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -0,0 +1,50 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2010 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
void
_cairo_observers_notify (cairo_list_t *observers, void *arg)
{
cairo_observer_t *obs, *next;
cairo_list_foreach_entry_safe (obs, next,
cairo_observer_t,
observers, link)
{
obs->callback (obs, arg);
}
}

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-os2-private.h"
#include "cairo-error-private.h"
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
@ -782,7 +783,7 @@ cairo_os2_surface_create (HPS hps_client_window,
0,
FALSE))
{
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
goto error_exit;
}
@ -791,7 +792,7 @@ cairo_os2_surface_create (HPS hps_client_window,
0,
FALSE))
{
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
goto error_exit;
}
@ -829,6 +830,7 @@ cairo_os2_surface_create (HPS hps_client_window,
/* Initialize base surface */
_cairo_surface_init (&local_os2_surface->base,
&cairo_os2_surface_backend,
NULL, /* device */
_cairo_content_from_format (CAIRO_FORMAT_ARGB32));
/* Successful exit */

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -175,7 +175,7 @@ _cairo_memory_stream_length (cairo_output_stream_t *stream);
cairo_private cairo_status_t
_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
unsigned char **data_out,
unsigned int *length_out);
unsigned long *length_out);
cairo_private cairo_output_stream_t *
_cairo_null_stream_create (void);

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,6 +37,7 @@
#include "cairoint.h"
#include "cairo-output-stream-private.h"
#include "cairo-error-private.h"
#include "cairo-compiler-private.h"
#include <stdio.h>
@ -694,7 +695,7 @@ _cairo_memory_stream_create (void)
cairo_status_t
_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
unsigned char **data_out,
unsigned int *length_out)
unsigned long *length_out)
{
memory_stream_t *stream;
cairo_status_t status;

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -57,7 +57,6 @@ typedef struct _cairo_paginated_surface {
cairo_surface_t *recording_surface;
int page_num;
cairo_bool_t page_is_blank;
} cairo_paginated_surface_t;
#endif /* CAIRO_PAGINATED_SURFACE_H */

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -48,6 +48,7 @@
#include "cairo-paginated-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-error-private.h"
static const cairo_surface_backend_t cairo_paginated_surface_backend;
@ -101,7 +102,9 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
goto FAIL;
}
_cairo_surface_init (&surface->base, &cairo_paginated_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_paginated_surface_backend,
NULL, /* device */
content);
/* Override surface->base.type with target's type so we don't leak
@ -119,7 +122,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
goto FAIL_CLEANUP_SURFACE;
surface->page_num = 1;
surface->page_is_blank = TRUE;
surface->base.is_clear = TRUE;
return &surface->base;
@ -154,9 +157,11 @@ _cairo_paginated_surface_finish (void *abstract_surface)
cairo_paginated_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (surface->page_is_blank == FALSE || surface->page_num == 1) {
cairo_surface_show_page (abstract_surface);
status = cairo_surface_status (abstract_surface);
if (! surface->base.is_clear || surface->page_num == 1) {
/* Bypass some of the sanity checking in cairo-surface.c, as we
* know that the surface is finished...
*/
status = _cairo_paginated_surface_show_page (surface);
}
/* XXX We want to propagate any errors from destroy(), but those are not
@ -164,11 +169,10 @@ _cairo_paginated_surface_finish (void *abstract_surface)
* and check the status afterwards. However, we can only call finish()
* on the target, if we own it.
*/
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) {
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1)
cairo_surface_finish (surface->target);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->target);
}
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->target);
cairo_surface_destroy (surface->target);
cairo_surface_finish (surface->recording_surface);
@ -272,17 +276,17 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
* filtering (if possible) to avoid introducing potential artifacts. */
pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_clip_init_rectangle (&clip, rect);
if (unlikely (status))
goto CLEANUP_IMAGE;
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
&pattern.base, &clip);
_cairo_clip_reset (&clip);
_cairo_clip_init (&clip);
status = _cairo_clip_rectangle (&clip, rect);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
&pattern.base, &clip);
}
_cairo_clip_fini (&clip);
_cairo_pattern_fini (&pattern.base);
CLEANUP_IMAGE:
cairo_surface_destroy (image);
@ -357,6 +361,7 @@ _paint_page (cairo_paginated_surface_t *surface)
CAIRO_PAGINATED_MODE_RENDER);
status = _cairo_recording_surface_replay_region (surface->recording_surface,
NULL,
surface->target,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
@ -471,16 +476,18 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
if (unlikely (status))
return status;
cairo_surface_destroy (surface->recording_surface);
if (! surface->base.finished) {
cairo_surface_destroy (surface->recording_surface);
surface->recording_surface = _create_recording_surface_for_target (surface->target,
surface->content);
status = surface->recording_surface->status;
if (unlikely (status))
return status;
surface->recording_surface = _create_recording_surface_for_target (surface->target,
surface->content);
status = surface->recording_surface->status;
if (unlikely (status))
return status;
surface->page_num++;
surface->page_is_blank = TRUE;
surface->page_num++;
surface->base.is_clear = TRUE;
}
return CAIRO_STATUS_SUCCESS;
}
@ -511,12 +518,6 @@ _cairo_paginated_surface_paint (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_paint (surface->recording_surface, op, source, clip);
}
@ -529,12 +530,6 @@ _cairo_paginated_surface_mask (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
}
@ -543,21 +538,15 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_stroke (surface->recording_surface, op, source,
path, style,
ctm, ctm_inverse,
@ -577,12 +566,6 @@ _cairo_paginated_surface_fill (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_fill (surface->recording_surface, op, source,
path, fill_rule,
tolerance, antialias,
@ -613,12 +596,6 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
utf8, utf8_len,
glyphs, num_glyphs,

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,6 +35,7 @@
*/
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
typedef struct cairo_path_bounder {
cairo_point_t current_point;
@ -134,26 +135,6 @@ _cairo_path_bounder_curve_to (void *closure,
}
}
static cairo_status_t
_cairo_path_bounder_curve_to_cp (void *closure,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_path_bounder_t *bounder = closure;
if (bounder->has_initial_point) {
_cairo_path_bounder_add_point (bounder, &bounder->current_point);
bounder->has_initial_point = FALSE;
}
_cairo_path_bounder_add_point (bounder, b);
_cairo_path_bounder_add_point (bounder, c);
_cairo_path_bounder_add_point (bounder, d);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
@ -168,21 +149,8 @@ void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to_cp,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
if (path->extents.p1.x < path->extents.p2.x) {
_cairo_box_round_to_rectangle (&path->extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
@ -199,15 +167,20 @@ _cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
if (! path->has_curve_to) {
bounder.extents = path->extents;
bounder.has_point = path->extents.p1.x < path->extents.p2.x;
} else {
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
}
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
@ -226,14 +199,19 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
if (! path->has_curve_to) {
bounder.extents = path->extents;
bounder.has_point = path->extents.p1.x < path->extents.p2.x;
} else {
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
}
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
@ -246,22 +224,44 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
/* Adjusts the fill extents (above) by the device-space pen. */
void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
if (! path->has_curve_to) {
bounder.extents = path->extents;
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
/* include trailing move-to for degenerate segments */
if (path->has_last_move_point) {
const cairo_point_t *point = &path->last_move_point;
if (point->x < bounder.extents.p1.x)
bounder.extents.p1.x = point->x;
if (point->y < bounder.extents.p1.y)
bounder.extents.p1.y = point->y;
if (point->x > bounder.extents.p2.x)
bounder.extents.p2.x = point->x;
if (point->y > bounder.extents.p2.y)
bounder.extents.p2.y = point->y;
}
bounder.has_point = bounder.extents.p1.x <= bounder.extents.p2.x;
bounder.has_initial_point = FALSE;
} else {
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
}
if (bounder.has_point) {
double dx, dy;
@ -294,12 +294,12 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
}
cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_traps_t traps;
cairo_box_t bbox;
@ -322,14 +322,18 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
return status;
}
void
_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
cairo_bool_t
_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
if (! path->has_curve_to) {
*box = path->extents;
return path->extents.p1.x <= path->extents.p2.x;
}
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
@ -340,15 +344,6 @@ _cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
if (bounder.has_point) {
*x1 = _cairo_fixed_to_double (bounder.extents.p1.x);
*y1 = _cairo_fixed_to_double (bounder.extents.p1.y);
*x2 = _cairo_fixed_to_double (bounder.extents.p2.x);
*y2 = _cairo_fixed_to_double (bounder.extents.p2.y);
} else {
*x1 = 0.0;
*y1 = 0.0;
*x2 = 0.0;
*y2 = 0.0;
}
*box = bounder.extents;
return bounder.has_point;
}

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -35,6 +35,8 @@
*/
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
@ -141,7 +143,8 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
if (traps->num_limits)
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_fill_to_polygon (path,
tolerance,
@ -217,11 +220,8 @@ _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_
CLEANUP_TRAPS:
_cairo_traps_fini (&traps);
if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */
region = cairo_region_create ();
if (likely (region->status) == CAIRO_STATUS_SUCCESS)
region->status = status;
}
if (unlikely (status))
region = _cairo_region_create_in_error (status);
return region;
}
@ -391,3 +391,75 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
static cairo_status_t
_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_polygon_t polygon;
cairo_status_t status;
_cairo_polygon_init (&polygon);
if (boxes->num_limits) {
_cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits);
boxes->num_limits = 0;
}
/* tolerance will be ignored as the path is rectilinear */
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
status =
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
fill_rule,
boxes);
}
_cairo_polygon_fini (&polygon);
return status;
}
cairo_status_t
_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
{
cairo_path_fixed_iter_t iter;
cairo_status_t status;
cairo_box_t box;
if (_cairo_path_fixed_is_box (path, &box))
return _cairo_boxes_add (boxes, &box);
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
continue;
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
status = _cairo_boxes_add (boxes, &box);
if (unlikely (status))
return status;
}
if (_cairo_path_fixed_iter_at_end (&iter))
return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
/* path is not rectangular, try extracting clipped rectilinear edges */
_cairo_boxes_clear (boxes);
return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
fill_rule,
boxes);
}

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -61,9 +61,10 @@ typedef char cairo_path_op_t;
typedef struct _cairo_path_buf {
cairo_list_t link;
unsigned int buf_size;
unsigned int num_ops;
unsigned int size_ops;
unsigned int num_points;
unsigned int size_points;
cairo_path_op_t *op;
cairo_point_t *points;
@ -80,15 +81,17 @@ struct _cairo_path_fixed {
cairo_point_t last_move_point;
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_last_move_point : 1;
unsigned int has_curve_to : 1;
unsigned int is_rectilinear : 1;
unsigned int maybe_fill_region : 1;
unsigned int is_empty_fill : 1;
cairo_box_t extents;
cairo_path_buf_fixed_t buf;
};
cairo_private void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,

View File

@ -14,7 +14,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -38,6 +38,7 @@
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
@ -52,7 +53,7 @@ _cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf);
static cairo_path_buf_t *
_cairo_path_buf_create (int buf_size);
_cairo_path_buf_create (int size_ops, int size_points);
static void
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
@ -88,18 +89,23 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->buf.base.num_ops = 0;
path->buf.base.num_points = 0;
path->buf.base.buf_size = CAIRO_PATH_BUF_SIZE;
path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
path->buf.base.op = path->buf.op;
path->buf.base.points = path->buf.points;
path->current_point.x = 0;
path->current_point.y = 0;
path->last_move_point = path->current_point;
path->has_last_move_point = FALSE;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->is_rectilinear = TRUE;
path->maybe_fill_region = TRUE;
path->is_empty_fill = TRUE;
path->extents.p1.x = path->extents.p1.y = INT_MAX;
path->extents.p2.x = path->extents.p2.y = INT_MIN;
}
cairo_status_t
@ -107,7 +113,7 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other)
{
cairo_path_buf_t *buf, *other_buf;
unsigned int num_points, num_ops, buf_size;
unsigned int num_points, num_ops;
VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
@ -115,18 +121,22 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
path->buf.base.op = path->buf.op;
path->buf.base.points = path->buf.points;
path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op);
path->buf.base.size_points = ARRAY_LENGTH (path->buf.points);
path->current_point = other->current_point;
path->last_move_point = other->last_move_point;
path->has_last_move_point = other->has_last_move_point;
path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
path->is_rectilinear = other->is_rectilinear;
path->maybe_fill_region = other->maybe_fill_region;
path->is_empty_fill = other->is_empty_fill;
path->extents = other->extents;
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
path->buf.base.buf_size = other->buf.base.buf_size;
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,
@ -141,9 +151,8 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
num_points += other_buf->num_points;
}
buf_size = MAX (num_ops, (num_points + 1) / 2);
if (buf_size) {
buf = _cairo_path_buf_create (buf_size);
if (num_ops) {
buf = _cairo_path_buf_create (num_ops, num_points);
if (unlikely (buf == NULL)) {
_cairo_path_fixed_fini (path);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -175,6 +184,8 @@ _cairo_path_fixed_hash (const cairo_path_fixed_t *path)
const cairo_path_buf_t *buf;
int num_points, num_ops;
hash = _cairo_hash_bytes (hash, &path->extents, sizeof (path->extents));
num_ops = num_points = 0;
cairo_path_foreach_buf_start (buf, path) {
hash = _cairo_hash_bytes (hash, buf->op,
@ -230,21 +241,25 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
return FALSE;
}
num_ops_a = num_points_a = 0;
if (a != NULL) {
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);
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;
}
num_ops_a = num_points_a = 0;
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);
num_ops_b = num_points_b = 0;
if (b != NULL) {
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);
}
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);
if (num_ops_a == 0 && num_ops_b == 0)
return TRUE;
@ -252,8 +267,6 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
if (num_ops_a != num_ops_b || num_points_a != num_points_b)
return FALSE;
assert (a != NULL && b != NULL);
buf_a = cairo_path_head (a);
num_points_a = buf_a->num_points;
num_ops_a = buf_a->num_ops;
@ -364,6 +377,21 @@ _cairo_path_last_op (cairo_path_fixed_t *path)
return buf->op[buf->num_ops - 1];
}
static inline void
_cairo_path_fixed_extents_add (cairo_path_fixed_t *path,
const cairo_point_t *point)
{
if (point->x < path->extents.p1.x)
path->extents.p1.x = point->x;
if (point->y < path->extents.p1.y)
path->extents.p1.y = point->y;
if (point->x > path->extents.p2.x)
path->extents.p2.x = point->x;
if (point->y > path->extents.p2.y)
path->extents.p2.y = point->y;
}
cairo_status_t
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
@ -402,6 +430,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
path->current_point = point;
path->last_move_point = point;
path->has_last_move_point = TRUE;
path->has_current_point = TRUE;
return CAIRO_STATUS_SUCCESS;
@ -510,6 +539,11 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
}
path->current_point = point;
if (path->has_last_move_point) {
_cairo_path_fixed_extents_add (path, &path->last_move_point);
path->has_last_move_point = FALSE;
}
_cairo_path_fixed_extents_add (path, &point);
return CAIRO_STATUS_SUCCESS;
}
@ -556,6 +590,15 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
path->is_rectilinear = FALSE;
path->maybe_fill_region = FALSE;
/* coarse bounds */
if (path->has_last_move_point) {
_cairo_path_fixed_extents_add (path, &path->last_move_point);
path->has_last_move_point = FALSE;
}
_cairo_path_fixed_extents_add (path, &point[0]);
_cairo_path_fixed_extents_add (path, &point[1]);
_cairo_path_fixed_extents_add (path, &point[2]);
return CAIRO_STATUS_SUCCESS;
}
@ -640,10 +683,10 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path,
{
cairo_path_buf_t *buf = cairo_path_tail (path);
if (buf->num_ops + 1 > buf->buf_size ||
buf->num_points + num_points > 2 * buf->buf_size)
if (buf->num_ops + 1 > buf->size_ops ||
buf->num_points + num_points > buf->size_points)
{
buf = _cairo_path_buf_create (buf->buf_size * 2);
buf = _cairo_path_buf_create (buf->num_ops * 2, buf->num_points * 2);
if (unlikely (buf == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -689,25 +732,23 @@ _cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_list_add_tail (&buf->link, &cairo_path_head (path)->link);
}
COMPILE_TIME_ASSERT (sizeof (cairo_path_op_t) == 1);
static cairo_path_buf_t *
_cairo_path_buf_create (int buf_size)
_cairo_path_buf_create (int size_ops, int size_points)
{
cairo_path_buf_t *buf;
/* adjust buf_size to ensure that buf->points is naturally aligned */
buf_size += sizeof (double)
- ((buf_size + sizeof (cairo_path_buf_t)) & (sizeof (double)-1));
buf = _cairo_malloc_ab_plus_c (buf_size,
sizeof (cairo_path_op_t) +
2 * sizeof (cairo_point_t),
sizeof (cairo_path_buf_t));
/* 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));
if (buf) {
buf->num_ops = 0;
buf->num_points = 0;
buf->buf_size = buf_size;
buf->size_ops = size_ops;
buf->size_points = size_points;
buf->op = (cairo_path_op_t *) (buf + 1);
buf->points = (cairo_point_t *) (buf->op + buf_size);
buf->points = (cairo_point_t *) (buf->op + size_ops);
}
return buf;
@ -906,6 +947,12 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
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;
}
void
@ -926,9 +973,9 @@ _cairo_path_fixed_translate (cairo_path_fixed_t *path,
}
path->last_move_point.x += offx;
path->last_move_point.y += offx;
path->last_move_point.y += offy;
path->current_point.x += offx;
path->current_point.y += offx;
path->current_point.y += offy;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
@ -936,6 +983,11 @@ _cairo_path_fixed_translate (cairo_path_fixed_t *path,
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
path->extents.p1.x += offx;
path->extents.p1.y += offy;
path->extents.p2.x += offx;
path->extents.p2.y += offy;
}
/**
@ -959,14 +1011,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0),
_cairo_fixed_from_double (matrix->xx),
_cairo_fixed_from_double (matrix->yy));
if (matrix->xx == 1. && matrix->yy == 1.) {
_cairo_path_fixed_translate (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0));
} else {
_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));
}
return;
}
path->extents.p1.x = path->extents.p1.y = INT_MAX;
path->extents.p2.x = path->extents.p2.y = INT_MIN;
path->maybe_fill_region = FALSE;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
@ -977,6 +1037,9 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
buf->points[i].x = _cairo_fixed_from_double (dx);
buf->points[i].y = _cairo_fixed_from_double (dy);
/* XXX need to eliminate surplus move-to's? */
_cairo_path_fixed_extents_add (path, &buf->points[i]);
}
} cairo_path_foreach_buf_end (buf, path);
}

View File

@ -12,7 +12,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -39,6 +39,8 @@
#define _BSD_SOURCE /* for hypot() */
#include "cairoint.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
@ -51,12 +53,11 @@ typedef struct _cairo_stroker_dash {
double dash_offset;
const double *dashes;
double approximate_dashes[2];
unsigned int num_dashes;
} cairo_stroker_dash_t;
typedef struct cairo_stroker {
cairo_stroke_style_t *style;
cairo_stroke_style_t style;
const cairo_matrix_t *ctm;
const cairo_matrix_t *ctm_inverse;
@ -138,39 +139,29 @@ _cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step)
static void
_cairo_stroker_dash_init (cairo_stroker_dash_t *dash,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
double tolerance)
const cairo_stroke_style_t *style)
{
dash->dashed = style->dash != NULL;
if (! dash->dashed)
return;
if (_cairo_stroke_style_dash_can_approximate (style, ctm, tolerance)) {
_cairo_stroke_style_dash_approximate (style, ctm, tolerance,
&dash->dash_offset,
dash->approximate_dashes,
&dash->num_dashes);
dash->dashes = dash->approximate_dashes;
} else {
dash->dashes = style->dash;
dash->num_dashes = style->num_dashes;
dash->dash_offset = style->dash_offset;
}
dash->dashes = style->dash;
dash->num_dashes = style->num_dashes;
dash->dash_offset = style->dash_offset;
_cairo_stroker_dash_start (dash);
}
static cairo_status_t
_cairo_stroker_init (cairo_stroker_t *stroker,
cairo_stroke_style_t *stroke_style,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance)
{
cairo_status_t status;
stroker->style = stroke_style;
stroker->style = *stroke_style;
stroker->ctm = ctm;
stroker->ctm_inverse = ctm_inverse;
stroker->tolerance = tolerance;
@ -190,7 +181,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
stroker->has_first_face = FALSE;
stroker->has_initial_sub_path = FALSE;
_cairo_stroker_dash_init (&stroker->dash, stroke_style, ctm, tolerance);
_cairo_stroker_dash_init (&stroker->dash, stroke_style);
stroker->add_external_edge = NULL;
@ -213,7 +204,7 @@ _cairo_stroker_limit (cairo_stroker_t *stroker,
* of the bounds but which might generate rendering that's within bounds.
*/
_cairo_stroke_style_max_distance_from_path (stroker->style, stroker->ctm,
_cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm,
&dx, &dy);
fdx = _cairo_fixed_from_double (dx);
@ -456,7 +447,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker,
outpt = &out->cw;
}
switch (stroker->style->line_join) {
switch (stroker->style.line_join) {
case CAIRO_LINE_JOIN_ROUND:
/* construct a fan around the common midpoint */
return _tessellate_fan (stroker,
@ -470,7 +461,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker,
/* dot product of incoming slope vector with outgoing slope vector */
double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
-in->usr_vector.y * out->usr_vector.y;
double ml = stroker->style->miter_limit;
double ml = stroker->style.miter_limit;
/* Check the miter limit -- lines meeting at an acute angle
* can generate long miters, the limit converts them to bevel
@ -665,7 +656,7 @@ static cairo_status_t
_cairo_stroker_add_cap (cairo_stroker_t *stroker,
const cairo_stroke_face_t *f)
{
switch (stroker->style->line_cap) {
switch (stroker->style.line_cap) {
case CAIRO_LINE_CAP_ROUND: {
cairo_slope_t slope;
@ -687,8 +678,8 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker,
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= stroker->style->line_width / 2.0;
dy *= stroker->style->line_width / 2.0;
dx *= stroker->style.line_width / 2.0;
dy *= stroker->style.line_width / 2.0;
cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
fvector.dx = _cairo_fixed_from_double (dx);
fvector.dy = _cairo_fixed_from_double (dy);
@ -826,13 +817,13 @@ _compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
*/
if (stroker->ctm_det_positive)
{
face_dx = - slope_dy * (stroker->style->line_width / 2.0);
face_dy = slope_dx * (stroker->style->line_width / 2.0);
face_dx = - slope_dy * (stroker->style.line_width / 2.0);
face_dy = slope_dx * (stroker->style.line_width / 2.0);
}
else
{
face_dx = slope_dy * (stroker->style->line_width / 2.0);
face_dy = - slope_dx * (stroker->style->line_width / 2.0);
face_dx = slope_dy * (stroker->style.line_width / 2.0);
face_dy = - slope_dx * (stroker->style.line_width / 2.0);
}
/* back to device space */
@ -866,7 +857,7 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker)
if (stroker->has_initial_sub_path
&& ! stroker->has_first_face
&& ! stroker->has_current_face
&& stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND)
&& stroker->style.line_cap == CAIRO_LINE_JOIN_ROUND)
{
/* pick an arbitrary slope to use */
double dx = 1.0, dy = 0.0;
@ -1231,8 +1222,8 @@ _cairo_stroker_curve_to (void *closure,
/* Temporarily modify the stroker to use round joins to guarantee
* smooth stroked curves. */
line_join_save = stroker->style->line_join;
stroker->style->line_join = CAIRO_LINE_JOIN_ROUND;
line_join_save = stroker->style.line_join;
stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
status = _cairo_spline_decompose (&spline, stroker->tolerance);
if (unlikely (status))
@ -1258,7 +1249,7 @@ _cairo_stroker_curve_to (void *closure,
stroker->current_face = face;
}
stroker->style->line_join = line_join_save;
stroker->style.line_join = line_join_save;
return CAIRO_STATUS_SUCCESS;
}
@ -1299,9 +1290,9 @@ _cairo_stroker_close_path (void *closure)
cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_status_t (*add_triangle) (void *closure,
const cairo_point_t triangle[3]),
@ -1350,7 +1341,7 @@ BAIL:
cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@ -1394,7 +1385,7 @@ BAIL:
cairo_status_t
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@ -1418,14 +1409,15 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
}
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
if (traps->num_limits)
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_stroke_to_polygon (path,
stroke_style,
ctm,
ctm_inverse,
tolerance,
&polygon);
stroke_style,
ctm,
ctm_inverse,
tolerance,
&polygon);
if (unlikely (status))
goto BAIL;
@ -1449,11 +1441,12 @@ typedef struct _segment_t {
} segment_t;
typedef struct _cairo_rectilinear_stroker {
cairo_stroke_style_t *stroke_style;
const cairo_stroke_style_t *stroke_style;
const cairo_matrix_t *ctm;
cairo_fixed_t half_line_width;
cairo_traps_t *traps;
cairo_bool_t do_traps;
void *container;
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t open_sub_path;
@ -1484,27 +1477,60 @@ _cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
stroker->bounds.p2.y += stroker->half_line_width;
}
static void
static cairo_bool_t
_cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
cairo_stroke_style_t *stroke_style,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
cairo_bool_t do_traps,
void *container)
{
/* This special-case rectilinear stroker only supports
* miter-joined lines (not curves) and a translation-only matrix
* (though it could probably be extended to support a matrix with
* uniform, integer scaling).
*
* It also only supports horizontal and vertical line_to
* elements. But we don't catch that here, but instead return
* UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
* non-rectilinear line_to is encountered.
*/
if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
return FALSE;
/* If the miter limit turns right angles into bevels, then we
* can't use this optimization. Remember, the ratio is
* 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or 2,
* which we round for safety. */
if (stroke_style->miter_limit < M_SQRT2)
return FALSE;
if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
{
return FALSE;
}
if (! _cairo_matrix_has_unity_scale (ctm))
return FALSE;
stroker->stroke_style = stroke_style;
stroker->ctm = ctm;
stroker->half_line_width =
_cairo_fixed_from_double (stroke_style->line_width / 2.0);
stroker->traps = traps;
stroker->open_sub_path = FALSE;
stroker->segments = stroker->segments_embedded;
stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
stroker->num_segments = 0;
/* Assume 2*EPSILON tolerance */
_cairo_stroker_dash_init (&stroker->dash, stroke_style, ctm, _cairo_fixed_to_double (2 * CAIRO_FIXED_EPSILON));
_cairo_stroker_dash_init (&stroker->dash, stroke_style);
stroker->has_bounds = FALSE;
stroker->do_traps = do_traps;
stroker->container = container;
return TRUE;
}
static void
@ -1663,7 +1689,16 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
b->x += half_line_width;
}
status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b);
if (stroker->do_traps) {
status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
} else {
cairo_box_t box;
box.p1 = *a;
box.p2 = *b;
status = _cairo_boxes_add (stroker->container, &box);
}
if (unlikely (status))
return status;
}
@ -1729,8 +1764,16 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
p2.x += half_line_width;
}
status = _cairo_traps_tessellate_rectangle (stroker->traps,
&p1, &p2);
if (stroker->do_traps) {
status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2);
} else {
cairo_box_t box;
box.p1 = p1;
box.p2 = p2;
status = _cairo_boxes_add (stroker->container, &box);
}
if (unlikely (status))
return status;
}
@ -1783,7 +1826,16 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
if (a->x == b->x && a->y == b->y)
continue;
status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b);
if (stroker->do_traps) {
status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
} else {
cairo_box_t box;
box.p1 = *a;
box.p2 = *b;
status = _cairo_boxes_add (stroker->container, &box);
}
if (unlikely (status))
return status;
}
@ -1978,45 +2030,22 @@ _cairo_rectilinear_stroker_close_path (void *closure)
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
{
cairo_rectilinear_stroker_t rectilinear_stroker;
cairo_int_status_t status;
/* This special-case rectilinear stroker only supports
* miter-joined lines (not curves) and a translation-only matrix
* (though it could probably be extended to support a matrix with
* uniform, integer scaling).
*
* It also only supports horizontal and vertical line_to
* elements. But we don't catch that here, but instead return
* UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
* non-rectilinear line_to is encountered.
*/
assert (path->is_rectilinear);
if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* If the miter limit turns right angles into bevels, then we
* can't use this optimization. Remember, the ratio is
* 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or 2,
* which we round for safety. */
if (stroke_style->miter_limit < M_SQRT2)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
stroke_style, ctm,
TRUE, traps))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (! _cairo_matrix_has_unity_scale (ctm))
return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_rectilinear_stroker_init (&rectilinear_stroker,
stroke_style,
ctm,
traps);
if (traps->num_limits) {
_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
traps->limits,
@ -2052,3 +2081,63 @@ BAIL:
return status;
}
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_boxes_t *boxes)
{
cairo_rectilinear_stroker_t rectilinear_stroker;
cairo_int_status_t status;
assert (path->is_rectilinear);
if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
stroke_style, ctm,
FALSE, boxes))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (boxes->num_limits) {
_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
boxes->limits,
boxes->num_limits);
}
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_rectilinear_stroker_move_to,
rectilinear_stroker.dash.dashed ?
_cairo_rectilinear_stroker_line_to_dashed :
_cairo_rectilinear_stroker_line_to,
NULL,
_cairo_rectilinear_stroker_close_path,
&rectilinear_stroker);
if (unlikely (status))
goto BAIL;
if (rectilinear_stroker.dash.dashed)
status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
else
status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
if (unlikely (status))
goto BAIL;
/* As we incrementally tessellate, we do not eliminate self-intersections */
status = _cairo_bentley_ottmann_tessellate_boxes (boxes,
CAIRO_FILL_RULE_WINDING,
boxes);
if (unlikely (status))
goto BAIL;
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
return CAIRO_STATUS_SUCCESS;
BAIL:
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
_cairo_boxes_clear (boxes);
return status;
}

View File

@ -13,7 +13,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -37,9 +37,19 @@
#include "cairoint.h"
#include "cairo-private.h"
#include "cairo-error-private.h"
#include "cairo-path-private.h"
#include "cairo-path-fixed-private.h"
/**
* SECTION:cairo-paths
* @Title: Paths
* @Short_Description: Creating paths and manipulating path data
*
* Paths are the most basic drawing tools and are primarily used to implicitly
* generate simple masks.
*/
static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
/* Closure for path interpretation. */

View File

@ -29,6 +29,29 @@
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
/**
* SECTION:cairo-pattern
* @Title: cairo_pattern_t
* @Short_Description: Sources for drawing
* @See_Also: #cairo_t, #cairo_surface_t
*
* #cairo_pattern_t is the paint with which cairo draws.
* The primary use of patterns is as the source for all cairo drawing
* operations, although they can also be used as masks, that is, as the
* brush too.
*
* A cairo pattern is created by using one of the many constructors,
* of the form cairo_pattern_create_<emphasis>type</emphasis>()
* or implicitly through
* cairo_set_source_<emphasis>type</emphasis>() functions.
*/
#if HAS_FREED_POOL
static freed_pool_t freed_pattern_pool[4];
#endif
static const cairo_solid_pattern_t _cairo_pattern_nil = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
@ -59,7 +82,28 @@ const cairo_solid_pattern_t _cairo_pattern_black = {
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
{ 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */
CAIRO_CONTENT_COLOR, /* content */
};
const cairo_solid_pattern_t _cairo_pattern_clear = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
{ 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
};
const cairo_solid_pattern_t _cairo_pattern_white = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
{ 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
};
/**
@ -329,23 +373,6 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
#endif
}
void
_cairo_pattern_fini_snapshot (cairo_pattern_t *pattern)
{
/* XXX this is quite ugly, but currently necessary to break the circular
* references with snapshot-cow and the recording-surface.
* This operation remains safe only whilst _cairo_surface_snapshot() is
* not public...
*/
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) pattern;
cairo_surface_finish (spat->surface);
}
_cairo_pattern_fini (pattern);
}
cairo_status_t
_cairo_pattern_create_copy (cairo_pattern_t **pattern_out,
const cairo_pattern_t *other)
@ -390,15 +417,10 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern_out,
void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color,
cairo_content_t content)
const cairo_color_t *color)
{
if (content == CAIRO_CONTENT_COLOR_ALPHA && CAIRO_COLOR_IS_OPAQUE (color))
content = CAIRO_CONTENT_COLOR;
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
pattern->color = *color;
pattern->content = content;
}
void
@ -455,106 +477,13 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
pattern->r2 = _cairo_fixed_from_double (fabs (radius1));
}
/* We use a small freed pattern cache here, because we don't want to
* constantly reallocate simple colors. */
#define MAX_PATTERN_CACHE_SIZE 4
typedef struct {
void *pool[MAX_PATTERN_CACHE_SIZE];
int top;
} freed_pool_t;
static freed_pool_t freed_pattern_pool[4];
static void *
_atomic_fetch (void **slot)
{
return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
}
static cairo_bool_t
_atomic_store (void **slot, void *pattern)
{
return _cairo_atomic_ptr_cmpxchg (slot, NULL, pattern) == NULL;
}
static void *
_freed_pattern_get (freed_pool_t *pool)
{
cairo_pattern_t *pattern;
int i;
i = pool->top - 1;
if (i < 0)
i = 0;
pattern = _atomic_fetch (&pool->pool[i]);
if (likely (pattern != NULL)) {
pool->top = i;
return pattern;
}
/* either empty or contended */
for (i = ARRAY_LENGTH (pool->pool); i--;) {
pattern = _atomic_fetch (&pool->pool[i]);
if (pattern != NULL) {
pool->top = i;
return pattern;
}
}
/* empty */
pool->top = 0;
return NULL;
}
static void
_freed_pattern_put (freed_pool_t *pool,
cairo_pattern_t *pattern)
{
int i = pool->top;
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], pattern)))
{
pool->top = i + 1;
return;
}
/* either full or contended */
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], pattern)) {
pool->top = i + 1;
return;
}
}
/* full */
pool->top = ARRAY_LENGTH (pool->pool);
free (pattern);
}
static void
_freed_patterns_reset (void)
{
int i, j;
for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) {
freed_pool_t *pool = &freed_pattern_pool[i];
for (j = 0; j < ARRAY_LENGTH (pool->pool); j++) {
free (pool->pool[j]);
pool->pool[j] = NULL;
}
}
}
cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color,
cairo_content_t content)
_cairo_pattern_create_solid (const cairo_color_t *color)
{
cairo_solid_pattern_t *pattern;
pattern =
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
if (unlikely (pattern == NULL)) {
/* None cached, need to create a new pattern. */
pattern = malloc (sizeof (cairo_solid_pattern_t));
@ -564,7 +493,7 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
}
}
_cairo_pattern_init_solid (pattern, color, content);
_cairo_pattern_init_solid (pattern, color);
CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
return &pattern->base;
@ -580,7 +509,7 @@ _cairo_pattern_create_in_error (cairo_status_t status)
CAIRO_MUTEX_INITIALIZE ();
pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
if (pattern->status == CAIRO_STATUS_SUCCESS)
status = _cairo_pattern_set_error (pattern, status);
@ -620,7 +549,7 @@ cairo_pattern_create_rgb (double red, double green, double blue)
CAIRO_MUTEX_INITIALIZE ();
return _cairo_pattern_create_solid (&color, CAIRO_CONTENT_COLOR);
return _cairo_pattern_create_solid (&color);
}
slim_hidden_def (cairo_pattern_create_rgb);
@ -660,7 +589,7 @@ cairo_pattern_create_rgba (double red, double green, double blue,
CAIRO_MUTEX_INITIALIZE ();
return _cairo_pattern_create_solid (&color, CAIRO_CONTENT_COLOR_ALPHA);
return _cairo_pattern_create_solid (&color);
}
slim_hidden_def (cairo_pattern_create_rgba);
@ -693,7 +622,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
return _cairo_pattern_create_in_error (surface->status);
pattern =
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_surface_pattern_t));
if (unlikely (pattern == NULL)) {
@ -743,7 +672,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
cairo_linear_pattern_t *pattern;
pattern =
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_linear_pattern_t));
if (unlikely (pattern == NULL)) {
@ -795,7 +724,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
cairo_radial_pattern_t *pattern;
pattern =
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
_freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_radial_pattern_t));
if (unlikely (pattern == NULL)) {
@ -899,7 +828,7 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
_cairo_pattern_fini (pattern);
/* maintain a small cache of freed patterns */
_freed_pattern_put (&freed_pattern_pool[type], pattern);
_freed_pool_put (&freed_pattern_pool[type], pattern);
}
slim_hidden_def (cairo_pattern_destroy);
@ -1592,14 +1521,14 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
break;
}
pixman_image_composite (PIXMAN_OP_SRC,
pixman_image,
NULL,
image->pixman_image,
x, y,
0, 0,
0, 0,
width, height);
pixman_image_composite32 (PIXMAN_OP_SRC,
pixman_image,
NULL,
image->pixman_image,
x, y,
0, 0,
0, 0,
width, height);
pixman_image_unref (pixman_image);
@ -1628,7 +1557,6 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
#define MAX_SURFACE_CACHE_SIZE 16
static struct {
struct _cairo_pattern_solid_surface_cache{
cairo_content_t content;
cairo_color_t color;
cairo_surface_t *surface;
} cache[MAX_SURFACE_CACHE_SIZE];
@ -1641,13 +1569,13 @@ _cairo_pattern_solid_surface_matches (
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (cache->content != pattern->content)
if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
return FALSE;
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
return FALSE;
if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content))
if (! _cairo_surface_is_similar (cache->surface, dst))
return FALSE;
return TRUE;
@ -1736,8 +1664,7 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
goto UNLOCK;
}
if (unlikely (! _cairo_surface_is_similar (surface,
dst, pattern->content)))
if (unlikely (! _cairo_surface_is_similar (surface, dst)))
{
/* In the rare event of a substitute surface being returned,
* don't cache the fallback.
@ -1753,7 +1680,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
to_destroy = solid_surface_cache.cache[i].surface;
solid_surface_cache.cache[i].surface = surface;
solid_surface_cache.cache[i].color = pattern->color;
solid_surface_cache.cache[i].content = pattern->content;
DONE:
*out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
@ -1800,6 +1726,151 @@ _cairo_pattern_reset_solid_surface_cache (void)
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
}
static void
_extents_to_linear_parameter (const cairo_linear_pattern_t *linear,
const cairo_rectangle_int_t *extents,
double t[2])
{
double t0, tdx, tdy;
double p1x, p1y, pdx, pdy, invsqnorm;
p1x = _cairo_fixed_to_double (linear->p1.x);
p1y = _cairo_fixed_to_double (linear->p1.y);
pdx = _cairo_fixed_to_double (linear->p2.x) - p1x;
pdy = _cairo_fixed_to_double (linear->p2.y) - p1y;
invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
pdx *= invsqnorm;
pdy *= invsqnorm;
t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy;
tdx = extents->width * pdx;
tdy = extents->height * pdy;
t[0] = t[1] = t0;
if (tdx < 0)
t[0] += tdx;
else
t[1] += tdx;
if (tdy < 0)
t[0] += tdy;
else
t[1] += tdy;
}
static cairo_bool_t
_linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
{
return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y;
}
static cairo_bool_t
_radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial)
{
return radial->r1 == radial->r2 &&
(radial->r1 == 0 /* && radial->r2 == 0 */ ||
(radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y));
}
static cairo_bool_t
_gradient_is_clear (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents)
{
unsigned int i;
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
if (gradient->n_stops == 0 ||
(gradient->base.extend == CAIRO_EXTEND_NONE &&
gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
return TRUE;
/* Check if the extents intersect the drawn part of the pattern. */
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
/* EXTEND_NONE degenerate linear gradients are clear */
if (_linear_pattern_is_degenerate (linear))
return TRUE;
if (extents != NULL) {
double t[2];
_extents_to_linear_parameter (linear, extents, t);
if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0))
return TRUE;
}
}
} else {
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
/* degenerate radial gradients are clear */
if (_radial_pattern_is_degenerate (radial) && FALSE)
return TRUE;
/* TODO: check actual intersection */
}
for (i = 0; i < gradient->n_stops; i++)
if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color))
return FALSE;
return TRUE;
}
/**
* _cairo_gradient_pattern_is_solid
*
* Convenience function to determine whether a gradient pattern is
* a solid color within the given extents. In this case the color
* argument is initialized to the color the pattern represents.
* This functions doesn't handle completely transparent gradients,
* thus it should be called only after _cairo_pattern_is_clear has
* returned FALSE.
*
* Return value: %TRUE if the pattern is a solid color.
**/
cairo_bool_t
_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents,
cairo_color_t *color)
{
unsigned int i;
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
/* TODO: radial, degenerate linear */
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
double t[2];
/* We already know that the pattern is not clear, thus if some
* part of it is clear, the whole is not solid.
*/
if (extents == NULL)
return FALSE;
_extents_to_linear_parameter (linear, extents, t);
if (t[0] < 0.0 || t[1] > 1.0)
return FALSE;
}
}
for (i = 1; i < gradient->n_stops; i++)
if (! _cairo_color_stop_equal (&gradient->stops[0].color,
&gradient->stops[i].color))
return FALSE;
_cairo_color_init_rgba (color,
gradient->stops[0].color.red,
gradient->stops[0].color.green,
gradient->stops[0].color.blue,
gradient->stops[0].color.alpha);
return TRUE;
}
/**
* _cairo_pattern_is_opaque_solid
*
@ -1825,10 +1896,78 @@ _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
}
static cairo_bool_t
_gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
_surface_is_opaque (const cairo_surface_pattern_t *pattern,
const cairo_rectangle_int_t *r)
{
if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
return FALSE;
if (pattern->base.extend != CAIRO_EXTEND_NONE)
return TRUE;
if (r != NULL) {
cairo_rectangle_int_t extents;
if (! _cairo_surface_get_extents (pattern->surface, &extents))
return TRUE;
if (r->x >= extents.x &&
r->y >= extents.y &&
r->x + r->width <= extents.x + extents.width &&
r->y + r->height <= extents.y + extents.height)
{
return TRUE;
}
}
return FALSE;
}
static cairo_bool_t
_surface_is_clear (const cairo_surface_pattern_t *pattern)
{
cairo_rectangle_int_t extents;
if (_cairo_surface_get_extents (pattern->surface, &extents) &&
(extents.width == 0 || extents.height == 0))
return TRUE;
return pattern->surface->is_clear &&
pattern->surface->content & CAIRO_CONTENT_ALPHA;
}
static cairo_bool_t
_gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents)
{
unsigned int i;
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
if (gradient->n_stops == 0 ||
(gradient->base.extend == CAIRO_EXTEND_NONE &&
gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
return FALSE;
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
if (gradient->base.extend == CAIRO_EXTEND_NONE) {
double t[2];
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
/* EXTEND_NONE degenerate radial gradients are clear */
if (_linear_pattern_is_degenerate (linear))
return FALSE;
if (extents == NULL)
return FALSE;
_extents_to_linear_parameter (linear, extents, t);
if (t[0] < 0.0 || t[1] > 1.0)
return FALSE;
}
}
for (i = 0; i < gradient->n_stops; i++)
if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color))
return FALSE;
@ -1846,7 +1985,8 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
* Return value: %TRUE if the pattern is a opaque.
**/
cairo_bool_t
_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
const cairo_rectangle_int_t *extents)
{
const cairo_pattern_union_t *pattern;
@ -1858,10 +1998,33 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_pattern_is_opaque_solid (abstract_pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return cairo_surface_get_content (pattern->surface.surface) == CAIRO_CONTENT_COLOR;
return _surface_is_opaque (&pattern->surface, extents);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _gradient_is_opaque (&pattern->gradient.base);
return _gradient_is_opaque (&pattern->gradient.base, extents);
}
ASSERT_NOT_REACHED;
return FALSE;
}
cairo_bool_t
_cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
{
const cairo_pattern_union_t *pattern;
if (abstract_pattern->has_component_alpha)
return FALSE;
pattern = (cairo_pattern_union_t *) abstract_pattern;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color);
case CAIRO_PATTERN_TYPE_SURFACE:
return _surface_is_clear (&pattern->surface);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _gradient_is_clear (&pattern->gradient.base, NULL);
}
ASSERT_NOT_REACHED;
@ -1882,7 +2045,7 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
* the filter radius, so we just guess base on what we know that
* backends do currently (see bug #10508)
*/
static cairo_filter_t
cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
double *pad_out)
{
@ -2206,21 +2369,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
return status;
}
static void
_init_solid_for_color_stop (cairo_solid_pattern_t *solid,
const cairo_color_t *color)
{
cairo_color_t premult;
/* Color stops aren't premultiplied, so fix that here */
_cairo_color_init_rgba (&premult,
color->red,
color->green,
color->blue,
color->alpha);
_cairo_pattern_init_solid (solid, &premult, CAIRO_CONTENT_COLOR_ALPHA);
}
/**
* _cairo_pattern_acquire_surface:
* @pattern: a #cairo_pattern_t
@ -2252,98 +2400,36 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_t **surface_out,
cairo_surface_attributes_t *attributes)
{
cairo_status_t status;
if (unlikely (pattern->status)) {
*surface_out = NULL;
return pattern->status;
}
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID: {
cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
dst, x, y, width, height,
surface_out,
attributes);
status = _cairo_pattern_acquire_surface_for_solid (src, dst,
x, y, width, height,
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
dst, x, y, width, height,
surface_out,
attributes);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
dst, x, y, width, height,
flags,
surface_out,
attributes);
} break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
/* XXX The gradient->solid conversion code should now be redundant. */
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2)
{
cairo_solid_pattern_t solid;
if (src->n_stops) {
_init_solid_for_color_stop (&solid, &src->stops->color);
} else {
_cairo_pattern_init_solid (&solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_ALPHA);
}
status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,
x, y,
width, height,
surface_out,
attributes);
}
else
{
unsigned int i;
/* Is the gradient a uniform colour?
* Happens more often than you would believe.
*/
for (i = 1; i < src->n_stops; i++) {
if (! _cairo_color_equal (&src->stops[0].color,
&src->stops[i].color))
{
break;
}
}
if (i == src->n_stops) {
cairo_solid_pattern_t solid;
_init_solid_for_color_stop (&solid, &src->stops->color);
status =
_cairo_pattern_acquire_surface_for_solid (&solid, dst,
x, y,
width, height,
surface_out,
attributes);
} else {
status =
_cairo_pattern_acquire_surface_for_gradient (src, dst,
x, y,
width, height,
surface_out,
attributes);
}
}
} break;
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
status = _cairo_pattern_acquire_surface_for_surface (src, dst,
x, y,
width, height,
flags,
surface_out,
attributes);
} break;
default:
ASSERT_NOT_REACHED;
status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
}
return status;
}
/**
@ -2401,8 +2487,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
combined = src_solid->color;
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&src_tmp.solid, &combined,
src_solid->content | mask_solid->content);
_cairo_pattern_init_solid (&src_tmp.solid, &combined);
src = &src_tmp.base;
mask = NULL;
@ -2452,7 +2537,6 @@ void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
{
cairo_matrix_t imatrix;
double x1, y1, x2, y2;
cairo_status_t status;
@ -2539,6 +2623,9 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
if (pattern->extend != CAIRO_EXTEND_NONE)
goto UNBOUNDED;
if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y)
goto EMPTY;
if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
goto UNBOUNDED;
@ -2562,14 +2649,21 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
ASSERT_NOT_REACHED;
}
imatrix = pattern->matrix;
status = cairo_matrix_invert (&imatrix);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
if (_cairo_matrix_is_translation (&pattern->matrix)) {
x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0;
y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0;
} else {
cairo_matrix_t imatrix;
_cairo_matrix_transform_bounding_box (&imatrix,
&x1, &y1, &x2, &y2,
NULL);
imatrix = pattern->matrix;
status = cairo_matrix_invert (&imatrix);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
_cairo_matrix_transform_bounding_box (&imatrix,
&x1, &y1, &x2, &y2,
NULL);
}
x1 = floor (x1);
if (x1 < CAIRO_RECT_INT_MIN)
@ -2607,7 +2701,6 @@ _cairo_solid_pattern_hash (unsigned long hash,
{
const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
hash = _cairo_hash_bytes (hash, &solid->content, sizeof (solid->content));
hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
return hash;
@ -2635,23 +2728,20 @@ _cairo_gradient_color_stops_hash (unsigned long hash,
return hash;
}
static unsigned long
unsigned long
_cairo_linear_pattern_hash (unsigned long hash,
const cairo_pattern_t *pattern)
const cairo_linear_pattern_t *linear)
{
const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
return _cairo_gradient_color_stops_hash (hash, &linear->base);
}
static unsigned long
_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern)
unsigned long
_cairo_radial_pattern_hash (unsigned long hash,
const cairo_radial_pattern_t *radial)
{
const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
@ -2696,9 +2786,9 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_LINEAR:
return _cairo_linear_pattern_hash (hash, pattern);
return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_radial_pattern_hash (hash, pattern);
return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_hash (hash, pattern);
default:
@ -2750,9 +2840,6 @@ _cairo_solid_pattern_equal (const cairo_pattern_t *A,
const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
if (a->content != b->content)
return FALSE;
return _cairo_color_equal (&a->color, &b->color);
}
@ -2768,20 +2855,17 @@ _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
for (n = 0; n < a->n_stops; n++) {
if (a->stops[n].offset != b->stops[n].offset)
return FALSE;
if (! _cairo_color_equal (&a->stops[n].color, &b->stops[n].color))
if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color))
return FALSE;
}
return TRUE;
}
static cairo_bool_t
_cairo_linear_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
cairo_bool_t
_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
const cairo_linear_pattern_t *b)
{
const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A;
const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B;
if (a->p1.x != b->p1.x)
return FALSE;
@ -2797,13 +2881,10 @@ _cairo_linear_pattern_equal (const cairo_pattern_t *A,
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
static cairo_bool_t
_cairo_radial_pattern_equal (const cairo_pattern_t *A,
const cairo_pattern_t *B)
cairo_bool_t
_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
const cairo_radial_pattern_t *b)
{
const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A;
const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B;
if (a->c1.x != b->c1.x)
return FALSE;
@ -2865,9 +2946,11 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_LINEAR:
return _cairo_linear_pattern_equal (a, b);
return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
(cairo_linear_pattern_t *) b);
case CAIRO_PATTERN_TYPE_RADIAL:
return _cairo_radial_pattern_equal (a, b);
return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
(cairo_radial_pattern_t *) b);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_equal (a, b);
default:
@ -3131,6 +3214,12 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
void
_cairo_pattern_reset_static_data (void)
{
_freed_patterns_reset ();
#if HAS_FREED_POOL
int i;
for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
_freed_pool_reset (&freed_pattern_pool[i]);
#endif
_cairo_pattern_reset_solid_surface_cache ();
}

View File

@ -15,7 +15,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -82,6 +82,7 @@ typedef struct _cairo_pdf_operators {
double cur_y;
int hex_width;
int num_glyphs;
double glyph_buf_x_pos;
cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE];
/* PDF line style */
@ -132,16 +133,16 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale);
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
const cairo_stroke_style_t *style,
double scale);
cairo_private cairo_int_status_t
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse);
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
@ -149,12 +150,12 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse);
cairo_fill_rule_t fill_rule,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,

View File

@ -15,7 +15,7 @@
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
@ -43,6 +43,7 @@
#if CAIRO_HAS_PDF_OPERATORS
#include "cairo-error-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-output-stream-private.h"
@ -499,14 +500,14 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
}
switch (fill_rule) {
default:
ASSERT_NOT_REACHED;
case CAIRO_FILL_RULE_WINDING:
pdf_operator = "W";
break;
case CAIRO_FILL_RULE_EVEN_ODD:
pdf_operator = "W*";
break;
default:
ASSERT_NOT_REACHED;
}
_cairo_output_stream_printf (pdf_operators->stream,
@ -549,9 +550,9 @@ _cairo_pdf_line_join (cairo_line_join_t join)
}
cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale)
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
const cairo_stroke_style_t *style,
double scale)
{
double *dash = style->dash;
int num_dashes = style->num_dashes;
@ -706,12 +707,12 @@ _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
}
static cairo_int_status_t
_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
const char *pdf_operator)
_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
const char *pdf_operator)
{
cairo_status_t status;
cairo_matrix_t m, path_transform;
@ -797,11 +798,11 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
}
cairo_int_status_t
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse)
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse)
{
return _cairo_pdf_operators_emit_stroke (pdf_operators,
path,
@ -833,14 +834,14 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
return status;
switch (fill_rule) {
default:
ASSERT_NOT_REACHED;
case CAIRO_FILL_RULE_WINDING:
pdf_operator = "f";
break;
case CAIRO_FILL_RULE_EVEN_ODD:
pdf_operator = "f*";
break;
default:
ASSERT_NOT_REACHED;
}
_cairo_output_stream_printf (pdf_operators->stream,
@ -851,24 +852,24 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
}
cairo_int_status_t
_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse)
cairo_fill_rule_t fill_rule,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse)
{
const char *operator;
switch (fill_rule) {
default:
ASSERT_NOT_REACHED;
case CAIRO_FILL_RULE_WINDING:
operator = "B";
break;
case CAIRO_FILL_RULE_EVEN_ODD:
operator = "B*";
break;
default:
ASSERT_NOT_REACHED;
}
return _cairo_pdf_operators_emit_stroke (pdf_operators,
@ -989,6 +990,7 @@ _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
}
pdf_operators->num_glyphs = 0;
pdf_operators->glyph_buf_x_pos = pdf_operators->cur_x;
status2 = _cairo_output_stream_destroy (word_wrap_stream);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
@ -1011,6 +1013,7 @@ _cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators
pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position;
pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index;
pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x;
pdf_operators->glyph_buf_x_pos += x;
pdf_operators->num_glyphs++;
if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE)
return _cairo_pdf_operators_flush_glyphs (pdf_operators);
@ -1035,6 +1038,7 @@ _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators,
pdf_operators->text_matrix = *matrix;
pdf_operators->cur_x = 0;
pdf_operators->cur_y = 0;
pdf_operators->glyph_buf_x_pos = 0;
_cairo_output_stream_printf (pdf_operators->stream,
"%f %f %f %f %f %f Tm\n",
pdf_operators->text_matrix.xx,
@ -1090,6 +1094,7 @@ _cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators,
translate.y0);
pdf_operators->cur_x = 0;
pdf_operators->cur_y = 0;
pdf_operators->glyph_buf_x_pos = 0;
pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix;
status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
@ -1139,6 +1144,7 @@ _cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators)
pdf_operators->in_text_object = TRUE;
pdf_operators->num_glyphs = 0;
pdf_operators->glyph_buf_x_pos = 0;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
@ -1243,7 +1249,7 @@ _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operator
* PDF consumers that do not handle very large position
* adjustments in TJ.
*/
if (fabs(x - pdf_operators->cur_x) > 10 ||
if (fabs(x - pdf_operators->glyph_buf_x_pos) > 10 ||
fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
@ -1380,8 +1386,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
assert (status == CAIRO_STATUS_SUCCESS);
pdf_operators->is_new_text_object = FALSE;
if (pdf_operators->in_text_object == FALSE) {

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