Renamed everything from Xr* to cairo_*

This commit is contained in:
Carl Worth 2003-07-18 11:34:19 +00:00
parent 4a57fd0881
commit dc1e96ae35
58 changed files with 11733 additions and 7351 deletions

View file

@ -2,6 +2,7 @@ Makefile
Makefile.in
aclocal.m4
autom4te.cache
cairo.pc
config.cache
config.guess
config.h
@ -15,4 +16,4 @@ ltmain.sh
stamp-h
stamp-h1
stamp-h.in
xr.pc

5
BUGS
View file

@ -1,2 +1,3 @@
SEGV if XrSetRGBColor is called before XrSetTargetDrawable
SEGV if XrFill is called before XrSetRGBColor
SEGV if cairo_set_rgb_color is called before cairo_set_target_drawable
SEGV if cairo_fill is called before cairo_set_rgb_color

View file

@ -1,3 +1,10 @@
2003-07-18 Carl Worth <cworth@isi.edu>
* src/cairo.h: Renamed everything from Xr* to cairo_*.
* util/xr2cairo: Added utility script xr2cairo to help users fix
their source code.
2003-07-03 Carl Worth <cworth@isi.edu>
* src/xrmatrix.c (XrMatrixGetAffine): Added XrMatrixGetAffine

View file

@ -2,7 +2,7 @@ SUBDIRS = src
EXTRA_DIST = \
COPYING \
xr.pc.in
cairo.pc.in
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xr.pc
pkgconfig_DATA = cairo.pc

30
README
View file

@ -1,4 +1,4 @@
Xr - Rendering library
Cairo - Multi-platform 2D graphics library
Compiling
---------
@ -6,27 +6,27 @@ See the INSTALL document for build instructions.
Description
-----------
Xr provides anti-aliased vector-based rendering for X. Paths consist
Cairo provides anti-aliased vector-based rendering for X. Paths consist
of line segments and cubic splines and can be rendered at any width
with various join and cap styles. All colors may be specified with
optional translucence (opacity/alpha) and combined using the extended
Porter/Duff compositing algebra as found in the X Render Extension.
Xr exports a stateful rendering API similar in spirit to the path
Cairo exports a stateful rendering API similar in spirit to the path
construction, text, and painting operators of PostScript, (with the
significant addition of translucence in the imaging model). When
complete, the API is intended to support the complete imaging model of
PDF 1.4.
Xr relies on the Xc library for backend rendering. Xc provides an
Cairo relies on the Xc library for backend rendering. Xc provides an
abstract interface for rendering to multiple target types. As of this
writing, Xc allows Xr to target X drawables as well as generic image
writing, Xc allows Cairo to target X drawables as well as generic image
buffers. Future backends such as PostScript, PDF, and perhaps OpenGL
are currently being planned.
Dependencies
------------
Xr currently requires the following supporting libraries:
Cairo currently requires the following supporting libraries:
Xc
Xft
@ -36,28 +36,28 @@ Xr currently requires the following supporting libraries:
Documentation
-------------
There's not much documentation yet apart from the Xr.h header
There's not much documentation yet apart from the cairo.h header
file. We'll be correcting that shortly.
In the meantime, the xrtest module in CVS provides a few example
programs using Xr. These may be helpful to a programmer just beginning
with Xr. Also, familiarity with the PostScript imaging model will
help in understanding Xr.
programs using Cairo. These may be helpful to a programmer just beginning
with Cairo. Also, familiarity with the PostScript imaging model will
help in understanding Cairo.
History
-------
Xr was developed by Carl Worth <cworth@isi.edu> and Keith Packard
Cairo was developed by Carl Worth <cworth@isi.edu> and Keith Packard
<keithp@keithp.com>. Many thanks are due to Lyle Ramshaw without whose
patient help our ignorance would be much more apparent.
Mailing List
------------
If you have trouble with Xr or you have some ideas for how it could be
improved, please feel free to send a message to xr@xwin.org.
If you have trouble with Cairo or you have some ideas for how it could be
improved, please feel free to send a message to cairo@cairographics.org
Xr is still under active development and all discussion happens on
Cairo is still under active development and all discussion happens on
that list. So if you want to lurk or, (even better), take part in the
development, take a look. Subscription information and archives are
available:
http://xwin.org/cgi-bin/mailman/listinfo/xr
http://cairographics.org/cgi-bin/mailman/listinfo/cairo

View file

@ -3,11 +3,11 @@ exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Xr
Description: X Rendering library
Name: cairo
Description: Multi-platform 2D graphics library
Version: @VERSION@
Requires: xc xft
Libs: -L${libdir} -lXr -lm
Libs: -L${libdir} -lcairo -lm
Cflags: -I${includedir}

View file

@ -1,9 +1,9 @@
AC_INIT(src/Xr.h)
AC_INIT(src/cairo.h)
dnl ===========================================================================
# Package version number, (as distinct from shared library version)
XR_VERSION=0.1.0
CAIRO_VERSION=0.1.0
# libtool shared library version
@ -29,7 +29,7 @@ XFT_REQUIRED=2.1.1
dnl ===========================================================================
AM_INIT_AUTOMAKE(xr, $XR_VERSION)
AM_INIT_AUTOMAKE(cairo, $CAIRO_VERSION)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
@ -45,14 +45,14 @@ AC_PATH_XTRA
dnl ===========================================================================
PKG_CHECK_MODULES(XR, xc >= $XC_REQUIRED xft >= $XFT_REQUIRED)
AC_SUBST(XR_CFLAGS)
AC_SUBST(XR_LIBS)
PKG_CHECK_MODULES(CAIRO, xc >= $XC_REQUIRED xft >= $XFT_REQUIRED)
AC_SUBST(CAIRO_CFLAGS)
AC_SUBST(CAIRO_LIBS)
dnl ===========================================================================
AC_OUTPUT([
xr.pc
cairo.pc
Makefile
src/Makefile
])

View file

@ -1,28 +1,27 @@
lib_LTLIBRARIES = libXr.la
include_HEADERS = Xr.h
lib_LTLIBRARIES = libcairo.la
include_HEADERS = cairo.h
libXr_la_SOURCES = \
Xr.h \
xr.c \
xrint.h \
xrcolor.c \
xrfont.c \
xrgstate.c \
xrmatrix.c \
xrmisc.c \
xrpath.c \
xrpathbounds.c \
xrpathfill.c \
xrpathstroke.c \
xrpen.c \
xrpolygon.c \
xrspline.c \
xrstate.c \
xrsurface.c \
xrtraps.c
libcairo_la_SOURCES = \
cairo.h \
cairo.c \
cairoint.h \
cairo_color.c \
cairo_font.c \
cairo_gstate.c \
cairo_matrix.c \
cairo_misc.c \
cairo_path.c \
cairo_path_bounds.c \
cairo_path_fill.c \
cairo_path_stroke.c \
cairo_pen.c \
cairo_polygon.c \
cairo_spline.c \
cairo_surface.c \
cairo_traps.c
libXr_la_LDFLAGS = -version-info @VERSION_INFO@
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@
INCLUDES = $(XR_CFLAGS) $(X_CFLAGS)
INCLUDES = $(CAIRO_CFLAGS) $(X_CFLAGS)
libXr_la_LIBADD = $(XR_LIBS) -lm
libcairo_la_LIBADD = $(CAIRO_LIBS) -lm

476
src/Xr.h
View file

@ -1,476 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH 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 _XR_H_
#define _XR_H_
#include <Xc.h>
typedef struct _XrState XrState;
typedef struct _XrSurface XrSurface;
typedef struct _XrMatrix XrMatrix;
_XFUNCPROTOBEGIN
/* Functions for manipulating state objects */
XrState *
XrCreate(void);
void
XrDestroy(XrState *xrs);
void
XrSave(XrState *xrs);
void
XrRestore(XrState *xrs);
/* XXX: I want to rethink this API
void
XrPushGroup(XrState *xrs);
void
XrPopGroup(XrState *xrs);
*/
/* Modify state */
void
XrSetTargetSurface (XrState *xrs, XrSurface *surface);
typedef enum _XrFormat {
XrFormatARGB32 = PictStandardARGB32,
XrFormatRGB24 = PictStandardRGB24,
XrFormatA8 = PictStandardA8,
XrFormatA1 = PictStandardA1
} XrFormat;
void
XrSetTargetDrawable (XrState *xrs,
Display *dpy,
Drawable drawable);
void
XrSetTargetImage (XrState *xrs,
char *data,
XrFormat format,
int width,
int height,
int stride);
typedef enum _XrOperator {
XrOperatorClear = PictOpClear,
XrOperatorSrc = PictOpSrc,
XrOperatorDst = PictOpDst,
XrOperatorOver = PictOpOver,
XrOperatorOverReverse = PictOpOverReverse,
XrOperatorIn = PictOpIn,
XrOperatorInReverse = PictOpInReverse,
XrOperatorOut = PictOpOut,
XrOperatorOutReverse = PictOpOutReverse,
XrOperatorAtop = PictOpAtop,
XrOperatorAtopReverse = PictOpAtopReverse,
XrOperatorXor = PictOpXor,
XrOperatorAdd = PictOpAdd,
XrOperatorSaturate = PictOpSaturate,
XrOperatorDisjointClear = PictOpDisjointClear,
XrOperatorDisjointSrc = PictOpDisjointSrc,
XrOperatorDisjointDst = PictOpDisjointDst,
XrOperatorDisjointOver = PictOpDisjointOver,
XrOperatorDisjointOverReverse = PictOpDisjointOverReverse,
XrOperatorDisjointIn = PictOpDisjointIn,
XrOperatorDisjointInReverse = PictOpDisjointInReverse,
XrOperatorDisjointOut = PictOpDisjointOut,
XrOperatorDisjointOutReverse = PictOpDisjointOutReverse,
XrOperatorDisjointAtop = PictOpDisjointAtop,
XrOperatorDisjointAtopReverse = PictOpDisjointAtopReverse,
XrOperatorDisjointXor = PictOpDisjointXor,
XrOperatorConjointClear = PictOpConjointClear,
XrOperatorConjointSrc = PictOpConjointSrc,
XrOperatorConjointDst = PictOpConjointDst,
XrOperatorConjointOver = PictOpConjointOver,
XrOperatorConjointOverReverse = PictOpConjointOverReverse,
XrOperatorConjointIn = PictOpConjointIn,
XrOperatorConjointInReverse = PictOpConjointInReverse,
XrOperatorConjointOut = PictOpConjointOut,
XrOperatorConjointOutReverse = PictOpConjointOutReverse,
XrOperatorConjointAtop = PictOpConjointAtop,
XrOperatorConjointAtopReverse = PictOpConjointAtopReverse,
XrOperatorConjointXor = PictOpConjointXor
} XrOperator;
void
XrSetOperator(XrState *xrs, XrOperator op);
/* XXX: Probably want to bite the bullet and expose an XrColor object */
void
XrSetRGBColor(XrState *xrs, double red, double green, double blue);
void
XrGetRGBColor(XrState *xrs, double *red, double *green, double *blue);
/* XXX: Do we want XrGetPattern as well? */
void
XrSetPattern(XrState *xrs, XrSurface *pattern);
void
XrSetTolerance(XrState *xrs, double tolerance);
void
XrSetAlpha(XrState *xrs, double alpha);
double
XrGetAlpha(XrState *xrs);
typedef enum _XrFillRule { XrFillRuleWinding, XrFillRuleEvenOdd } XrFillRule;
void
XrSetFillRule(XrState *xrs, XrFillRule fill_rule);
void
XrSetLineWidth(XrState *xrs, double width);
typedef enum _XrLineCap { XrLineCapButt, XrLineCapRound, XrLineCapSquare } XrLineCap;
void
XrSetLineCap(XrState *xrs, XrLineCap line_cap);
typedef enum _XrLineJoin { XrLineJoinMiter, XrLineJoinRound, XrLineJoinBevel } XrLineJoin;
void
XrSetLineJoin(XrState *xrs, XrLineJoin line_join);
void
XrSetDash(XrState *xrs, double *dashes, int ndash, double offset);
void
XrSetMiterLimit(XrState *xrs, double limit);
void
XrTranslate(XrState *xrs, double tx, double ty);
void
XrScale(XrState *xrs, double sx, double sy);
void
XrRotate(XrState *xrs, double angle);
void
XrConcatMatrix(XrState *xrs,
XrMatrix *matrix);
void
XrSetMatrix(XrState *xrs,
XrMatrix *matrix);
void
XrDefaultMatrix(XrState *xrs);
/* XXX: There's been a proposal to add XrDefaultMatrixExact */
void
XrIdentityMatrix(XrState *xrs);
void
XrTransformPoint (XrState *xrs, double *x, double *y);
void
XrTransformDistance (XrState *xrs, double *dx, double *dy);
void
XrInverseTransformPoint (XrState *xrs, double *x, double *y);
void
XrInverseTransformDistance (XrState *xrs, double *dx, double *dy);
/* Path creation functions */
void
XrNewPath(XrState *xrs);
void
XrMoveTo(XrState *xrs, double x, double y);
void
XrLineTo(XrState *xrs, double x, double y);
void
XrCurveTo(XrState *xrs,
double x1, double y1,
double x2, double y2,
double x3, double y3);
void
XrRelMoveTo(XrState *xrs, double dx, double dy);
void
XrRelLineTo(XrState *xrs, double dx, double dy);
void
XrRelCurveTo(XrState *xrs,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
void
XrRectangle (XrState *xrs,
double x, double y,
double width, double height);
void
XrClosePath(XrState *xrs);
/* Painting functions */
void
XrStroke(XrState *xrs);
void
XrFill(XrState *xrs);
/* Clipping */
void
XrClip(XrState *xrs);
/* Font/Text functions */
/* XXX: The font support should probably expose an XrFont object with
several functions, (XrFontTransform, etc.) in a parallel manner as
XrMatrix and (eventually) XrColor */
void
XrSelectFont(XrState *xrs, const char *key);
void
XrScaleFont(XrState *xrs, double scale);
/* XXX: Probably want to use an XrMatrix here, (to fix as part of the
big text support rewrite) */
void
XrTransformFont(XrState *xrs,
double a, double b,
double c, double d);
void
XrTextExtents(XrState *xrs,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy);
void
XrShowText(XrState *xrs, const unsigned char *utf8);
/* Image functions */
void
XrShowSurface (XrState *xrs,
XrSurface *surface,
int width,
int height);
/* Query functions */
XrOperator
XrGetOperator(XrState *xrs);
double
XrGetTolerance(XrState *xrs);
void
XrGetCurrentPoint(XrState *, double *x, double *y);
XrFillRule
XrGetFillRule(XrState *xrs);
double
XrGetLineWidth(XrState *xrs);
XrLineCap
XrGetLineCap(XrState *xrs);
XrLineJoin
XrGetLineJoin(XrState *xrs);
double
XrGetMiterLimit(XrState *xrs);
/* XXX: How to do XrGetDash??? Do we want to switch to an XrDash object? */
void
XrGetMatrix(XrState *xrs,
double *a, double *b,
double *c, double *d,
double *tx, double *ty);
XrSurface *
XrGetTargetSurface (XrState *xrs);
/* Error status queries */
typedef enum _XrStatus {
XrStatusSuccess = 0,
XrStatusNoMemory,
XrStatusInvalidRestore,
XrStatusInvalidPopGroup,
XrStatusNoCurrentPoint,
XrStatusInvalidMatrix
} XrStatus;
XrStatus
XrGetStatus(XrState *xrs);
const char *
XrGetStatusString(XrState *xrs);
/* Surface mainpulation */
/* XXX: This is a mess from the user's POV. Should the Visual or the
XrFormat control what render format is used? Maybe I can have
XrSurfaceCreateForWindow with a visual, and
XrSurfaceCreateForPixmap with an XrFormat. Would that work?
*/
XrSurface *
XrSurfaceCreateForDrawable (Display *dpy,
Drawable drawable,
Visual *visual,
XrFormat format,
Colormap colormap);
XrSurface *
XrSurfaceCreateForImage (char *data,
XrFormat format,
int width,
int height,
int stride);
XrSurface *
XrSurfaceCreateNextTo (XrSurface *neighbor,
XrFormat format,
int width,
int height);
/* XXX: One problem with having RGB and A here in one function is that
it introduces the question of pre-multiplied vs. non-pre-multiplied
alpha. Do I want to export an XrColor structure instead? So far, no
other public functions need it. */
XrSurface *
XrSurfaceCreateNextToSolid (XrSurface *neighbor,
XrFormat format,
int width,
int height,
double red,
double green,
double blue,
double alpha);
void
XrSurfaceDestroy(XrSurface *surface);
/* XXX: Should this take an X/Y offset as well? (Probably) */
XrStatus
XrSurfacePutImage (XrSurface *surface,
char *data,
int width,
int height,
int stride);
/* XXX: The Xc version of this function isn't quite working yet
XrStatus
XrSurfaceSetClipRegion (XrSurface *surface, Region region);
*/
/* XXX: Note: The current Render/Ic implementations don't do the right
thing with repeat when the surface has a non-identity matrix. */
XrStatus
XrSurfaceSetRepeat (XrSurface *surface, int repeat);
XrStatus
XrSurfaceSetMatrix(XrSurface *surface, XrMatrix *matrix);
XrStatus
XrSurfaceGetMatrix (XrSurface *surface, XrMatrix *matrix);
typedef enum {
XrFilterFast = XcFilterFast,
XrFilterGood = XcFilterGood,
XrFilterBest = XcFilterBest,
XrFilterNearest = XcFilterNearest,
XrFilterBilinear = XcFilterBilinear
} XrFilter;
XrStatus
XrSurfaceSetFilter(XrSurface *surface, XrFilter filter);
/* Matrix functions */
XrMatrix *
XrMatrixCreate (void);
void
XrMatrixDestroy (XrMatrix *matrix);
XrStatus
XrMatrixCopy(XrMatrix *matrix, const XrMatrix *other);
XrStatus
XrMatrixSetIdentity (XrMatrix *matrix);
XrStatus
XrMatrixSetAffine (XrMatrix *xrs,
double a, double b,
double c, double d,
double tx, double ty);
XrStatus
XrMatrixGetAffine (XrMatrix *matrix,
double *a, double *b,
double *c, double *d,
double *tx, double *ty);
XrStatus
XrMatrixTranslate (XrMatrix *matrix, double tx, double ty);
XrStatus
XrMatrixScale (XrMatrix *matrix, double sx, double sy);
XrStatus
XrMatrixRotate (XrMatrix *matrix, double radians);
XrStatus
XrMatrixInvert(XrMatrix *matrix);
XrStatus
XrMatrixMultiply (XrMatrix *result, const XrMatrix *a, const XrMatrix *b);
XrStatus
XrMatrixTransformDistance (XrMatrix *xr, double *dx, double *dy);
XrStatus
XrMatrixTransformPoint (XrMatrix *xr, double *x, double *y);
_XFUNCPROTOEND
#endif

80
src/cairo-color.c Normal file
View file

@ -0,0 +1,80 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
static cairo_color_t CAIRO_COLOR_DEFAULT = { 1.0, 1.0, 1.0, 1.0, {0xffff, 0xffff, 0xffff, 0xffff}};
static void
_cairo_color_compute_xc_color (cairo_color_t *color);
void
_cairo_color_init (cairo_color_t *color)
{
*color = CAIRO_COLOR_DEFAULT;
}
void
_cairo_color_fini (cairo_color_t *color)
{
/* Nothing to do here */
}
static void
_cairo_color_compute_xc_color (cairo_color_t *color)
{
color->xc_color.red = color->red * color->alpha * 0xffff;
color->xc_color.green = color->green * color->alpha * 0xffff;
color->xc_color.blue = color->blue * color->alpha * 0xffff;
color->xc_color.alpha = color->alpha * 0xffff;
}
void
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
{
color->red = red;
color->green = green;
color->blue = blue;
_cairo_color_compute_xc_color (color);
}
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
{
*red = color->red;
*green = color->green;
*blue = color->blue;
}
void
_cairo_color_set_alpha (cairo_color_t *color, double alpha)
{
color->alpha = alpha;
_cairo_color_compute_xc_color (color);
}

171
src/cairo-font.c Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <string.h>
#include "cairoint.h"
void
_cairo_font_init (cairo_font_t *font)
{
font->key = (unsigned char *) strdup (CAIRO_FONT_KEY_DEFAULT);
font->dpy = NULL;
font->xft_font = NULL;
cairo_matrix_set_identity (&font->matrix);
}
cairo_status_t
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other)
{
*font = *other;
if (other->key) {
font->key = (unsigned char *) strdup ((char *) other->key);
if (font->key == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
if (other->xft_font) {
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
if (font->xft_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_font_fini (cairo_font_t *font)
{
if (font->key)
free (font->key);
font->key = NULL;
_cairo_matrix_fini (&font->matrix);
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
}
cairo_status_t
_cairo_font_select (cairo_font_t *font, const char *key)
{
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->key)
free (font->key);
font->key = (unsigned char *) strdup ((char *) key);
if (font->key == NULL)
return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_font_scale (cairo_font_t *font, double scale)
{
cairo_matrix_scale (&font->matrix, scale, scale);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_font_transform (cairo_font_t *font,
double a, double b,
double c, double d)
{
cairo_matrix_t m;
cairo_matrix_set_affine (&m, a, b, c, d, 0, 0);
cairo_matrix_multiply (&font->matrix, &m, &font->matrix);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
cairo_matrix_t matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font) {
*xft_font = font->xft_font;
return CAIRO_STATUS_SUCCESS;
}
pattern = FcNameParse (font->key);
matrix = gstate->ctm;
cairo_matrix_multiply (&matrix, &font->matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling? */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (expansion);
FcPatternAddDouble (pattern, "pixelsize", font_size);
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
/* XXX: Need to abandon Xft and use Xc instead */
/* When I do that I can throw away these Display pointers */
font->dpy = gstate->surface->dpy;
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
*xft_font = font->xft_font;
FcPatternDestroy (pattern);
return CAIRO_STATUS_SUCCESS;
}

1123
src/cairo-gstate.c Normal file

File diff suppressed because it is too large Load diff

380
src/cairo-matrix.c Normal file
View file

@ -0,0 +1,380 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include <math.h>
#include "cairoint.h"
static cairo_matrix_t CAIRO_MATRIX_IDENTITY = {
{
{1, 0},
{0, 1},
{0, 0}
}
};
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
cairo_matrix_t *
cairo_matrix_create (void)
{
cairo_matrix_t *matrix;
matrix = malloc (sizeof (cairo_matrix_t));
if (matrix == NULL)
return NULL;
_cairo_matrix_init (matrix);
return matrix;
}
void
_cairo_matrix_init (cairo_matrix_t *matrix)
{
cairo_matrix_set_identity (matrix);
}
void
_cairo_matrix_fini (cairo_matrix_t *matrix)
{
/* nothing to do here */
}
void
cairo_matrix_destroy (cairo_matrix_t *matrix)
{
_cairo_matrix_fini (matrix);
free (matrix);
}
cairo_status_t
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
{
*matrix = *other;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix)
{
*matrix = CAIRO_MATRIX_IDENTITY;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_set_affine (cairo_matrix_t *matrix,
double a, double b,
double c, double d,
double tx, double ty)
{
matrix->m[0][0] = a; matrix->m[0][1] = b;
matrix->m[1][0] = c; matrix->m[1][1] = d;
matrix->m[2][0] = tx; matrix->m[2][1] = ty;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *a, double *b,
double *c, double *d,
double *tx, double *ty)
{
*a = matrix->m[0][0]; *b = matrix->m[0][1];
*c = matrix->m[1][0]; *d = matrix->m[1][1];
*tx = matrix->m[2][0]; *ty = matrix->m[2][1];
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
double tx, double ty)
{
return cairo_matrix_set_affine (matrix,
1, 0,
0, 1,
tx, ty);
}
cairo_status_t
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
cairo_matrix_t tmp;
_cairo_matrix_set_translate (&tmp, tx, ty);
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
cairo_status_t
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
double sx, double sy)
{
return cairo_matrix_set_affine (matrix,
sx, 0,
0, sy,
0, 0);
}
cairo_status_t
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
cairo_matrix_t tmp;
_cairo_matrix_set_scale (&tmp, sx, sy);
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double radians)
{
return cairo_matrix_set_affine (matrix,
cos (radians), sin (radians),
-sin (radians), cos (radians),
0, 0);
}
cairo_status_t
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
cairo_matrix_t tmp;
_cairo_matrix_set_rotate (&tmp, radians);
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
cairo_status_t
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
cairo_matrix_t r;
int row, col, n;
double t;
for (row = 0; row < 3; row++) {
for (col = 0; col < 2; col++) {
if (row == 2)
t = b->m[2][col];
else
t = 0;
for (n = 0; n < 2; n++) {
t += a->m[row][n] * b->m[n][col];
}
r.m[row][col] = t;
}
}
*result = r;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
{
double new_x, new_y;
new_x = (matrix->m[0][0] * *dx
+ matrix->m[1][0] * *dy);
new_y = (matrix->m[0][1] * *dx
+ matrix->m[1][1] * *dy);
*dx = new_x;
*dy = new_y;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
{
cairo_matrix_transform_distance (matrix, x, y);
*x += matrix->m[2][0];
*y += matrix->m[2][1];
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height)
{
int i;
double quad_x[4], quad_y[4];
double dx1, dy1;
double dx2, dy2;
double min_x, max_x;
double min_y, max_y;
quad_x[0] = *x;
quad_y[0] = *y;
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
dx1 = *width;
dy1 = 0;
cairo_matrix_transform_distance (matrix, &dx1, &dy1);
quad_x[1] = quad_x[0] + dx1;
quad_y[1] = quad_y[0] + dy1;
dx2 = 0;
dy2 = *height;
cairo_matrix_transform_distance (matrix, &dx2, &dy2);
quad_x[2] = quad_x[0] + dx2;
quad_y[2] = quad_y[0] + dy2;
quad_x[3] = quad_x[0] + dx1 + dx2;
quad_y[3] = quad_y[0] + dy1 + dy2;
min_x = max_x = quad_x[0];
min_y = max_y = quad_y[0];
for (i=1; i < 4; i++) {
if (quad_x[i] < min_x)
min_x = quad_x[i];
if (quad_x[i] > max_x)
max_x = quad_x[i];
if (quad_y[i] < min_y)
min_y = quad_y[i];
if (quad_y[i] > max_y)
max_y = quad_y[i];
}
*x = min_x;
*y = min_y;
*width = max_x - min_x;
*height = max_y - min_y;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
int row, col;
for (row = 0; row < 3; row++)
for (col = 0; col < 2; col++)
matrix->m[row][col] *= scalar;
}
/* This function isn't a correct adjoint in that the implicit 1 in the
homogeneous result should actually be ad-bc instead. But, since this
adjoint is only used in the computation of the inverse, which
divides by det (A)=ad-bc anyway, everything works out in the end. */
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
{
/* adj (A) = transpose (C:cofactor (A,i,j)) */
double a, b, c, d, tx, ty;
a = matrix->m[0][0]; b = matrix->m[0][1];
c = matrix->m[1][0]; d = matrix->m[1][1];
tx = matrix->m[2][0]; ty = matrix->m[2][1];
cairo_matrix_set_affine (matrix,
d, -b,
-c, a,
c*ty - d*tx, b*tx - a*ty);
}
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix)
{
/* inv (A) = 1/det (A) * adj (A) */
double det;
_cairo_matrix_compute_determinant (matrix, &det);
if (det == 0)
return CAIRO_STATUS_INVALID_MATRIX;
_cairo_matrix_compute_adjoint (matrix);
_cairo_matrix_scalar_multiply (matrix, 1 / det);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
{
double a, b, c, d;
a = matrix->m[0][0]; b = matrix->m[0][1];
c = matrix->m[1][0]; d = matrix->m[1][1];
*det = a*d - b*c;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
{
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
det (M - lI) = 0
The zeros in our homogeneous 3x3 matrix make this equation equal
to that formed by the sub-matrix:
M = a b
c d
by which:
l^2 - (a+d)l + (ad - bc) = 0
l = (a+d +/- sqrt (a^2 + 2ad + d^2 - 4 (ad-bc))) / 2;
*/
double a, b, c, d, rad;
a = matrix->m[0][0];
b = matrix->m[0][1];
c = matrix->m[1][0];
d = matrix->m[1][1];
rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
*lambda1 = (a + d + rad) / 2.0;
*lambda2 = (a + d - rad) / 2.0;
return CAIRO_STATUS_SUCCESS;
}

168
src/cairo-path-bounds.c Normal file
View file

@ -0,0 +1,168 @@
/*
* Copyright © 2003 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
typedef struct _cairo_path_bounder {
int has_pt;
XFixed min_x;
XFixed min_y;
XFixed max_x;
XFixed max_y;
} cairo_path_bounder;
static void
_cairo_path_bounder_init (cairo_path_bounder *bounder);
static void
_cairo_path_bounder_fini (cairo_path_bounder *bounder);
static cairo_status_t
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt);
static cairo_status_t
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_path_bounder_add_spline (void *closure,
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static cairo_status_t
_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done done);
static cairo_status_t
_cairo_path_bounder_done_path (void *closure);
static void
_cairo_path_bounder_init (cairo_path_bounder *bounder)
{
bounder->has_pt = 0;
}
static void
_cairo_path_bounder_fini (cairo_path_bounder *bounder)
{
bounder->has_pt = 0;
}
static cairo_status_t
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt)
{
if (bounder->has_pt) {
if (pt->x < bounder->min_x)
bounder->min_x = pt->x;
if (pt->y < bounder->min_y)
bounder->min_y = pt->y;
if (pt->x > bounder->max_x)
bounder->max_x = pt->x;
if (pt->y > bounder->max_y)
bounder->max_y = pt->y;
} else {
bounder->min_x = pt->x;
bounder->min_y = pt->y;
bounder->max_x = pt->x;
bounder->max_y = pt->y;
bounder->has_pt = 1;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_path_bounder *bounder = closure;
_cairo_path_bounder_add_point (bounder, p1);
_cairo_path_bounder_add_point (bounder, p2);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_add_spline (void *closure,
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
cairo_path_bounder *bounder = closure;
_cairo_path_bounder_add_point (bounder, a);
_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_done_sub_path (void *closure, cairo_sub_path_done done)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_done_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
static cairo_path_callbacks_t cb = {
_cairo_path_bounder_add_edge,
_cairo_path_bounder_add_spline,
_cairo_path_bounder_done_sub_path,
_cairo_path_bounder_done_path
};
cairo_path_bounder bounder;
_cairo_path_bounder_init (&bounder);
status = _cairo_path_interpret (path, cairo_path_direction_forward, &cb, &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_cairo_path_bounder_fini (&bounder);
return status;
}
*x1 = XFixedToDouble (bounder.min_x);
*y1 = XFixedToDouble (bounder.min_y);
*x2 = XFixedToDouble (bounder.max_x);
*y2 = XFixedToDouble (bounder.max_y);
_cairo_path_bounder_fini (&bounder);
return CAIRO_STATUS_SUCCESS;
}

158
src/cairo-path-fill.c Normal file
View file

@ -0,0 +1,158 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
typedef struct _cairo_filler {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
cairo_polygon_t polygon;
} cairo_filler;
static void
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
static void
_cairo_filler_fini (cairo_filler *filler);
static cairo_status_t
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static cairo_status_t
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done);
static cairo_status_t
_cairo_filler_done_path (void *closure);
static void
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
filler->gstate = gstate;
filler->traps = traps;
_cairo_polygon_init (&filler->polygon);
}
static void
_cairo_filler_fini (cairo_filler *filler)
{
_cairo_polygon_fini (&filler->polygon);
}
static cairo_status_t
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_filler *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
return _cairo_polygon_add_edge (polygon, p1, p2);
}
static cairo_status_t
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
int i;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
cairo_gstate_t *gstate = filler->gstate;
cairo_spline_t spline;
status = _cairo_spline_init (&spline, a, b, c, d);
if (status == cairo_int_status_degenerate)
return CAIRO_STATUS_SUCCESS;
_cairo_spline_decompose (&spline, gstate->tolerance);
if (status)
goto CLEANUP_SPLINE;
for (i = 0; i < spline.num_pts - 1; i++) {
status = _cairo_polygon_add_edge (polygon, &spline.pts[i], &spline.pts[i+1]);
if (status)
goto CLEANUP_SPLINE;
}
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
return status;
}
static cairo_status_t
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_close (polygon);
return status;
}
static cairo_status_t
_cairo_filler_done_path (void *closure)
{
cairo_filler *filler = closure;
return cairo_traps_tessellate_polygon (filler->traps,
&filler->polygon,
filler->gstate->fill_rule);
}
cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
static const cairo_path_callbacks_t filler_callbacks = {
_cairo_filler_add_edge,
_cairo_filler_add_spline,
_cairo_filler_done_sub_path,
_cairo_filler_done_path
};
cairo_status_t status;
cairo_filler filler;
_cairo_filler_init (&filler, gstate, traps);
status = _cairo_path_interpret (path,
cairo_path_direction_forward,
&filler_callbacks, &filler);
if (status) {
_cairo_filler_fini (&filler);
return status;
}
_cairo_filler_fini (&filler);
return CAIRO_STATUS_SUCCESS;
}

715
src/cairo-path-stroke.c Normal file
View file

@ -0,0 +1,715 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
typedef struct _cairo_stroker {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
int have_prev;
int have_first;
int is_first;
cairo_stroke_face_t prev;
cairo_stroke_face_t first;
int dash_index;
int dash_on;
double dash_remain;
} cairo_stroker;
/* private functions */
static void
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps);
static void
_cairo_stroker_fini (cairo_stroker *stroker);
static cairo_status_t
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static cairo_status_t
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done);
static cairo_status_t
_cairo_stroker_done_path (void *closure);
static void
_translate_point (XPointFixed *pt, XPointFixed *offset);
static int
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out);
static cairo_status_t
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
static void
_cairo_stroker_start_dash (cairo_stroker *stroker)
{
cairo_gstate_t *gstate = stroker->gstate;
double offset;
int on = 1;
int i = 0;
offset = gstate->dash_offset;
while (offset >= gstate->dash[i]) {
offset -= gstate->dash[i];
on = 1-on;
if (++i == gstate->num_dashes)
i = 0;
}
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_remain = gstate->dash[i] - offset;
}
static void
_cairo_stroker_step_dash (cairo_stroker *stroker, double step)
{
cairo_gstate_t *gstate = stroker->gstate;
stroker->dash_remain -= step;
if (stroker->dash_remain <= 0) {
stroker->dash_index++;
if (stroker->dash_index == gstate->num_dashes)
stroker->dash_index = 0;
stroker->dash_on = 1-stroker->dash_on;
stroker->dash_remain = gstate->dash[stroker->dash_index];
}
}
static void
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
stroker->gstate = gstate;
stroker->traps = traps;
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
if (gstate->dash)
_cairo_stroker_start_dash (stroker);
}
static void
_cairo_stroker_fini (cairo_stroker *stroker)
{
/* nothing to do here */
}
static void
_translate_point (XPointFixed *pt, XPointFixed *offset)
{
pt->x += offset->x;
pt->y += offset->y;
}
static int
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
XPointDouble d_in, d_out;
d_in.x = XFixedToDouble (in->cw.x - in->pt.x);
d_in.y = XFixedToDouble (in->cw.y - in->pt.y);
d_out.x = XFixedToDouble (out->cw.x - out->pt.x);
d_out.y = XFixedToDouble (out->cw.y - out->pt.y);
return d_out.y * d_in.x > d_in.y * d_out.x;
}
static cairo_status_t
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
cairo_status_t status;
cairo_gstate_t *gstate = stroker->gstate;
int clockwise = _cairo_stroker_face_clockwise (out, in);
XPointFixed *inpt, *outpt;
if (in->cw.x == out->cw.x
&& in->cw.y == out->cw.y
&& in->ccw.x == out->ccw.x
&& in->ccw.y == out->ccw.y) {
return CAIRO_STATUS_SUCCESS;
}
if (clockwise) {
inpt = &in->ccw;
outpt = &out->ccw;
} else {
inpt = &in->cw;
outpt = &out->cw;
}
switch (gstate->line_join) {
case CAIRO_LINE_JOIN_ROUND: {
int i;
int start, step, stop;
XPointFixed tri[3], initial, final;
cairo_pen_t *pen = &gstate->pen_regular;
tri[0] = in->pt;
if (clockwise) {
initial = in->ccw;
_cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
step = -1;
_cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
final = out->ccw;
} else {
initial = in->cw;
_cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
step = +1;
_cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
final = out->cw;
}
i = start;
tri[1] = initial;
while (i != stop) {
tri[2] = in->pt;
_translate_point (&tri[2], &pen->vertex[i].pt);
cairo_traps_tessellate_triangle (stroker->traps, tri);
tri[1] = tri[2];
i += step;
if (i < 0)
i = pen->num_vertices - 1;
if (i >= pen->num_vertices)
i = 0;
}
tri[2] = final;
return cairo_traps_tessellate_triangle (stroker->traps, tri);
}
case CAIRO_LINE_JOIN_MITER:
default: {
cairo_polygon_t polygon;
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
XDouble ml = gstate->miter_limit;
_cairo_polygon_init (&polygon);
if (2 <= ml * ml * (1 - c)) {
XDouble x1, y1, x2, y2;
XDouble mx, my;
XDouble dx1, dx2, dy1, dy2;
XPointFixed outer;
x1 = XFixedToDouble (inpt->x);
y1 = XFixedToDouble (inpt->y);
dx1 = in->usr_vector.x;
dy1 = in->usr_vector.y;
cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
x2 = XFixedToDouble (outpt->x);
y2 = XFixedToDouble (outpt->y);
dx2 = out->usr_vector.x;
dy2 = out->usr_vector.y;
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
(dx1 * dy2 - dx2 * dy1));
if (dy1)
mx = (my - y1) * dx1 / dy1 + x1;
else
mx = (my - y2) * dx2 / dy2 + x2;
outer.x = XDoubleToFixed (mx);
outer.y = XDoubleToFixed (my);
_cairo_polygon_add_edge (&polygon, &in->pt, inpt);
_cairo_polygon_add_edge (&polygon, inpt, &outer);
_cairo_polygon_add_edge (&polygon, &outer, outpt);
_cairo_polygon_add_edge (&polygon, outpt, &in->pt);
status = cairo_traps_tessellate_polygon (stroker->traps,
&polygon,
CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
return status;
}
/* fall through ... */
}
case CAIRO_LINE_JOIN_BEVEL: {
XPointFixed tri[3];
tri[0] = in->pt;
tri[1] = *inpt;
tri[2] = *outpt;
return cairo_traps_tessellate_triangle (stroker->traps, tri);
}
}
}
static cairo_status_t
_cairo_stroker_cap (cairo_stroker *stroker, cairo_stroke_face_t *f)
{
cairo_status_t status;
cairo_gstate_t *gstate = stroker->gstate;
if (gstate->line_cap == CAIRO_LINE_CAP_BUTT)
return CAIRO_STATUS_SUCCESS;
switch (gstate->line_cap) {
case CAIRO_LINE_CAP_ROUND: {
int i;
int start, stop;
cairo_slope_fixed_t slope;
XPointFixed tri[3];
cairo_pen_t *pen = &gstate->pen_regular;
slope = f->dev_vector;
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
tri[0] = f->pt;
tri[1] = f->cw;
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
tri[2] = f->pt;
_translate_point (&tri[2], &pen->vertex[i].pt);
cairo_traps_tessellate_triangle (stroker->traps, tri);
tri[1] = tri[2];
}
tri[2] = f->ccw;
return cairo_traps_tessellate_triangle (stroker->traps, tri);
}
case CAIRO_LINE_CAP_SQUARE: {
double dx, dy;
cairo_slope_fixed_t fvector;
XPointFixed occw, ocw;
cairo_polygon_t polygon;
_cairo_polygon_init (&polygon);
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= gstate->line_width / 2.0;
dy *= gstate->line_width / 2.0;
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
fvector.dx = XDoubleToFixed (dx);
fvector.dy = XDoubleToFixed (dy);
occw.x = f->ccw.x + fvector.dx;
occw.y = f->ccw.y + fvector.dy;
ocw.x = f->cw.x + fvector.dx;
ocw.y = f->cw.y + fvector.dy;
_cairo_polygon_add_edge (&polygon, &f->cw, &ocw);
_cairo_polygon_add_edge (&polygon, &ocw, &occw);
_cairo_polygon_add_edge (&polygon, &occw, &f->ccw);
_cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw);
status = cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
return status;
}
case CAIRO_LINE_CAP_BUTT:
default:
return CAIRO_STATUS_SUCCESS;
}
}
static void
_compute_face (XPointFixed *pt, cairo_slope_fixed_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
{
double mag, tmp;
double dx, dy;
XPointDouble usr_vector;
XPointFixed offset_ccw, offset_cw;
dx = XFixedToDouble (slope->dx);
dy = XFixedToDouble (slope->dy);
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
mag = sqrt (dx * dx + dy * dy);
if (mag == 0) {
/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
return;
}
dx /= mag;
dy /= mag;
usr_vector.x = dx;
usr_vector.y = dy;
tmp = dx;
dx = - dy * (gstate->line_width / 2.0);
dy = tmp * (gstate->line_width / 2.0);
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
offset_ccw.x = XDoubleToFixed (dx);
offset_ccw.y = XDoubleToFixed (dy);
offset_cw.x = -offset_ccw.x;
offset_cw.y = -offset_ccw.y;
face->ccw = *pt;
_translate_point (&face->ccw, &offset_ccw);
face->pt = *pt;
face->cw = *pt;
_translate_point (&face->cw, &offset_cw);
face->usr_vector.x = usr_vector.x;
face->usr_vector.y = usr_vector.y;
face->dev_vector = *slope;
}
static cairo_status_t
_cairo_stroker_add_sub_edge (cairo_stroker *stroker, XPointFixed *p1, XPointFixed *p2,
cairo_stroke_face_t *start, cairo_stroke_face_t *end)
{
cairo_gstate_t *gstate = stroker->gstate;
XPointFixed quad[4];
cairo_slope_fixed_t slope;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in _compute_face). The key behavior is that
degenerate paths should draw as much as possible. */
return CAIRO_STATUS_SUCCESS;
}
_compute_slope (p1, p2, &slope);
_compute_face (p1, &slope, gstate, start);
/* XXX: This could be optimized slightly by not calling
_compute_face again but rather translating the relevant
fields from start. */
_compute_face (p2, &slope, gstate, end);
quad[0] = start->cw;
quad[1] = start->ccw;
quad[2] = end->ccw;
quad[3] = end->cw;
return cairo_traps_tessellate_rectangle (stroker->traps, quad);
}
static cairo_status_t
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_status_t status;
cairo_stroker *stroker = closure;
cairo_stroke_face_t start, end;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in cairo_stroker_add_sub_edge and in _compute_face). The
key behavior is that degenerate paths should draw as much
as possible. */
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &start, &end);
if (status)
return status;
if (stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
return CAIRO_STATUS_SUCCESS;
}
/*
* Dashed lines. Cap each dash end, join around turns when on
*/
static cairo_status_t
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker *stroker = closure;
cairo_gstate_t *gstate = stroker->gstate;
double mag, remain, tmp;
double dx, dy;
double dx2, dy2;
XPointFixed fd1, fd2;
int first = 1;
cairo_stroke_face_t sub_start, sub_end;
dx = XFixedToDouble (p2->x - p1->x);
dy = XFixedToDouble (p2->y - p1->y);
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
mag = sqrt (dx *dx + dy * dy);
remain = mag;
fd1 = *p1;
while (remain) {
tmp = stroker->dash_remain;
if (tmp > remain)
tmp = remain;
remain -= tmp;
dx2 = dx * (mag - remain)/mag;
dy2 = dy * (mag - remain)/mag;
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
fd2.x = XDoubleToFixed (dx2);
fd2.y = XDoubleToFixed (dy2);
fd2.x += p1->x;
fd2.y += p1->y;
/*
* XXX simplify this case analysis
*/
if (stroker->dash_on) {
status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &sub_start, &sub_end);
if (status)
return status;
if (!first) {
/*
* Not first dash in this segment, cap start
*/
status = _cairo_stroker_cap (stroker, &sub_start);
if (status)
return status;
} else {
/*
* First in this segment, join to any prev, else
* if at start of sub-path, mark position, else
* cap
*/
if (stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start);
if (status)
return status;
} else {
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = sub_start;
} else {
status = _cairo_stroker_cap (stroker, &sub_start);
if (status)
return status;
}
}
}
if (remain) {
/*
* Cap if not at end of segment
*/
status = _cairo_stroker_cap (stroker, &sub_end);
if (status)
return status;
} else {
/*
* Mark previous line face and fix up next time
* through
*/
stroker->prev = sub_end;
stroker->have_prev = 1;
}
} else {
/*
* If starting with off dash, check previous face
* and cap if necessary
*/
if (first) {
if (stroker->have_prev) {
status = _cairo_stroker_cap (stroker, &stroker->prev);
if (status)
return status;
}
}
if (!remain)
stroker->have_prev = 0;
}
_cairo_stroker_step_dash (stroker, tmp);
fd1 = fd2;
first = 0;
}
stroker->is_first = 0;
return status;
}
static cairo_status_t
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker *stroker = closure;
cairo_gstate_t *gstate = stroker->gstate;
cairo_spline_t spline;
cairo_pen_t pen;
cairo_stroke_face_t start, end;
XPointFixed extra_points[4];
status = _cairo_spline_init (&spline, a, b, c, d);
if (status == cairo_int_status_degenerate)
return CAIRO_STATUS_SUCCESS;
status = _cairo_pen_init_copy (&pen, &gstate->pen_regular);
if (status)
goto CLEANUP_SPLINE;
_compute_face (a, &spline.initial_slope, gstate, &start);
_compute_face (d, &spline.final_slope, gstate, &end);
if (stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
extra_points[0] = start.cw;
extra_points[0].x -= start.pt.x;
extra_points[0].y -= start.pt.y;
extra_points[1] = start.ccw;
extra_points[1].x -= start.pt.x;
extra_points[1].y -= start.pt.y;
extra_points[2] = end.cw;
extra_points[2].x -= end.pt.x;
extra_points[2].y -= end.pt.y;
extra_points[3] = end.ccw;
extra_points[3].x -= end.pt.x;
extra_points[3].y -= end.pt.y;
status = _cairo_pen_add_points (&pen, extra_points, 4);
if (status)
goto CLEANUP_PEN;
status = _cairo_pen_stroke_spline (&pen, &spline, gstate->tolerance, stroker->traps);
if (status)
goto CLEANUP_PEN;
CLEANUP_PEN:
_cairo_pen_fini (&pen);
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
return status;
}
static cairo_status_t
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done)
{
cairo_status_t status;
cairo_stroker *stroker = closure;
switch (done) {
case cairo_sub_path_done_join:
if (stroker->have_first && stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first);
if (status)
return status;
break;
}
/* fall through... */
case cairo_sub_path_done_cap:
if (stroker->have_first) {
XPointFixed t;
/* The initial cap needs an outward facing vector. Reverse everything */
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
t = stroker->first.cw;
stroker->first.cw = stroker->first.ccw;
stroker->first.ccw = t;
status = _cairo_stroker_cap (stroker, &stroker->first);
if (status)
return status;
}
if (stroker->have_prev) {
status = _cairo_stroker_cap (stroker, &stroker->prev);
if (status)
return status;
}
break;
}
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_stroker_done_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
static const cairo_path_callbacks_t stroker_solid_cb = {
_cairo_stroker_add_edge,
_cairo_stroker_add_spline,
_cairo_stroker_done_sub_path,
_cairo_stroker_done_path
};
static const cairo_path_callbacks_t stroker_dashed_cb = {
_cairo_stroker_add_edge_dashed,
_cairo_stroker_add_spline,
_cairo_stroker_done_sub_path,
_cairo_stroker_done_path
};
const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
cairo_status_t status;
cairo_stroker stroker;
_cairo_stroker_init (&stroker, gstate, traps);
status = _cairo_path_interpret (path,
cairo_path_direction_forward,
callbacks, &stroker);
if (status) {
_cairo_stroker_fini (&stroker);
return status;
}
_cairo_stroker_fini (&stroker);
return CAIRO_STATUS_SUCCESS;
}

436
src/cairo-path.c Normal file
View file

@ -0,0 +1,436 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include "cairoint.h"
/* private functions */
static cairo_status_t
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts);
static void
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op);
static cairo_status_t
_cairo_path_new_op_buf (cairo_path_t *path);
static void
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg);
static cairo_status_t
_cairo_path_new_arg_buf (cairo_path_t *path);
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void);
static void
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *buf);
static void
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op);
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void);
static void
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *buf);
static void
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts);
void
_cairo_path_init (cairo_path_t *path)
{
path->op_head = NULL;
path->op_tail = NULL;
path->arg_head = NULL;
path->arg_tail = NULL;
}
cairo_status_t
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
{
cairo_path_op_buf_t *op, *other_op;
cairo_path_arg_buf_t *arg, *other_arg;
_cairo_path_init (path);
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _cairo_path_op_buf_create ();
if (op == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
*op = *other_op;
_cairo_path_add_op_buf (path, op);
}
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
arg = _cairo_path_arg_buf_create ();
if (arg == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
*arg = *other_arg;
_cairo_path_add_arg_buf (path, arg);
}
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_path_fini (cairo_path_t *path)
{
cairo_path_op_buf_t *op;
cairo_path_arg_buf_t *arg;
while (path->op_head) {
op = path->op_head;
path->op_head = op->next;
_cairo_path_op_buf_destroy (op);
}
path->op_tail = NULL;
while (path->arg_head) {
arg = path->arg_head;
path->arg_head = arg->next;
_cairo_path_arg_buf_destroy (arg);
}
path->arg_tail = NULL;
}
cairo_status_t
_cairo_path_move_to (cairo_path_t *path, double x, double y)
{
XPointFixed pt;
pt.x = XDoubleToFixed (x);
pt.y = XDoubleToFixed (y);
return _cairo_path_add (path, cairo_path_op_move_to, &pt, 1);
}
cairo_status_t
_cairo_path_line_to (cairo_path_t *path, double x, double y)
{
XPointFixed pt;
pt.x = XDoubleToFixed (x);
pt.y = XDoubleToFixed (y);
return _cairo_path_add (path, cairo_path_op_line_to, &pt, 1);
}
cairo_status_t
_cairo_path_curve_to (cairo_path_t *path,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
XPointFixed pt[3];
pt[0].x = XDoubleToFixed (x1);
pt[0].y = XDoubleToFixed (y1);
pt[1].x = XDoubleToFixed (x2);
pt[1].y = XDoubleToFixed (y2);
pt[2].x = XDoubleToFixed (x3);
pt[2].y = XDoubleToFixed (y3);
return _cairo_path_add (path, cairo_path_op_curve_to, pt, 3);
}
cairo_status_t
_cairo_path_close_path (cairo_path_t *path)
{
return _cairo_path_add (path, cairo_path_op_close_path, NULL, 0);
}
static cairo_status_t
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts)
{
cairo_status_t status;
if (path->op_tail == NULL || path->op_tail->num_ops + 1 > CAIRO_PATH_BUF_SZ) {
status = _cairo_path_new_op_buf (path);
if (status)
return status;
}
_cairo_path_op_buf_add (path->op_tail, op);
if (path->arg_tail == NULL || path->arg_tail->num_pts + num_pts > CAIRO_PATH_BUF_SZ) {
status = _cairo_path_new_arg_buf (path);
if (status)
return status;
}
_cairo_path_arg_buf_add (path->arg_tail, pts, num_pts);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op)
{
op->next = NULL;
op->prev = path->op_tail;
if (path->op_tail) {
path->op_tail->next = op;
} else {
path->op_head = op;
}
path->op_tail = op;
}
static cairo_status_t
_cairo_path_new_op_buf (cairo_path_t *path)
{
cairo_path_op_buf_t *op;
op = _cairo_path_op_buf_create ();
if (op == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_path_add_op_buf (path, op);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
{
arg->next = NULL;
arg->prev = path->arg_tail;
if (path->arg_tail) {
path->arg_tail->next = arg;
} else {
path->arg_head = arg;
}
path->arg_tail = arg;
}
static cairo_status_t
_cairo_path_new_arg_buf (cairo_path_t *path)
{
cairo_path_arg_buf_t *arg;
arg = _cairo_path_arg_buf_create ();
if (arg == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_path_add_arg_buf (path, arg);
return CAIRO_STATUS_SUCCESS;
}
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void)
{
cairo_path_op_buf_t *op;
op = malloc (sizeof (cairo_path_op_buf_t));
if (op) {
op->num_ops = 0;
op->next = NULL;
}
return op;
}
static void
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
{
free (op);
}
static void
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op)
{
op_buf->op[op_buf->num_ops++] = op;
}
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void)
{
cairo_path_arg_buf_t *arg;
arg = malloc (sizeof (cairo_path_arg_buf_t));
if (arg) {
arg->num_pts = 0;
arg->next = NULL;
}
return arg;
}
static void
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
{
free (arg);
}
static void
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts)
{
int i;
for (i=0; i < num_pts; i++) {
arg->pt[arg->num_pts++] = pts[i];
}
}
#define CAIRO_PATH_OP_MAX_ARGS 3
static int num_args[] =
{
1, /* cairo_path_move_to */
1, /* cairo_path_op_line_to */
3, /* cairo_path_op_curve_to */
0, /* cairo_path_op_close_path */
};
cairo_status_t
_cairo_path_interpret (cairo_path_t *path, cairo_path_direction dir, const cairo_path_callbacks_t *cb, void *closure)
{
cairo_status_t status;
int i, arg;
cairo_path_op_buf_t *op_buf;
cairo_path_op op;
cairo_path_arg_buf_t *arg_buf = path->arg_head;
int buf_i = 0;
XPointFixed pt[CAIRO_PATH_OP_MAX_ARGS];
XPointFixed current = {0, 0};
XPointFixed first = {0, 0};
int has_current = 0;
int has_edge = 0;
int step = (dir == cairo_path_direction_forward) ? 1 : -1;
for (op_buf = (dir == cairo_path_direction_forward) ? path->op_head : path->op_tail;
op_buf;
op_buf = (dir == cairo_path_direction_forward) ? op_buf->next : op_buf->prev)
{
int start, stop;
if (dir == cairo_path_direction_forward) {
start = 0;
stop = op_buf->num_ops;
} else {
start = op_buf->num_ops - 1;
stop = -1;
}
for (i=start; i != stop; i += step) {
op = op_buf->op[i];
if (dir == cairo_path_direction_reverse) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_pts;
}
buf_i -= num_args[op];
}
for (arg = 0; arg < num_args[op]; arg++) {
pt[arg] = arg_buf->pt[buf_i];
buf_i++;
if (buf_i >= arg_buf->num_pts) {
arg_buf = arg_buf->next;
buf_i = 0;
}
}
if (dir == cairo_path_direction_reverse) {
buf_i -= num_args[op];
}
switch (op) {
case cairo_path_op_move_to:
if (has_edge) {
status = (*cb->DoneSubPath) (closure, cairo_sub_path_done_cap);
if (status)
return status;
}
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
break;
case cairo_path_op_line_to:
if (has_current) {
status = (*cb->AddEdge) (closure, &current, &pt[0]);
if (status)
return status;
current = pt[0];
has_edge = 1;
} else {
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
}
break;
case cairo_path_op_curve_to:
if (has_current) {
status = (*cb->AddSpline) (closure, &current, &pt[0], &pt[1], &pt[2]);
if (status)
return status;
current = pt[2];
has_edge = 1;
} else {
first = pt[2];
current = pt[2];
has_current = 1;
has_edge = 0;
}
break;
case cairo_path_op_close_path:
if (has_edge) {
(*cb->AddEdge) (closure, &current, &first);
(*cb->DoneSubPath) (closure, cairo_sub_path_done_join);
}
current.x = 0;
current.y = 0;
first.x = 0;
first.y = 0;
has_current = 0;
has_edge = 0;
break;
}
}
}
if (has_edge)
(*cb->DoneSubPath) (closure, cairo_sub_path_done_cap);
return (*cb->DonePath) (closure);
}

398
src/cairo-pen.c Normal file
View file

@ -0,0 +1,398 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
static int
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix);
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen);
static int
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
static int
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
static int
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b);
static cairo_status_t
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_pen_stroke_direction_t dir, cairo_polygon_t *polygon);
cairo_status_t
_cairo_pen_init_empty (cairo_pen_t *pen)
{
pen->radius = 0;
pen->tolerance = 0;
pen->vertex = NULL;
pen->num_vertices = 0;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
{
int i;
cairo_pen_vertex *v;
double dx, dy;
if (pen->num_vertices) {
/* XXX: It would be nice to notice that the pen is already properly constructed.
However, this test would also have to account for possible changes in the transformation
matrix.
if (pen->radius == radius && pen->tolerance == tolerance)
return CAIRO_STATUS_SUCCESS;
*/
_cairo_pen_fini (pen);
}
pen->radius = radius;
pen->tolerance = gstate->tolerance;
pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, &gstate->ctm);
/* number of vertices must be even */
if (pen->num_vertices % 2)
pen->num_vertices++;
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
if (pen->vertex == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
for (i=0; i < pen->num_vertices; i++) {
v = &pen->vertex[i];
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
dx = radius * cos (v->theta);
dy = radius * sin (v->theta);
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
v->pt.x = XDoubleToFixed (dx);
v->pt.y = XDoubleToFixed (dy);
/* Recompute theta in device space */
v->theta = atan2 (v->pt.y, v->pt.x);
if (v->theta < 0)
v->theta += 2 * M_PI;
}
_cairo_pen_compute_slopes (pen);
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_pen_fini (cairo_pen_t *pen)
{
free (pen->vertex);
_cairo_pen_init_empty (pen);
}
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
*pen = *other;
if (pen->num_vertices) {
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
if (pen->vertex == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
memcpy (pen->vertex, other->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
}
return CAIRO_STATUS_SUCCESS;
}
static int
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b)
{
double diff;
const cairo_pen_vertex *va = a;
const cairo_pen_vertex *vb = b;
diff = va->theta - vb->theta;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
else
return 0;
}
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, XPointFixed *pt, int num_pts)
{
int i, j;
cairo_pen_vertex *v, *v_next, *new_vertex;
pen->num_vertices += num_pts;
new_vertex = realloc (pen->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
if (new_vertex == NULL) {
pen->num_vertices -= num_pts;
return CAIRO_STATUS_NO_MEMORY;
}
pen->vertex = new_vertex;
/* initialize new vertices */
for (i=0; i < num_pts; i++) {
v = &pen->vertex[pen->num_vertices-(i+1)];
v->pt = pt[i];
v->theta = atan2 (v->pt.y, v->pt.x);
if (v->theta < 0)
v->theta += 2 * M_PI;
}
qsort (pen->vertex, pen->num_vertices, sizeof (cairo_pen_vertex), _cairo_pen_vertex_compare_by_theta);
/* eliminate any duplicate vertices */
for (i=0; i < pen->num_vertices - 1; i++ ) {
v = &pen->vertex[i];
v_next = &pen->vertex[i+1];
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
for (j=i+1; j < pen->num_vertices - 1; j++)
pen->vertex[j] = pen->vertex[j+1];
pen->num_vertices--;
/* There may be more of the same duplicate, check again */
i--;
}
}
_cairo_pen_compute_slopes (pen);
return CAIRO_STATUS_SUCCESS;
}
static int
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix)
{
double expansion, theta;
/* The determinant represents the area expansion factor of the
transform. In the worst case, this is entirely in one
dimension, which is what we assume here. */
_cairo_matrix_compute_determinant (matrix, &expansion);
if (tolerance > expansion*radius) {
return 4;
}
theta = acos (1 - tolerance/(expansion * radius));
return ceil (M_PI / theta);
}
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen)
{
int i, i_prev;
cairo_pen_vertex *prev, *v, *next;
for (i=0, i_prev = pen->num_vertices - 1;
i < pen->num_vertices;
i_prev = i++) {
prev = &pen->vertex[i_prev];
v = &pen->vertex[i];
next = &pen->vertex[(i + 1) % pen->num_vertices];
_compute_slope (&prev->pt, &v->pt, &v->slope_cw);
_compute_slope (&v->pt, &next->pt, &v->slope_ccw);
}
}
/* Is a clockwise of b?
*
* NOTE: The strict equality here is not significant in and of itself,
* but there are functions up above that are sensitive to it,
* (cf. _cairo_pen_find_active_cw_vertex_index).
*/
static int
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
{
double a_dx = XFixedToDouble (a->dx);
double a_dy = XFixedToDouble (a->dy);
double b_dx = XFixedToDouble (b->dx);
double b_dy = XFixedToDouble (b->dy);
return b_dy * a_dx > a_dy * b_dx;
}
static int
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
{
return ! _slope_clockwise (a, b);
}
/* Find active pen vertex for clockwise edge of stroke at the given slope.
*
* NOTE: The behavior of this function is sensitive to the sense of
* the inequality within _slope_clockwise/_slope_counter_clockwise.
*
* The issue is that the slope_ccw member of one pen vertex will be
* equivalent to the slope_cw member of the next pen vertex in a
* counterclockwise order. However, for this function, we care
* strongly about which vertex is returned.
*/
cairo_status_t
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
cairo_slope_fixed_t *slope,
int *active)
{
int i;
for (i=0; i < pen->num_vertices; i++) {
if (_slope_clockwise (slope, &pen->vertex[i].slope_ccw)
&& _slope_counter_clockwise (slope, &pen->vertex[i].slope_cw))
break;
}
*active = i;
return CAIRO_STATUS_SUCCESS;
}
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
*
* NOTE: The behavior of this function is sensitive to the sense of
* the inequality within _slope_clockwise/_slope_counter_clockwise.
*/
cairo_status_t
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
cairo_slope_fixed_t *slope,
int *active)
{
int i;
cairo_slope_fixed_t slope_reverse;
slope_reverse = *slope;
slope_reverse.dx = -slope_reverse.dx;
slope_reverse.dy = -slope_reverse.dy;
for (i=pen->num_vertices-1; i >= 0; i--) {
if (_slope_counter_clockwise (&pen->vertex[i].slope_ccw, &slope_reverse)
&& _slope_clockwise (&pen->vertex[i].slope_cw, &slope_reverse))
break;
}
*active = i;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
cairo_spline_t *spline,
cairo_pen_stroke_direction_t dir,
cairo_polygon_t *polygon)
{
int i;
cairo_status_t status;
int start, stop, step;
int active = 0;
XPointFixed hull_pt;
cairo_slope_fixed_t slope, initial_slope, final_slope;
XPointFixed *pt = spline->pts;
int num_pts = spline->num_pts;
if (dir == cairo_pen_stroke_direction_forward) {
start = 0;
stop = num_pts;
step = 1;
initial_slope = spline->initial_slope;
final_slope = spline->final_slope;
} else {
start = num_pts - 1;
stop = -1;
step = -1;
initial_slope = spline->final_slope;
initial_slope.dx = -initial_slope.dx;
initial_slope.dy = -initial_slope.dy;
final_slope = spline->initial_slope;
final_slope.dx = -final_slope.dx;
final_slope.dy = -final_slope.dy;
}
_cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);
i = start;
while (i != stop) {
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
hull_pt.y = pt[i].y + pen->vertex[active].pt.y;
status = _cairo_polygon_add_point (polygon, &hull_pt);
if (status)
return status;
if (i + step == stop)
slope = final_slope;
else
_compute_slope (&pt[i], &pt[i+step], &slope);
if (_slope_counter_clockwise (&slope, &pen->vertex[active].slope_ccw)) {
if (++active == pen->num_vertices)
active = 0;
} else if (_slope_clockwise (&slope, &pen->vertex[active].slope_cw)) {
if (--active == -1)
active = pen->num_vertices - 1;
} else {
i += step;
}
}
return CAIRO_STATUS_SUCCESS;
}
/* Compute outline of a given spline using the pen.
The trapezoids needed to fill that outline will be added to traps
*/
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t *pen,
cairo_spline_t *spline,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_polygon_t polygon;
_cairo_polygon_init (&polygon);
status = _cairo_spline_decompose (spline, tolerance);
if (status)
return status;
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_forward, &polygon);
if (status)
return status;
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_reverse, &polygon);
if (status)
return status;
_cairo_polygon_close (&polygon);
cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
return CAIRO_STATUS_SUCCESS;
}

175
src/cairo-polygon.c Normal file
View file

@ -0,0 +1,175 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include "cairoint.h"
#define CAIRO_POLYGON_GROWTH_INC 10
/* private functions */
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
static void
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt);
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
polygon->num_edges = 0;
polygon->edges_size = 0;
polygon->edges = NULL;
polygon->first_pt_defined = 0;
polygon->last_pt_defined = 0;
polygon->closed = 0;
}
void
_cairo_polygon_fini (cairo_polygon_t *polygon)
{
if (polygon->edges_size) {
free (polygon->edges);
polygon->edges = NULL;
polygon->edges_size = 0;
polygon->num_edges = 0;
}
polygon->first_pt_defined = 0;
polygon->last_pt_defined = 0;
polygon->closed = 0;
}
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int new_size = polygon->num_edges + additional;
if (new_size <= polygon->edges_size) {
return CAIRO_STATUS_SUCCESS;
}
polygon->edges_size = new_size;
new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t));
if (new_edges == NULL) {
polygon->edges_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
polygon->edges = new_edges;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt)
{
polygon->last_pt = *pt;
polygon->last_pt_defined = 1;
}
cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, XPointFixed *p1, XPointFixed *p2)
{
cairo_status_t status;
cairo_edge_t *edge;
if (! polygon->first_pt_defined) {
polygon->first_pt = *p1;
polygon->first_pt_defined = 1;
polygon->closed = 0;
}
/* drop horizontal edges */
if (p1->y == p2->y) {
goto DONE;
}
if (polygon->num_edges >= polygon->edges_size) {
status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
if (status) {
return status;
}
}
edge = &polygon->edges[polygon->num_edges];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
edge->clockWise = True;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
edge->clockWise = False;
}
polygon->num_edges++;
DONE:
_cairo_polygon_set_last_point (polygon, p2);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_polygon_add_point (cairo_polygon_t *polygon, XPointFixed *pt)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (polygon->last_pt_defined) {
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, pt);
} else {
_cairo_polygon_set_last_point (polygon, pt);
}
return status;
}
cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon)
{
cairo_status_t status;
if (polygon->closed == 0 && polygon->last_pt_defined) {
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, &polygon->first_pt);
if (status)
return status;
polygon->closed = 1;
polygon->first_pt_defined = 0;
}
return CAIRO_STATUS_SUCCESS;
}

271
src/cairo-spline.c Normal file
View file

@ -0,0 +1,271 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
static cairo_status_t
_cairo_spline_grow_by (cairo_spline_t *spline, int additional);
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt);
static void
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result);
static void
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2);
static double
_cairo_spline_error_squared (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
#define CAIRO_SPLINE_GROWTH_INC 100
cairo_int_status
_cairo_spline_init (cairo_spline_t *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
spline->a = *a;
spline->b = *b;
spline->c = *c;
spline->d = *d;
if (a->x != b->x || a->y != b->y) {
_compute_slope (&spline->a, &spline->b, &spline->initial_slope);
} else if (a->x != c->x || a->y != c->y) {
_compute_slope (&spline->a, &spline->c, &spline->initial_slope);
} else if (a->x != d->x || a->y != d->y) {
_compute_slope (&spline->a, &spline->d, &spline->initial_slope);
} else {
return cairo_int_status_degenerate;
}
if (c->x != d->x || c->y != d->y) {
_compute_slope (&spline->c, &spline->d, &spline->final_slope);
} else if (b->x != d->x || b->y != d->y) {
_compute_slope (&spline->b, &spline->d, &spline->final_slope);
} else {
_compute_slope (&spline->a, &spline->d, &spline->final_slope);
}
spline->num_pts = 0;
spline->pts_size = 0;
spline->pts = NULL;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_spline_fini (cairo_spline_t *spline)
{
spline->num_pts = 0;
spline->pts_size = 0;
free (spline->pts);
spline->pts = NULL;
}
static cairo_status_t
_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
{
XPointFixed *new_pts;
int old_size = spline->pts_size;
int new_size = spline->num_pts + additional;
if (new_size <= spline->pts_size)
return CAIRO_STATUS_SUCCESS;
spline->pts_size = new_size;
new_pts = realloc (spline->pts, spline->pts_size * sizeof (XPointFixed));
if (new_pts == NULL) {
spline->pts_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
spline->pts = new_pts;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt)
{
cairo_status_t status;
if (spline->num_pts >= spline->pts_size) {
status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
if (status)
return status;
}
spline->pts[spline->num_pts] = *pt;
spline->num_pts++;
return CAIRO_STATUS_SUCCESS;
}
static void
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result)
{
result->x = a->x + ((b->x - a->x) >> 1);
result->y = a->y + ((b->y - a->y) >> 1);
}
static void
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2)
{
XPointFixed ab, bc, cd;
XPointFixed abbc, bccd;
XPointFixed final;
_lerp_half (&spline->a, &spline->b, &ab);
_lerp_half (&spline->b, &spline->c, &bc);
_lerp_half (&spline->c, &spline->d, &cd);
_lerp_half (&ab, &bc, &abbc);
_lerp_half (&bc, &cd, &bccd);
_lerp_half (&abbc, &bccd, &final);
s1->a = spline->a;
s1->b = ab;
s1->c = abbc;
s1->d = final;
s2->a = final;
s2->b = bccd;
s2->c = cd;
s2->d = spline->d;
}
static double
_PointDistanceSquaredToPoint (XPointFixed *a, XPointFixed *b)
{
double dx = XFixedToDouble (b->x - a->x);
double dy = XFixedToDouble (b->y - a->y);
return dx*dx + dy*dy;
}
static double
_PointDistanceSquaredToSegment (XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
{
double u;
double dx, dy;
double pdx, pdy;
XPointFixed px;
/* intersection point (px):
px = p1 + u(p2 - p1)
(p - px) . (p2 - p1) = 0
Thus:
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
*/
dx = XFixedToDouble (p2->x - p1->x);
dy = XFixedToDouble (p2->y - p1->y);
if (dx == 0 && dy == 0)
return _PointDistanceSquaredToPoint (p, p1);
pdx = XFixedToDouble (p->x - p1->x);
pdy = XFixedToDouble (p->y - p1->y);
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
if (u <= 0)
return _PointDistanceSquaredToPoint (p, p1);
else if (u >= 1)
return _PointDistanceSquaredToPoint (p, p2);
px.x = p1->x + u * (p2->x - p1->x);
px.y = p1->y + u * (p2->y - p1->y);
return _PointDistanceSquaredToPoint (p, &px);
}
/* Return an upper bound on the error (squared) that could result from approximating
a spline as a line segment connecting the two endpoints */
static double
_cairo_spline_error_squared (cairo_spline_t *spline)
{
double berr, cerr;
berr = _PointDistanceSquaredToSegment (&spline->b, &spline->a, &spline->d);
cerr = _PointDistanceSquaredToSegment (&spline->c, &spline->a, &spline->d);
if (berr > cerr)
return berr;
else
return cerr;
}
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result)
{
cairo_status_t status;
cairo_spline_t s1, s2;
if (_cairo_spline_error_squared (spline) < tolerance_squared) {
return _cairo_spline_add_point (result, &spline->a);
}
_de_casteljau (spline, &s1, &s2);
status = _cairo_spline_decompose_into (&s1, tolerance_squared, result);
if (status)
return status;
status = _cairo_spline_decompose_into (&s2, tolerance_squared, result);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
{
cairo_status_t status;
if (spline->pts_size) {
_cairo_spline_fini (spline);
}
status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline);
if (status)
return status;
status = _cairo_spline_add_point (spline, &spline->d);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}

391
src/cairo-surface.c Normal file
View file

@ -0,0 +1,391 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include "cairoint.h"
cairo_surface_t *
cairo_surface_create_for_drawable (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL)
return NULL;
surface->dpy = dpy;
surface->image_data = NULL;
surface->xc_surface = XcSurfaceCreateForDrawable (dpy, drawable, visual, format, colormap);
if (surface->xc_surface == NULL) {
free (surface);
return NULL;
}
/* XXX: We should really get this value from somewhere like Xft.dpy */
surface->ppm = 3780;
surface->ref_count = 1;
return surface;
}
/* XXX: These definitions are 100% bogus. The problem that needs to be
fixed is that Ic needs to export a real API for passing in
formats. */
#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
((type) << 16) | \
((a) << 12) | \
((r) << 8) | \
((g) << 4) | \
((b)))
/*
* gray/color formats use a visual index instead of argb
*/
#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \
((type) << 16) | \
((vi)))
#define PICT_TYPE_A 1
#define PICT_TYPE_ARGB 2
#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2)
/* 32bpp formats */
#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8)
#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8)
#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0)
#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0)
static int
cairo_format_bpp (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_A1:
return 1;
break;
case CAIRO_FORMAT_A8:
return 8;
break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_ARGB32:
default:
return 32;
break;
}
}
cairo_surface_t *
cairo_surface_create_for_image (char *data,
cairo_format_t format,
int width,
int height,
int stride)
{
cairo_surface_t *surface;
IcFormat icformat;
IcImage *image;
int bpp;
/* XXX: This all needs to change, (but IcFormatInit interface needs to change first) */
switch (format) {
case CAIRO_FORMAT_ARGB32:
IcFormatInit (&icformat, PICT_a8r8g8b8);
bpp = 32;
break;
case CAIRO_FORMAT_RGB24:
IcFormatInit (&icformat, PICT_x8r8g8b8);
bpp = 32;
break;
case CAIRO_FORMAT_A8:
IcFormatInit (&icformat, PICT_a8);
bpp = 8;
break;
case CAIRO_FORMAT_A1:
IcFormatInit (&icformat, PICT_a1);
bpp = 1;
break;
default:
return NULL;
}
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL)
return NULL;
surface->dpy = NULL;
surface->image_data = NULL;
image = IcImageCreateForData ((IcBits *) data, &icformat, width, height, cairo_format_bpp (format), stride);
if (image == NULL) {
free (surface);
return NULL;
}
surface->xc_surface = XcSurfaceCreateForIcImage (image);
if (surface->xc_surface == NULL) {
IcImageDestroy (image);
free (surface);
return NULL;
}
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
return surface;
}
cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
int width,
int height)
{
return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
}
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_A1:
return 1;
case CAIRO_FORMAT_A8:
return 8;
case CAIRO_FORMAT_RGB24:
return 24;
case CAIRO_FORMAT_ARGB32:
default:
return 32;
}
}
cairo_surface_t *
cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
int width,
int height,
double red,
double green,
double blue,
double alpha)
{
cairo_surface_t *surface = NULL;
cairo_color_t color;
/* XXX: create_similar should perhaps move down to Xc, (then we
could drop xrsurface->dpy as well) */
if (other->dpy) {
Display *dpy = other->dpy;
int scr = DefaultScreen (dpy);
Pixmap pix = XCreatePixmap (dpy,
DefaultRootWindow (dpy),
width, height,
_CAIRO_FORMAT_DEPTH (format));
surface = cairo_surface_create_for_drawable (dpy, pix,
NULL,
format,
DefaultColormap (dpy, scr));
/* XXX: huh? This should be fine since we already created a picture
from the pixmap, right?? (Somehow, it seems to be causing some
breakage).
XFreePixmap (surface->dpy, pix);
*/
} else {
char *data;
int stride;
stride = ((width * cairo_format_bpp (format)) + 7) >> 3;
data = malloc (stride * height);
if (data == NULL)
return NULL;
surface = cairo_surface_create_for_image (data, format,
width, height, stride);
/* lodge data in the surface structure to be freed with the surface */
surface->image_data = data;
}
/* XXX: Initializing the color in this way assumes
non-pre-multiplied alpha. I'm not sure that that's what I want
to do or not. */
_cairo_color_init (&color);
_cairo_color_set_rgb (&color, red, green, blue);
_cairo_color_set_alpha (&color, alpha);
_cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SRC, &color, 0, 0, width, height);
return surface;
}
void
_cairo_surface_reference (cairo_surface_t *surface)
{
if (surface == NULL)
return;
surface->ref_count++;
}
void
cairo_surface_destroy (cairo_surface_t *surface)
{
if (surface == NULL)
return;
surface->ref_count--;
if (surface->ref_count)
return;
surface->dpy = 0;
XcSurfaceDestroy (surface->xc_surface);
surface->xc_surface = NULL;
if (surface->image_data)
free (surface->image_data);
surface->image_data = NULL;
free (surface);
}
cairo_status_t
cairo_surface_put_image (cairo_surface_t *surface,
char *data,
int width,
int height,
int stride)
{
XcSurfacePutImage (surface->xc_surface, data,
width, height, stride);
return CAIRO_STATUS_SUCCESS;
}
/* XXX: Symmetry demands an cairo_surface_get_image as well */
/* XXX: We may want to move to projective matrices at some point. If
nothing else, that would eliminate the two different transform data
structures we have here. */
cairo_status_t
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
{
XTransform xtransform;
xtransform.matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
xtransform.matrix[0][1] = XDoubleToFixed (matrix->m[1][0]);
xtransform.matrix[0][2] = XDoubleToFixed (matrix->m[2][0]);
xtransform.matrix[1][0] = XDoubleToFixed (matrix->m[0][1]);
xtransform.matrix[1][1] = XDoubleToFixed (matrix->m[1][1]);
xtransform.matrix[1][2] = XDoubleToFixed (matrix->m[2][1]);
xtransform.matrix[2][0] = 0;
xtransform.matrix[2][1] = 0;
xtransform.matrix[2][2] = XDoubleToFixed (1);
XcSurfaceSetTransform (surface->xc_surface,
&xtransform);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
{
XTransform xtransform;
XcSurfaceGetTransform (surface->xc_surface, &xtransform);
matrix->m[0][0] = XFixedToDouble (xtransform.matrix[0][0]);
matrix->m[1][0] = XFixedToDouble (xtransform.matrix[0][1]);
matrix->m[2][0] = XFixedToDouble (xtransform.matrix[0][2]);
matrix->m[0][1] = XFixedToDouble (xtransform.matrix[1][0]);
matrix->m[1][1] = XFixedToDouble (xtransform.matrix[1][1]);
matrix->m[2][1] = XFixedToDouble (xtransform.matrix[1][2]);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
{
XcSurfaceSetFilter (surface->xc_surface, filter);
return CAIRO_STATUS_SUCCESS;
}
/* XXX: The Xc version of this function isn't quite working yet
cairo_status_t
cairo_surface_set_clip_region (cairo_surface_t *surface, Region region)
{
XcSurfaceSetClipRegion (surface->xc_surface, region);
return CAIRO_STATUS_SUCCESS;
}
*/
cairo_status_t
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
{
XcSurfaceSetRepeat (surface->xc_surface, repeat);
return CAIRO_STATUS_SUCCESS;
}
/* XXX: This function is going away, right? */
Picture
_cairo_surface_get_picture (cairo_surface_t *surface)
{
return XcSurfaceGetPicture (surface->xc_surface);
}
void
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
cairo_color_t *color,
int x,
int y,
int width,
int height)
{
XcFillRectangle (operator,
surface->xc_surface,
&color->xc_color,
x, y,
width, height);
}

View file

@ -1,6 +1,4 @@
/*
* $XFree86: $
*
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
@ -21,47 +19,47 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* 2002-07-15: Converted from XRenderCompositeDoublePoly to XrTrap. Carl D. Worth
* 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
*/
#include "xrint.h"
#include "cairoint.h"
#define XR_TRAPS_GROWTH_INC 10
#define CAIRO_TRAPS_GROWTH_INC 10
/* private functions */
static XrStatus
_XrTrapsGrowBy(XrTraps *traps, int additional);
static cairo_status_t
cairo_traps_grow_by (cairo_traps_t *traps, int additional);
XrStatus
_XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
XLineFixed left, XLineFixed right);
cairo_status_t
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
XLineFixed left, XLineFixed right);
XrStatus
_XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
XPointFixed left_p1, XPointFixed left_p2,
XPointFixed right_p1, XPointFixed right_p2);
cairo_status_t
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
XPointFixed left_p1, XPointFixed left_p2,
XPointFixed right_p1, XPointFixed right_p2);
static int
_ComparePointFixedByY (const void *av, const void *bv);
_compare_point_fixed_by_y (const void *av, const void *bv);
static int
_CompareXrEdgeByTop (const void *av, const void *bv);
_compare_cairo_edge_by_top (const void *av, const void *bv);
static XFixed
_ComputeX (XLineFixed *line, XFixed y);
_compute_x (XLineFixed *line, XFixed y);
static double
_ComputeInverseSlope (XLineFixed *l);
_compute_inverse_slope (XLineFixed *l);
static double
_ComputeXIntercept (XLineFixed *l, double inverse_slope);
_compute_x_intercept (XLineFixed *l, double inverse_slope);
static XFixed
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
void
_XrTrapsInit(XrTraps *traps)
cairo_traps_init (cairo_traps_t *traps)
{
traps->num_xtraps = 0;
@ -70,29 +68,29 @@ _XrTrapsInit(XrTraps *traps)
}
void
_XrTrapsDeinit(XrTraps *traps)
cairo_traps_fini (cairo_traps_t *traps)
{
if (traps->xtraps_size) {
free(traps->xtraps);
free (traps->xtraps);
traps->xtraps = NULL;
traps->xtraps_size = 0;
traps->num_xtraps = 0;
}
}
XrStatus
_XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
XLineFixed left, XLineFixed right)
cairo_status_t
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
XLineFixed left, XLineFixed right)
{
XrStatus status;
cairo_status_t status;
XTrapezoid *trap;
if (top == bottom) {
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}
if (traps->num_xtraps >= traps->xtraps_size) {
status = _XrTrapsGrowBy(traps, XR_TRAPS_GROWTH_INC);
status = cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC);
if (status)
return status;
}
@ -105,13 +103,13 @@ _XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
traps->num_xtraps++;
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}
XrStatus
_XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
XPointFixed left_p1, XPointFixed left_p2,
XPointFixed right_p1, XPointFixed right_p2)
cairo_status_t
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
XPointFixed left_p1, XPointFixed left_p2,
XPointFixed right_p1, XPointFixed right_p2)
{
XLineFixed left;
XLineFixed right;
@ -122,35 +120,35 @@ _XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
right.p1 = right_p1;
right.p2 = right_p2;
return _XrTrapsAddTrap(traps, top, bottom, left, right);
return cairo_traps_add_trap (traps, top, bottom, left, right);
}
static XrStatus
_XrTrapsGrowBy(XrTraps *traps, int additional)
static cairo_status_t
cairo_traps_grow_by (cairo_traps_t *traps, int additional)
{
XTrapezoid *new_xtraps;
int old_size = traps->xtraps_size;
int new_size = traps->num_xtraps + additional;
if (new_size <= traps->xtraps_size) {
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}
traps->xtraps_size = new_size;
new_xtraps = realloc(traps->xtraps, traps->xtraps_size * sizeof(XTrapezoid));
new_xtraps = realloc (traps->xtraps, traps->xtraps_size * sizeof (XTrapezoid));
if (new_xtraps == NULL) {
traps->xtraps_size = old_size;
return XrStatusNoMemory;
return CAIRO_STATUS_NO_MEMORY;
}
traps->xtraps = new_xtraps;
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}
static int
_ComparePointFixedByY (const void *av, const void *bv)
_compare_point_fixed_by_y (const void *av, const void *bv)
{
const XPointFixed *a = av, *b = bv;
@ -161,105 +159,111 @@ _ComparePointFixedByY (const void *av, const void *bv)
return ret;
}
XrStatus
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
cairo_status_t
cairo_traps_tessellate_triangle (cairo_traps_t *traps, XPointFixed t[3])
{
XrStatus status;
cairo_status_t status;
XLineFixed line;
double intersect;
XPointFixed tsort[3];
memcpy(tsort, t, 3 * sizeof(XPointFixed));
qsort(tsort, 3, sizeof(XPointFixed), _ComparePointFixedByY);
memcpy (tsort, t, 3 * sizeof (XPointFixed));
qsort (tsort, 3, sizeof (XPointFixed), _compare_point_fixed_by_y);
/* horizontal top edge requires special handling */
if (tsort[0].y == tsort[1].y) {
if (tsort[0].x < tsort[1].x)
status = _XrTrapsAddTrapFromPoints (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
else
status = _XrTrapsAddTrapFromPoints (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
return status;
}
line.p1 = tsort[0];
line.p2 = tsort[1];
intersect = _ComputeX (&line, tsort[2].y);
intersect = _compute_x (&line, tsort[2].y);
if (intersect < tsort[2].x) {
status = _XrTrapsAddTrapFromPoints(traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[1],
tsort[0], tsort[2]);
status = cairo_traps_add_trap_from_points (traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[1],
tsort[0], tsort[2]);
if (status)
return status;
status = _XrTrapsAddTrapFromPoints(traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
if (status)
return status;
} else {
status = _XrTrapsAddTrapFromPoints(traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[2],
tsort[0], tsort[1]);
status = cairo_traps_add_trap_from_points (traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[2],
tsort[0], tsort[1]);
if (status)
return status;
status = _XrTrapsAddTrapFromPoints(traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
if (status)
return status;
}
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}
/* Warning: This function reorders the elements of the array provided. */
XrStatus
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
cairo_status_t
cairo_traps_tessellate_rectangle (cairo_traps_t *traps, XPointFixed q[4])
{
XrStatus status;
cairo_status_t status;
qsort(q, 4, sizeof(XPointFixed), _ComparePointFixedByY);
qsort (q, 4, sizeof (XPointFixed), _compare_point_fixed_by_y);
if (q[1].x > q[2].x) {
status = _XrTrapsAddTrapFromPoints(traps, q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
status = cairo_traps_add_trap_from_points (traps,
q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
if (status)
return status;
status = _XrTrapsAddTrapFromPoints(traps, q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
status = cairo_traps_add_trap_from_points (traps,
q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
if (status)
return status;
status = _XrTrapsAddTrapFromPoints(traps, q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
status = cairo_traps_add_trap_from_points (traps,
q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
if (status)
return status;
} else {
status = _XrTrapsAddTrapFromPoints(traps, q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
status = cairo_traps_add_trap_from_points (traps,
q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
if (status)
return status;
status = _XrTrapsAddTrapFromPoints(traps, q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
status = cairo_traps_add_trap_from_points (traps,
q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
if (status)
return status;
status = _XrTrapsAddTrapFromPoints(traps, q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
status = cairo_traps_add_trap_from_points (traps,
q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
if (status)
return status;
}
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}
static int
_CompareXrEdgeByTop (const void *av, const void *bv)
_compare_cairo_edge_by_top (const void *av, const void *bv)
{
const XrEdge *a = av, *b = bv;
const cairo_edge_t *a = av, *b = bv;
int ret;
ret = a->edge.p1.y - b->edge.p1.y;
@ -270,35 +274,35 @@ _CompareXrEdgeByTop (const void *av, const void *bv)
/* Return value is:
> 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
== 0 if slope(a) == slope(b)
== 0 if slope (a) == slope (b)
< 0 if a is "counter-clockwise" from b
*/
static int
_CompareXrEdgeBySlope (const void *av, const void *bv)
_compare_cairo_edge_by_slope (const void *av, const void *bv)
{
const XrEdge *a = av, *b = bv;
const cairo_edge_t *a = av, *b = bv;
double a_dx = XFixedToDouble(a->edge.p2.x - a->edge.p1.x);
double a_dy = XFixedToDouble(a->edge.p2.y - a->edge.p1.y);
double b_dx = XFixedToDouble(b->edge.p2.x - b->edge.p1.x);
double b_dy = XFixedToDouble(b->edge.p2.y - b->edge.p1.y);
double a_dx = XFixedToDouble (a->edge.p2.x - a->edge.p1.x);
double a_dy = XFixedToDouble (a->edge.p2.y - a->edge.p1.y);
double b_dx = XFixedToDouble (b->edge.p2.x - b->edge.p1.x);
double b_dy = XFixedToDouble (b->edge.p2.y - b->edge.p1.y);
return b_dy * a_dx - a_dy * b_dx;
}
static int
_CompareXrEdgeByCurrentXThenSlope (const void *av, const void *bv)
_compare_cairo_edge_by_current_xthen_slope (const void *av, const void *bv)
{
const XrEdge *a = av, *b = bv;
const cairo_edge_t *a = av, *b = bv;
int ret;
ret = a->current_x - b->current_x;
if (ret == 0)
ret = _CompareXrEdgeBySlope(a, b);
ret = _compare_cairo_edge_by_slope (a, b);
return ret;
}
/* XXX: Both _ComputeX and _ComputeInverseSlope will divide by zero
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
for horizontal lines. Now, we "know" that when we are tessellating
polygons that the polygon data structure discards all horizontal
edges, but there's nothing here to guarantee that. I suggest the
@ -324,34 +328,34 @@ _det (double a, double b, double c, double d)
}
static int
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
{
double dx1 = XFixedToDouble(l1->p1.x - l1->p2.x);
double dy1 = XFixedToDouble(l1->p1.y - l1->p2.y);
double dx1 = XFixedToDouble (l1->p1.x - l1->p2.x);
double dy1 = XFixedToDouble (l1->p1.y - l1->p2.y);
double dx2 = XFixedToDouble(l2->p1.x - l2->p2.x);
double dy2 = XFixedToDouble(l2->p1.y - l2->p2.y);
double dx2 = XFixedToDouble (l2->p1.x - l2->p2.x);
double dy2 = XFixedToDouble (l2->p1.y - l2->p2.y);
double l1_det, l2_det;
double den_det = _det(dx1, dy1, dx2, dy2);
double den_det = _det (dx1, dy1, dx2, dy2);
if (den_det == 0)
return 0;
l1_det = _det(l1->p1.x, l1->p1.y,
l1_det = _det (l1->p1.x, l1->p1.y,
l1->p2.x, l1->p2.y);
l2_det = _det(l2->p1.x, l2->p1.y,
l2_det = _det (l2->p1.x, l2->p1.y,
l2->p2.x, l2->p2.y);
*y_intersection = _det(l1_det, dy1,
*y_intersection = _det (l1_det, dy1,
l2_det, dy2) / den_det;
return 1;
}
*/
static XFixed
_ComputeX (XLineFixed *line, XFixed y)
_compute_x (XLineFixed *line, XFixed y)
{
XFixed dx = line->p2.x - line->p1.x;
double ex = (double) (y - line->p1.y) * (double) dx;
@ -361,20 +365,20 @@ _ComputeX (XLineFixed *line, XFixed y)
}
static double
_ComputeInverseSlope (XLineFixed *l)
_compute_inverse_slope (XLineFixed *l)
{
return (XFixedToDouble (l->p2.x - l->p1.x) /
XFixedToDouble (l->p2.y - l->p1.y));
}
static double
_ComputeXIntercept (XLineFixed *l, double inverse_slope)
_compute_x_intercept (XLineFixed *l, double inverse_slope)
{
return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y);
}
static int
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
{
/*
* x = m1y + b1
@ -383,10 +387,10 @@ _LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
* y * (m1 - m2) = b2 - b1
* y = (b2 - b1) / (m1 - m2)
*/
double m1 = _ComputeInverseSlope (l1);
double b1 = _ComputeXIntercept (l1, m1);
double m2 = _ComputeInverseSlope (l2);
double b2 = _ComputeXIntercept (l2, m2);
double m1 = _compute_inverse_slope (l1);
double b1 = _compute_x_intercept (l1, m1);
double m2 = _compute_inverse_slope (l2);
double b2 = _compute_x_intercept (l2, m2);
if (m1 == m2)
return 0;
@ -396,9 +400,9 @@ _LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
}
static void
_SortEdgeList(XrEdge **active)
_SortEdgeList (cairo_edge_t **active)
{
XrEdge *e, *en, *next;
cairo_edge_t *e, *en, *next;
/* sort active list */
for (e = *active; e; e = next)
@ -410,7 +414,7 @@ _SortEdgeList(XrEdge **active)
*/
for (en = next; en; en = en->next)
{
if (_CompareXrEdgeByCurrentXThenSlope(e, en) > 0)
if (_compare_cairo_edge_by_current_xthen_slope (e, en) > 0)
{
/*
* insert en before e
@ -443,14 +447,14 @@ _SortEdgeList(XrEdge **active)
/* The algorithm here is pretty simple:
inactive = [edges]
y = min_p1_y(inactive)
y = min_p1_y (inactive)
while (num_active || num_inactive) {
active = all edges containing y
next_y = min( min_p2_y(active), min_p1_y(inactive), min_intersection(active) )
next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )
fill_traps(active, y, next_y, fill_rule)
fill_traps (active, y, next_y, fill_rule)
y = next_y
}
@ -467,23 +471,23 @@ _SortEdgeList(XrEdge **active)
Warning: This function reorders the edges of the polygon provided.
*/
XrStatus
_XrTrapsTessellatePolygon (XrTraps *traps,
XrPolygon *poly,
XrFillRule fill_rule)
cairo_status_t
cairo_traps_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule)
{
XrStatus status;
cairo_status_t status;
int inactive;
XrEdge *active;
XrEdge *e, *en, *next;
cairo_edge_t *active;
cairo_edge_t *e, *en, *next;
XFixed y, next_y, intersect;
int in_out, num_edges = poly->num_edges;
XrEdge *edges = poly->edges;
cairo_edge_t *edges = poly->edges;
if (num_edges == 0)
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
qsort (edges, num_edges, sizeof (XrEdge), _CompareXrEdgeByTop);
qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
y = edges[0].edge.p1.y;
active = 0;
@ -491,7 +495,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
while (active || inactive < num_edges)
{
for (e = active; e; e = e->next) {
e->current_x = _ComputeX (&e->edge, y);
e->current_x = _compute_x (&e->edge, y);
}
/* insert new active edges into list */
@ -502,7 +506,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
break;
/* move this edge into the active list */
inactive++;
e->current_x = _ComputeX (&e->edge, y);
e->current_x = _compute_x (&e->edge, y);
/* insert e at head of list */
e->next = active;
@ -512,7 +516,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
active = e;
}
_SortEdgeList(&active);
_SortEdgeList (&active);
/* find next inflection point */
if (active)
@ -528,12 +532,12 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
/* check intersect */
if (en && e->current_x != en->current_x)
{
if (_LinesIntersect (&e->edge, &en->edge, &intersect))
if (_lines_intersect (&e->edge, &en->edge, &intersect))
if (intersect > y) {
/* Need to guarantee that we get all the way past
the intersection point so that the edges sort
properly next time through the loop. */
if (_ComputeX(&e->edge, intersect) < _ComputeX(&en->edge, intersect))
if (_compute_x (&e->edge, intersect) < _compute_x (&en->edge, intersect))
intersect++;
if (intersect < next_y)
next_y = intersect;
@ -548,7 +552,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
in_out = 0;
for (e = active; e && (en = e->next); e = e->next)
{
if (fill_rule == XrFillRuleWinding) {
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
if (e->clockWise) {
in_out++;
} else {
@ -563,7 +567,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
continue;
}
}
status = _XrTrapsAddTrap(traps, y, next_y, e->edge, en->edge);
status = cairo_traps_add_trap (traps, y, next_y, e->edge, en->edge);
if (status)
return status;
}
@ -585,5 +589,5 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
y = next_y;
}
return XrStatusSuccess;
return CAIRO_STATUS_SUCCESS;
}

715
src/cairo.c Normal file
View file

@ -0,0 +1,715 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
static void
_cairo_restrict_value (double *value, double min, double max);
static void
_cairo_init (cairo_t *cr);
static void
_cairo_fini (cairo_t *cr);
cairo_t *
cairo_create (void)
{
cairo_t *cr;
cr = malloc (sizeof (cairo_t));
if (cr) {
_cairo_init (cr);
if (cr->status) {
free (cr);
return NULL;
}
}
return cr;
}
static void
_cairo_init (cairo_t *cr)
{
cr->gstate = NULL;
cr->status = CAIRO_STATUS_SUCCESS;
cairo_save (cr);
}
static void
_cairo_fini (cairo_t *cr)
{
while (cr->gstate) {
cairo_restore (cr);
}
}
void
cairo_destroy (cairo_t *cr)
{
_cairo_fini (cr);
free (cr);
}
void
cairo_save (cairo_t *cr)
{
cairo_gstate_t *top;
if (cr->status)
return;
if (cr->gstate) {
top = _cairo_gstate_clone (cr->gstate);
} else {
top = _cairo_gstate_create ();
}
if (top == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
top->next = cr->gstate;
cr->gstate = top;
}
void
cairo_restore (cairo_t *cr)
{
cairo_gstate_t *top;
if (cr->status)
return;
if (cr->gstate == NULL) {
cr->status = CAIRO_STATUS_INVALID_RESTORE;
return;
}
top = cr->gstate;
cr->gstate = top->next;
_cairo_gstate_destroy (top);
}
/* XXX: I want to rethink this API
void
cairo_push_group (cairo_t *cr)
{
if (cr->status)
return;
cr->status = cairoPush (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_begin_group (cr->gstate);
}
void
cairo_pop_group (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_end_group (cr->gstate);
if (cr->status)
return;
cr->status = cairoPop (cr);
}
*/
void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_target_surface (cr->gstate, surface);
}
cairo_surface_t *
cairo_get_target_surface (cairo_t *cr)
{
return _cairo_gstate_get_target_surface (cr->gstate);
}
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable)
{
cairo_surface_t *surface;
if (cr->status)
return;
surface = cairo_surface_create_for_drawable (dpy, drawable,
DefaultVisual (dpy, DefaultScreen (dpy)),
0,
DefaultColormap (dpy, DefaultScreen (dpy)));
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
cairo_surface_destroy (surface);
}
void
cairo_set_target_image (cairo_t *cr,
char *data,
cairo_format_t format,
int width,
int height,
int stride)
{
cairo_surface_t *surface;
if (cr->status)
return;
surface = cairo_surface_create_for_image (data,
format,
width, height, stride);
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
cairo_surface_destroy (surface);
}
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_operator (cr->gstate, op);
}
cairo_operator_t
cairo_get_operator (cairo_t *cr)
{
return _cairo_gstate_get_operator (cr->gstate);
}
void
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
{
if (cr->status)
return;
_cairo_restrict_value (&red, 0.0, 1.0);
_cairo_restrict_value (&green, 0.0, 1.0);
_cairo_restrict_value (&blue, 0.0, 1.0);
cr->status = _cairo_gstate_set_rgb_color (cr->gstate, red, green, blue);
}
void
cairo_get_rgb_color (cairo_t *cr, double *red, double *green, double *blue)
{
/* XXX: Should we do anything with the return values in the error case? */
if (cr->status)
return;
cr->status = _cairo_gstate_get_rgb_color (cr->gstate, red, green, blue);
}
void
cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern);
}
void
cairo_set_tolerance (cairo_t *cr, double tolerance)
{
if (cr->status)
return;
_cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance);
cr->status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
}
double
cairo_get_tolerance (cairo_t *cr)
{
return _cairo_gstate_get_tolerance (cr->gstate);
}
void
cairo_set_alpha (cairo_t *cr, double alpha)
{
if (cr->status)
return;
_cairo_restrict_value (&alpha, 0.0, 1.0);
cr->status = _cairo_gstate_set_alpha (cr->gstate, alpha);
}
double
cairo_get_alpha (cairo_t *cr)
{
return _cairo_gstate_get_alpha (cr->gstate);
}
void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
}
void
cairo_set_line_width (cairo_t *cr, double width)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_width (cr->gstate, width);
}
double
cairo_get_line_width (cairo_t *cr)
{
return _cairo_gstate_get_line_width (cr->gstate);
}
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
}
cairo_line_cap_t
cairo_get_line_cap (cairo_t *cr)
{
return _cairo_gstate_get_line_cap (cr->gstate);
}
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join);
}
cairo_line_join_t
cairo_get_line_join (cairo_t *cr)
{
return _cairo_gstate_get_line_join (cr->gstate);
}
void
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset);
}
void
cairo_set_miter_limit (cairo_t *cr, double limit)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
}
double
cairo_get_miter_limit (cairo_t *cr)
{
return _cairo_gstate_get_miter_limit (cr->gstate);
}
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
if (cr->status)
return;
cr->status = cairo_gstate_translate (cr->gstate, tx, ty);
}
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
if (cr->status)
return;
cr->status = _cairo_gstate_scale (cr->gstate, sx, sy);
}
void
cairo_rotate (cairo_t *cr, double angle)
{
if (cr->status)
return;
cr->status = _cairo_gstate_rotate (cr->gstate, angle);
}
void
cairo_concat_matrix (cairo_t *cr,
cairo_matrix_t *matrix)
{
if (cr->status)
return;
cr->status = _cairo_gstate_concat_matrix (cr->gstate, matrix);
}
void
cairo_set_matrix (cairo_t *cr,
cairo_matrix_t *matrix)
{
if (cr->status)
return;
cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix);
}
void
cairo_default_matrix (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_default_matrix (cr->gstate);
}
void
cairo_identity_matrix (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_identity_matrix (cr->gstate);
}
void
cairo_transform_point (cairo_t *cr, double *x, double *y)
{
if (cr->status)
return;
cr->status = cairo_gstateransform_point (cr->gstate, x, y);
}
void
cairo_transform_distance (cairo_t *cr, double *dx, double *dy)
{
if (cr->status)
return;
cr->status = cairo_gstateransform_distance (cr->gstate, dx, dy);
}
void
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y)
{
if (cr->status)
return;
cr->status = _cairo_gstate_inverse_transform_point (cr->gstate, x, y);
}
void
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy)
{
if (cr->status)
return;
cr->status = _cairo_gstate_inverse_transform_distance (cr->gstate, dx, dy);
}
void
cairo_new_path (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_new_path (cr->gstate);
}
void
cairo_move_to (cairo_t *cr, double x, double y)
{
if (cr->status)
return;
cr->status = _cairo_gstate_move_to (cr->gstate, x, y);
}
void
cairo_line_to (cairo_t *cr, double x, double y)
{
if (cr->status)
return;
cr->status = _cairo_gstate_line_to (cr->gstate, x, y);
}
void
cairo_curve_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
if (cr->status)
return;
cr->status = _cairo_gstate_curve_to (cr->gstate,
x1, y1,
x2, y2,
x3, y3);
}
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
if (cr->status)
return;
cr->status = _cairo_gstate_rel_move_to (cr->gstate, dx, dy);
}
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
{
if (cr->status)
return;
cr->status = _cairo_gstate_rel_line_to (cr->gstate, dx, dy);
}
void
cairo_rel_curve_to (cairo_t *cr,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3)
{
if (cr->status)
return;
cr->status = _cairo_gstate_rel_curve_to (cr->gstate,
dx1, dy1,
dx2, dy2,
dx3, dy3);
}
void
cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height)
{
if (cr->status)
return;
cairo_move_to (cr, x, y);
cairo_rel_line_to (cr, width, 0);
cairo_rel_line_to (cr, 0, height);
cairo_rel_line_to (cr, -width, 0);
cairo_close_path (cr);
}
void
cairo_close_path (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_close_path (cr->gstate);
}
void
cairo_get_current_point (cairo_t *cr, double *x, double *y)
{
/* XXX: Should we do anything with the return values in the error case? */
if (cr->status)
return;
cr->status = _cairo_gstate_get_current_point (cr->gstate, x, y);
}
void
cairo_stroke (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_stroke (cr->gstate);
}
void
cairo_fill (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_fill (cr->gstate);
}
void
cairo_clip (cairo_t *cr)
{
if (cr->status)
return;
cr->status = _cairo_gstate_clip (cr->gstate);
}
void
cairo_select_font (cairo_t *cr, const char *key)
{
if (cr->status)
return;
cr->status = _cairo_gstate_select_font (cr->gstate, key);
}
void
cairo_scale_font (cairo_t *cr, double scale)
{
if (cr->status)
return;
cr->status = _cairo_gstate_scale_font (cr->gstate, scale);
}
void
cairo_transform_font (cairo_t *cr,
double a, double b,
double c, double d)
{
if (cr->status)
return;
cr->status = cairo_gstateransform_font (cr->gstate,
a, b, c, d);
}
void
cairo_text_extents (cairo_t *cr,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy)
{
if (cr->status)
return;
cr->status = cairo_gstateext_extents (cr->gstate, utf8,
x, y, width, height, dx, dy);
}
void
cairo_show_text (cairo_t *cr, const unsigned char *utf8)
{
if (cr->status)
return;
cr->status = _cairo_gstate_show_text (cr->gstate, utf8);
}
void
cairo_show_surface (cairo_t *cr,
cairo_surface_t *surface,
int width,
int height)
{
if (cr->status)
return;
cr->status = _cairo_gstate_show_surface (cr->gstate,
surface, width, height);
}
cairo_status_t
cairo_get_status (cairo_t *cr)
{
return cr->status;
}
const char *
cairo_get_status_string (cairo_t *cr)
{
switch (cr->status) {
case CAIRO_STATUS_SUCCESS:
return "success";
case CAIRO_STATUS_NO_MEMORY:
return "out of memory";
case CAIRO_STATUS_INVALID_RESTORE:
return "cairo_restore without matching cairo_save";
case CAIRO_STATUS_INVALID_POP_GROUP:
return "cairo_pop_group without matching cairo_push_group";
case CAIRO_STATUS_NO_CURRENT_POINT:
return "no current point defined";
case CAIRO_STATUS_INVALID_MATRIX:
return "invalid matrix (not invertible)";
}
return "";
}
static void
_cairo_restrict_value (double *value, double min, double max)
{
if (*value < min)
*value = min;
else if (*value > max)
*value = max;
}

494
src/cairo.h Normal file
View file

@ -0,0 +1,494 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#ifndef _CAIRO_H_
#define _CAIRO_H_
#include <Xc.h>
typedef struct cairo cairo_t;
typedef struct cairo_surface_t cairo_surface_t;
typedef struct cairo_matrix_t cairo_matrix_t;
#ifdef __cplusplus
extern "C" {
#endif
/* Functions for manipulating state objects */
cairo_t *
cairo_create (void);
void
cairo_destroy (cairo_t *cr);
void
cairo_save (cairo_t *cr);
void
cairo_restore (cairo_t *cr);
/* XXX: I want to rethink this API
void
cairo_push_group (cairo_t *cr);
void
cairo_pop_group (cairo_t *cr);
*/
/* Modify state */
void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface);
typedef enum cairo_format_t {
CAIRO_FORMAT_ARGB32 = PictStandardARGB32,
CAIRO_FORMAT_RGB24 = PictStandardRGB24,
CAIRO_FORMAT_A8 = PictStandardA8,
CAIRO_FORMAT_A1 = PictStandardA1
} cairo_format_t;
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable);
void
cairo_set_target_image (cairo_t *cr,
char *data,
cairo_format_t format,
int width,
int height,
int stride);
typedef enum cairo_operator_t {
CAIRO_OPERATOR_CLEAR = PictOpClear,
CAIRO_OPERATOR_SRC = PictOpSrc,
CAIRO_OPERATOR_DST = PictOpDst,
CAIRO_OPERATOR_OVER = PictOpOver,
CAIRO_OPERATOR_OVER_REVERSE = PictOpOverReverse,
CAIRO_OPERATOR_IN = PictOpIn,
CAIRO_OPERATOR_IN_REVERSE = PictOpInReverse,
CAIRO_OPERATOR_OUT = PictOpOut,
CAIRO_OPERATOR_OUT_REVERSE = PictOpOutReverse,
CAIRO_OPERATOR_ATOP = PictOpAtop,
CAIRO_OPERATOR_ATOP_REVERSE = PictOpAtopReverse,
CAIRO_OPERATOR_XOR = PictOpXor,
CAIRO_OPERATOR_ADD = PictOpAdd,
CAIRO_OPERATOR_SATURATE = PictOpSaturate,
CAIRO_OPERATOR_DISJOINT_CLEAR = PictOpDisjointClear,
CAIRO_OPERATOR_DISJOINT_SRC = PictOpDisjointSrc,
CAIRO_OPERATOR_DISJOINT_DST = PictOpDisjointDst,
CAIRO_OPERATOR_DISJOINT_OVER = PictOpDisjointOver,
CAIRO_OPERATOR_DISJOINT_OVER_REVERSE = PictOpDisjointOverReverse,
CAIRO_OPERATOR_DISJOINT_IN = PictOpDisjointIn,
CAIRO_OPERATOR_DISJOINT_IN_REVERSE = PictOpDisjointInReverse,
CAIRO_OPERATOR_DISJOINT_OUT = PictOpDisjointOut,
CAIRO_OPERATOR_DISJOINT_OUT_REVERSE = PictOpDisjointOutReverse,
CAIRO_OPERATOR_DISJOINT_ATOP = PictOpDisjointAtop,
CAIRO_OPERATOR_DISJOINT_ATOP_REVERSE = PictOpDisjointAtopReverse,
CAIRO_OPERATOR_DISJOINT_XOR = PictOpDisjointXor,
CAIRO_OPERATOR_CONJOINT_CLEAR = PictOpConjointClear,
CAIRO_OPERATOR_CONJOINT_SRC = PictOpConjointSrc,
CAIRO_OPERATOR_CONJOINT_DST = PictOpConjointDst,
CAIRO_OPERATOR_CONJOINT_OVER = PictOpConjointOver,
CAIRO_OPERATOR_CONJOINT_OVER_REVERSE = PictOpConjointOverReverse,
CAIRO_OPERATOR_CONJOINT_IN = PictOpConjointIn,
CAIRO_OPERATOR_CONJOINT_IN_REVERSE = PictOpConjointInReverse,
CAIRO_OPERATOR_CONJOINT_OUT = PictOpConjointOut,
CAIRO_OPERATOR_CONJOINT_OUT_REVERSE = PictOpConjointOutReverse,
CAIRO_OPERATOR_CONJOINT_ATOP = PictOpConjointAtop,
CAIRO_OPERATOR_CONJOINT_ATOP_REVERSE = PictOpConjointAtopReverse,
CAIRO_OPERATOR_CONJOINT_XOR = PictOpConjointXor
} cairo_operator_t;
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op);
/* XXX: Probably want to bite the bullet and expose a cairo_color_t object */
void
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue);
void
cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern);
void
cairo_set_tolerance (cairo_t *cr, double tolerance);
void
cairo_set_alpha (cairo_t *cr, double alpha);
typedef enum cairo_fill_rule_t {
CAIRO_FILL_RULE_WINDING,
CAIRO_FILL_RULE_EVEN_ODD
} cairo_fill_rule_t;
void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule);
void
cairo_set_line_width (cairo_t *cr, double width);
typedef enum cairo_line_cap_t {
CAIRO_LINE_CAP_BUTT,
CAIRO_LINE_CAP_ROUND,
CAIRO_LINE_CAP_SQUARE
} cairo_line_cap_t;
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap);
typedef enum cairo_line_join_t {
CAIRO_LINE_JOIN_MITER,
CAIRO_LINE_JOIN_ROUND,
CAIRO_LINE_JOIN_BEVEL
} cairo_line_join_t;
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join);
void
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset);
void
cairo_set_miter_limit (cairo_t *cr, double limit);
void
cairo_translate (cairo_t *cr, double tx, double ty);
void
cairo_scale (cairo_t *cr, double sx, double sy);
void
cairo_rotate (cairo_t *cr, double angle);
void
cairo_concat_matrix (cairo_t *cr,
cairo_matrix_t *matrix);
void
cairo_set_matrix (cairo_t *cr,
cairo_matrix_t *matrix);
void
cairo_default_matrix (cairo_t *cr);
/* XXX: There's been a proposal to add cairo_default_matrix_exact */
void
cairo_identity_matrix (cairo_t *cr);
void
cairo_transform_point (cairo_t *cr, double *x, double *y);
void
cairo_transform_distance (cairo_t *cr, double *dx, double *dy);
void
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y);
void
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy);
/* Path creation functions */
void
cairo_new_path (cairo_t *cr);
void
cairo_move_to (cairo_t *cr, double x, double y);
void
cairo_line_to (cairo_t *cr, double x, double y);
void
cairo_curve_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double x3, double y3);
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy);
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy);
void
cairo_rel_curve_to (cairo_t *cr,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
void
cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height);
void
cairo_close_path (cairo_t *cr);
/* Painting functions */
void
cairo_stroke (cairo_t *cr);
void
cairo_fill (cairo_t *cr);
/* Clipping */
void
cairo_clip (cairo_t *cr);
/* Font/Text functions */
/* XXX: The font support should probably expose a cairo_font_t object with
several functions, (cairo_font_transform, etc.) in a parallel manner as
cairo_matrix_t and (eventually) cairo_color_t */
void
cairo_select_font (cairo_t *cr, const char *key);
void
cairo_scale_font (cairo_t *cr, double scale);
/* XXX: Probably want to use a cairo_matrix_t here, (to fix as part of the
big text support rewrite) */
void
cairo_transform_font (cairo_t *cr,
double a, double b,
double c, double d);
void
cairo_text_extents (cairo_t *cr,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy);
void
cairo_show_text (cairo_t *cr, const unsigned char *utf8);
/* Image functions */
void
cairo_show_surface (cairo_t *cr,
cairo_surface_t *surface,
int width,
int height);
/* Query functions */
cairo_operator_t
cairo_get_operator (cairo_t *cr);
void
cairo_get_rgb_color (cairo_t *cr, double *red, double *green, double *blue);
/* XXX: Do we want cairo_get_pattern as well? */
double
cairo_get_tolerance (cairo_t *cr);
double
cairo_get_alpha (cairo_t *cr);
void
cairo_get_current_point (cairo_t *cr, double *x, double *y);
cairo_fill_rule_t
cairo_get_fill_rule (cairo_t *cr);
double
cairo_get_line_width (cairo_t *cr);
cairo_line_cap_t
cairo_get_line_cap (cairo_t *cr);
cairo_line_join_t
cairo_get_line_join (cairo_t *cr);
double
cairo_get_miter_limit (cairo_t *cr);
/* XXX: How to do cairo_get_dash??? Do we want to switch to a cairo_dash object? */
void
cairo_get_matrix (cairo_t *cr,
double *a, double *b,
double *c, double *d,
double *tx, double *ty);
cairo_surface_t *
cairo_get_target_surface (cairo_t *cr);
/* Error status queries */
typedef enum cairo_status_t {
CAIRO_STATUS_SUCCESS = 0,
CAIRO_STATUS_NO_MEMORY,
CAIRO_STATUS_INVALID_RESTORE,
CAIRO_STATUS_INVALID_POP_GROUP,
CAIRO_STATUS_NO_CURRENT_POINT,
CAIRO_STATUS_INVALID_MATRIX
} cairo_status_t;
cairo_status_t
cairo_get_status (cairo_t *cr);
const char *
cairo_get_status_string (cairo_t *cr);
/* Surface mainpulation */
/* XXX: This is a mess from the user's POV. Should the Visual or the
cairo_format_t control what render format is used? Maybe I can have
cairo_surface_create_for_window with a visual, and
cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
*/
cairo_surface_t *
cairo_surface_create_for_drawable (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap);
cairo_surface_t *
cairo_surface_create_for_image (char *data,
cairo_format_t format,
int width,
int height,
int stride);
cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
int width,
int height);
/* XXX: One problem with having RGB and A here in one function is that
it introduces the question of pre-multiplied vs. non-pre-multiplied
alpha. Do I want to export a cairo_color_t structure instead? So far, no
other public functions need it. */
cairo_surface_t *
cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
int width,
int height,
double red,
double green,
double blue,
double alpha);
void
cairo_surface_destroy (cairo_surface_t *surface);
/* XXX: Should this take an X/Y offset as well? (Probably) */
cairo_status_t
cairo_surface_put_image (cairo_surface_t *surface,
char *data,
int width,
int height,
int stride);
/* XXX: The Xc version of this function isn't quite working yet
cairo_status_t
cairo_surface_set_clip_region (cairo_surface_t *surface, Region region);
*/
/* XXX: Note: The current Render/Ic implementations don't do the right
thing with repeat when the surface has a non-identity matrix. */
cairo_status_t
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat);
cairo_status_t
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
cairo_status_t
cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
typedef enum cairo_filter_t {
CAIRO_FILTER_FAST = XcFilterFast,
CAIRO_FILTER_GOOD = XcFilterGood,
CAIRO_FILTER_BEST = XcFilterBest,
CAIRO_FILTER_NEAREST = XcFilterNearest,
CAIRO_FILTER_BILINEAR = XcFilterBilinear
} cairo_filter_t;
cairo_status_t
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter);
/* Matrix functions */
cairo_matrix_t *
cairo_matrix_create (void);
void
cairo_matrix_destroy (cairo_matrix_t *matrix);
cairo_status_t
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other);
cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix);
cairo_status_t
cairo_matrix_set_affine (cairo_matrix_t *cr,
double a, double b,
double c, double d,
double tx, double ty);
cairo_status_t
cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *a, double *b,
double *c, double *d,
double *tx, double *ty);
cairo_status_t
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty);
cairo_status_t
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy);
cairo_status_t
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians);
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix);
cairo_status_t
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b);
cairo_status_t
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy);
cairo_status_t
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
#ifdef __cplusplus
}
#endif
#endif

80
src/cairo_color.c Normal file
View file

@ -0,0 +1,80 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
static cairo_color_t CAIRO_COLOR_DEFAULT = { 1.0, 1.0, 1.0, 1.0, {0xffff, 0xffff, 0xffff, 0xffff}};
static void
_cairo_color_compute_xc_color (cairo_color_t *color);
void
_cairo_color_init (cairo_color_t *color)
{
*color = CAIRO_COLOR_DEFAULT;
}
void
_cairo_color_fini (cairo_color_t *color)
{
/* Nothing to do here */
}
static void
_cairo_color_compute_xc_color (cairo_color_t *color)
{
color->xc_color.red = color->red * color->alpha * 0xffff;
color->xc_color.green = color->green * color->alpha * 0xffff;
color->xc_color.blue = color->blue * color->alpha * 0xffff;
color->xc_color.alpha = color->alpha * 0xffff;
}
void
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
{
color->red = red;
color->green = green;
color->blue = blue;
_cairo_color_compute_xc_color (color);
}
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
{
*red = color->red;
*green = color->green;
*blue = color->blue;
}
void
_cairo_color_set_alpha (cairo_color_t *color, double alpha)
{
color->alpha = alpha;
_cairo_color_compute_xc_color (color);
}

171
src/cairo_font.c Normal file
View file

@ -0,0 +1,171 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <string.h>
#include "cairoint.h"
void
_cairo_font_init (cairo_font_t *font)
{
font->key = (unsigned char *) strdup (CAIRO_FONT_KEY_DEFAULT);
font->dpy = NULL;
font->xft_font = NULL;
cairo_matrix_set_identity (&font->matrix);
}
cairo_status_t
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other)
{
*font = *other;
if (other->key) {
font->key = (unsigned char *) strdup ((char *) other->key);
if (font->key == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
if (other->xft_font) {
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
if (font->xft_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_font_fini (cairo_font_t *font)
{
if (font->key)
free (font->key);
font->key = NULL;
_cairo_matrix_fini (&font->matrix);
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
}
cairo_status_t
_cairo_font_select (cairo_font_t *font, const char *key)
{
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->key)
free (font->key);
font->key = (unsigned char *) strdup ((char *) key);
if (font->key == NULL)
return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_font_scale (cairo_font_t *font, double scale)
{
cairo_matrix_scale (&font->matrix, scale, scale);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_font_transform (cairo_font_t *font,
double a, double b,
double c, double d)
{
cairo_matrix_t m;
cairo_matrix_set_affine (&m, a, b, c, d, 0, 0);
cairo_matrix_multiply (&font->matrix, &m, &font->matrix);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
cairo_matrix_t matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font) {
*xft_font = font->xft_font;
return CAIRO_STATUS_SUCCESS;
}
pattern = FcNameParse (font->key);
matrix = gstate->ctm;
cairo_matrix_multiply (&matrix, &font->matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling? */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (expansion);
FcPatternAddDouble (pattern, "pixelsize", font_size);
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
/* XXX: Need to abandon Xft and use Xc instead */
/* When I do that I can throw away these Display pointers */
font->dpy = gstate->surface->dpy;
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
*xft_font = font->xft_font;
FcPatternDestroy (pattern);
return CAIRO_STATUS_SUCCESS;
}

1123
src/cairo_gstate.c Normal file

File diff suppressed because it is too large Load diff

380
src/cairo_matrix.c Normal file
View file

@ -0,0 +1,380 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include <math.h>
#include "cairoint.h"
static cairo_matrix_t CAIRO_MATRIX_IDENTITY = {
{
{1, 0},
{0, 1},
{0, 0}
}
};
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
cairo_matrix_t *
cairo_matrix_create (void)
{
cairo_matrix_t *matrix;
matrix = malloc (sizeof (cairo_matrix_t));
if (matrix == NULL)
return NULL;
_cairo_matrix_init (matrix);
return matrix;
}
void
_cairo_matrix_init (cairo_matrix_t *matrix)
{
cairo_matrix_set_identity (matrix);
}
void
_cairo_matrix_fini (cairo_matrix_t *matrix)
{
/* nothing to do here */
}
void
cairo_matrix_destroy (cairo_matrix_t *matrix)
{
_cairo_matrix_fini (matrix);
free (matrix);
}
cairo_status_t
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
{
*matrix = *other;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix)
{
*matrix = CAIRO_MATRIX_IDENTITY;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_set_affine (cairo_matrix_t *matrix,
double a, double b,
double c, double d,
double tx, double ty)
{
matrix->m[0][0] = a; matrix->m[0][1] = b;
matrix->m[1][0] = c; matrix->m[1][1] = d;
matrix->m[2][0] = tx; matrix->m[2][1] = ty;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *a, double *b,
double *c, double *d,
double *tx, double *ty)
{
*a = matrix->m[0][0]; *b = matrix->m[0][1];
*c = matrix->m[1][0]; *d = matrix->m[1][1];
*tx = matrix->m[2][0]; *ty = matrix->m[2][1];
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
double tx, double ty)
{
return cairo_matrix_set_affine (matrix,
1, 0,
0, 1,
tx, ty);
}
cairo_status_t
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
cairo_matrix_t tmp;
_cairo_matrix_set_translate (&tmp, tx, ty);
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
cairo_status_t
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
double sx, double sy)
{
return cairo_matrix_set_affine (matrix,
sx, 0,
0, sy,
0, 0);
}
cairo_status_t
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
cairo_matrix_t tmp;
_cairo_matrix_set_scale (&tmp, sx, sy);
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double radians)
{
return cairo_matrix_set_affine (matrix,
cos (radians), sin (radians),
-sin (radians), cos (radians),
0, 0);
}
cairo_status_t
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
cairo_matrix_t tmp;
_cairo_matrix_set_rotate (&tmp, radians);
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
cairo_status_t
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
cairo_matrix_t r;
int row, col, n;
double t;
for (row = 0; row < 3; row++) {
for (col = 0; col < 2; col++) {
if (row == 2)
t = b->m[2][col];
else
t = 0;
for (n = 0; n < 2; n++) {
t += a->m[row][n] * b->m[n][col];
}
r.m[row][col] = t;
}
}
*result = r;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
{
double new_x, new_y;
new_x = (matrix->m[0][0] * *dx
+ matrix->m[1][0] * *dy);
new_y = (matrix->m[0][1] * *dx
+ matrix->m[1][1] * *dy);
*dx = new_x;
*dy = new_y;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
{
cairo_matrix_transform_distance (matrix, x, y);
*x += matrix->m[2][0];
*y += matrix->m[2][1];
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height)
{
int i;
double quad_x[4], quad_y[4];
double dx1, dy1;
double dx2, dy2;
double min_x, max_x;
double min_y, max_y;
quad_x[0] = *x;
quad_y[0] = *y;
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
dx1 = *width;
dy1 = 0;
cairo_matrix_transform_distance (matrix, &dx1, &dy1);
quad_x[1] = quad_x[0] + dx1;
quad_y[1] = quad_y[0] + dy1;
dx2 = 0;
dy2 = *height;
cairo_matrix_transform_distance (matrix, &dx2, &dy2);
quad_x[2] = quad_x[0] + dx2;
quad_y[2] = quad_y[0] + dy2;
quad_x[3] = quad_x[0] + dx1 + dx2;
quad_y[3] = quad_y[0] + dy1 + dy2;
min_x = max_x = quad_x[0];
min_y = max_y = quad_y[0];
for (i=1; i < 4; i++) {
if (quad_x[i] < min_x)
min_x = quad_x[i];
if (quad_x[i] > max_x)
max_x = quad_x[i];
if (quad_y[i] < min_y)
min_y = quad_y[i];
if (quad_y[i] > max_y)
max_y = quad_y[i];
}
*x = min_x;
*y = min_y;
*width = max_x - min_x;
*height = max_y - min_y;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
int row, col;
for (row = 0; row < 3; row++)
for (col = 0; col < 2; col++)
matrix->m[row][col] *= scalar;
}
/* This function isn't a correct adjoint in that the implicit 1 in the
homogeneous result should actually be ad-bc instead. But, since this
adjoint is only used in the computation of the inverse, which
divides by det (A)=ad-bc anyway, everything works out in the end. */
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
{
/* adj (A) = transpose (C:cofactor (A,i,j)) */
double a, b, c, d, tx, ty;
a = matrix->m[0][0]; b = matrix->m[0][1];
c = matrix->m[1][0]; d = matrix->m[1][1];
tx = matrix->m[2][0]; ty = matrix->m[2][1];
cairo_matrix_set_affine (matrix,
d, -b,
-c, a,
c*ty - d*tx, b*tx - a*ty);
}
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix)
{
/* inv (A) = 1/det (A) * adj (A) */
double det;
_cairo_matrix_compute_determinant (matrix, &det);
if (det == 0)
return CAIRO_STATUS_INVALID_MATRIX;
_cairo_matrix_compute_adjoint (matrix);
_cairo_matrix_scalar_multiply (matrix, 1 / det);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
{
double a, b, c, d;
a = matrix->m[0][0]; b = matrix->m[0][1];
c = matrix->m[1][0]; d = matrix->m[1][1];
*det = a*d - b*c;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
{
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
det (M - lI) = 0
The zeros in our homogeneous 3x3 matrix make this equation equal
to that formed by the sub-matrix:
M = a b
c d
by which:
l^2 - (a+d)l + (ad - bc) = 0
l = (a+d +/- sqrt (a^2 + 2ad + d^2 - 4 (ad-bc))) / 2;
*/
double a, b, c, d, rad;
a = matrix->m[0][0];
b = matrix->m[0][1];
c = matrix->m[1][0];
d = matrix->m[1][1];
rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
*lambda1 = (a + d + rad) / 2.0;
*lambda2 = (a + d - rad) / 2.0;
return CAIRO_STATUS_SUCCESS;
}

36
src/cairo_misc.c Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
void
_compute_slope (XPointFixed *a, XPointFixed *b, cairo_slope_fixed_t *slope)
{
slope->dx = b->x - a->x;
slope->dy = b->y - a->y;
}

436
src/cairo_path.c Normal file
View file

@ -0,0 +1,436 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include "cairoint.h"
/* private functions */
static cairo_status_t
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts);
static void
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op);
static cairo_status_t
_cairo_path_new_op_buf (cairo_path_t *path);
static void
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg);
static cairo_status_t
_cairo_path_new_arg_buf (cairo_path_t *path);
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void);
static void
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *buf);
static void
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op);
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void);
static void
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *buf);
static void
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts);
void
_cairo_path_init (cairo_path_t *path)
{
path->op_head = NULL;
path->op_tail = NULL;
path->arg_head = NULL;
path->arg_tail = NULL;
}
cairo_status_t
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
{
cairo_path_op_buf_t *op, *other_op;
cairo_path_arg_buf_t *arg, *other_arg;
_cairo_path_init (path);
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _cairo_path_op_buf_create ();
if (op == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
*op = *other_op;
_cairo_path_add_op_buf (path, op);
}
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
arg = _cairo_path_arg_buf_create ();
if (arg == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
*arg = *other_arg;
_cairo_path_add_arg_buf (path, arg);
}
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_path_fini (cairo_path_t *path)
{
cairo_path_op_buf_t *op;
cairo_path_arg_buf_t *arg;
while (path->op_head) {
op = path->op_head;
path->op_head = op->next;
_cairo_path_op_buf_destroy (op);
}
path->op_tail = NULL;
while (path->arg_head) {
arg = path->arg_head;
path->arg_head = arg->next;
_cairo_path_arg_buf_destroy (arg);
}
path->arg_tail = NULL;
}
cairo_status_t
_cairo_path_move_to (cairo_path_t *path, double x, double y)
{
XPointFixed pt;
pt.x = XDoubleToFixed (x);
pt.y = XDoubleToFixed (y);
return _cairo_path_add (path, cairo_path_op_move_to, &pt, 1);
}
cairo_status_t
_cairo_path_line_to (cairo_path_t *path, double x, double y)
{
XPointFixed pt;
pt.x = XDoubleToFixed (x);
pt.y = XDoubleToFixed (y);
return _cairo_path_add (path, cairo_path_op_line_to, &pt, 1);
}
cairo_status_t
_cairo_path_curve_to (cairo_path_t *path,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
XPointFixed pt[3];
pt[0].x = XDoubleToFixed (x1);
pt[0].y = XDoubleToFixed (y1);
pt[1].x = XDoubleToFixed (x2);
pt[1].y = XDoubleToFixed (y2);
pt[2].x = XDoubleToFixed (x3);
pt[2].y = XDoubleToFixed (y3);
return _cairo_path_add (path, cairo_path_op_curve_to, pt, 3);
}
cairo_status_t
_cairo_path_close_path (cairo_path_t *path)
{
return _cairo_path_add (path, cairo_path_op_close_path, NULL, 0);
}
static cairo_status_t
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts)
{
cairo_status_t status;
if (path->op_tail == NULL || path->op_tail->num_ops + 1 > CAIRO_PATH_BUF_SZ) {
status = _cairo_path_new_op_buf (path);
if (status)
return status;
}
_cairo_path_op_buf_add (path->op_tail, op);
if (path->arg_tail == NULL || path->arg_tail->num_pts + num_pts > CAIRO_PATH_BUF_SZ) {
status = _cairo_path_new_arg_buf (path);
if (status)
return status;
}
_cairo_path_arg_buf_add (path->arg_tail, pts, num_pts);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op)
{
op->next = NULL;
op->prev = path->op_tail;
if (path->op_tail) {
path->op_tail->next = op;
} else {
path->op_head = op;
}
path->op_tail = op;
}
static cairo_status_t
_cairo_path_new_op_buf (cairo_path_t *path)
{
cairo_path_op_buf_t *op;
op = _cairo_path_op_buf_create ();
if (op == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_path_add_op_buf (path, op);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
{
arg->next = NULL;
arg->prev = path->arg_tail;
if (path->arg_tail) {
path->arg_tail->next = arg;
} else {
path->arg_head = arg;
}
path->arg_tail = arg;
}
static cairo_status_t
_cairo_path_new_arg_buf (cairo_path_t *path)
{
cairo_path_arg_buf_t *arg;
arg = _cairo_path_arg_buf_create ();
if (arg == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_path_add_arg_buf (path, arg);
return CAIRO_STATUS_SUCCESS;
}
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void)
{
cairo_path_op_buf_t *op;
op = malloc (sizeof (cairo_path_op_buf_t));
if (op) {
op->num_ops = 0;
op->next = NULL;
}
return op;
}
static void
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
{
free (op);
}
static void
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op)
{
op_buf->op[op_buf->num_ops++] = op;
}
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void)
{
cairo_path_arg_buf_t *arg;
arg = malloc (sizeof (cairo_path_arg_buf_t));
if (arg) {
arg->num_pts = 0;
arg->next = NULL;
}
return arg;
}
static void
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
{
free (arg);
}
static void
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts)
{
int i;
for (i=0; i < num_pts; i++) {
arg->pt[arg->num_pts++] = pts[i];
}
}
#define CAIRO_PATH_OP_MAX_ARGS 3
static int num_args[] =
{
1, /* cairo_path_move_to */
1, /* cairo_path_op_line_to */
3, /* cairo_path_op_curve_to */
0, /* cairo_path_op_close_path */
};
cairo_status_t
_cairo_path_interpret (cairo_path_t *path, cairo_path_direction dir, const cairo_path_callbacks_t *cb, void *closure)
{
cairo_status_t status;
int i, arg;
cairo_path_op_buf_t *op_buf;
cairo_path_op op;
cairo_path_arg_buf_t *arg_buf = path->arg_head;
int buf_i = 0;
XPointFixed pt[CAIRO_PATH_OP_MAX_ARGS];
XPointFixed current = {0, 0};
XPointFixed first = {0, 0};
int has_current = 0;
int has_edge = 0;
int step = (dir == cairo_path_direction_forward) ? 1 : -1;
for (op_buf = (dir == cairo_path_direction_forward) ? path->op_head : path->op_tail;
op_buf;
op_buf = (dir == cairo_path_direction_forward) ? op_buf->next : op_buf->prev)
{
int start, stop;
if (dir == cairo_path_direction_forward) {
start = 0;
stop = op_buf->num_ops;
} else {
start = op_buf->num_ops - 1;
stop = -1;
}
for (i=start; i != stop; i += step) {
op = op_buf->op[i];
if (dir == cairo_path_direction_reverse) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_pts;
}
buf_i -= num_args[op];
}
for (arg = 0; arg < num_args[op]; arg++) {
pt[arg] = arg_buf->pt[buf_i];
buf_i++;
if (buf_i >= arg_buf->num_pts) {
arg_buf = arg_buf->next;
buf_i = 0;
}
}
if (dir == cairo_path_direction_reverse) {
buf_i -= num_args[op];
}
switch (op) {
case cairo_path_op_move_to:
if (has_edge) {
status = (*cb->DoneSubPath) (closure, cairo_sub_path_done_cap);
if (status)
return status;
}
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
break;
case cairo_path_op_line_to:
if (has_current) {
status = (*cb->AddEdge) (closure, &current, &pt[0]);
if (status)
return status;
current = pt[0];
has_edge = 1;
} else {
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
}
break;
case cairo_path_op_curve_to:
if (has_current) {
status = (*cb->AddSpline) (closure, &current, &pt[0], &pt[1], &pt[2]);
if (status)
return status;
current = pt[2];
has_edge = 1;
} else {
first = pt[2];
current = pt[2];
has_current = 1;
has_edge = 0;
}
break;
case cairo_path_op_close_path:
if (has_edge) {
(*cb->AddEdge) (closure, &current, &first);
(*cb->DoneSubPath) (closure, cairo_sub_path_done_join);
}
current.x = 0;
current.y = 0;
first.x = 0;
first.y = 0;
has_current = 0;
has_edge = 0;
break;
}
}
}
if (has_edge)
(*cb->DoneSubPath) (closure, cairo_sub_path_done_cap);
return (*cb->DonePath) (closure);
}

168
src/cairo_path_bounds.c Normal file
View file

@ -0,0 +1,168 @@
/*
* Copyright © 2003 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
typedef struct _cairo_path_bounder {
int has_pt;
XFixed min_x;
XFixed min_y;
XFixed max_x;
XFixed max_y;
} cairo_path_bounder;
static void
_cairo_path_bounder_init (cairo_path_bounder *bounder);
static void
_cairo_path_bounder_fini (cairo_path_bounder *bounder);
static cairo_status_t
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt);
static cairo_status_t
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_path_bounder_add_spline (void *closure,
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static cairo_status_t
_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done done);
static cairo_status_t
_cairo_path_bounder_done_path (void *closure);
static void
_cairo_path_bounder_init (cairo_path_bounder *bounder)
{
bounder->has_pt = 0;
}
static void
_cairo_path_bounder_fini (cairo_path_bounder *bounder)
{
bounder->has_pt = 0;
}
static cairo_status_t
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt)
{
if (bounder->has_pt) {
if (pt->x < bounder->min_x)
bounder->min_x = pt->x;
if (pt->y < bounder->min_y)
bounder->min_y = pt->y;
if (pt->x > bounder->max_x)
bounder->max_x = pt->x;
if (pt->y > bounder->max_y)
bounder->max_y = pt->y;
} else {
bounder->min_x = pt->x;
bounder->min_y = pt->y;
bounder->max_x = pt->x;
bounder->max_y = pt->y;
bounder->has_pt = 1;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_path_bounder *bounder = closure;
_cairo_path_bounder_add_point (bounder, p1);
_cairo_path_bounder_add_point (bounder, p2);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_add_spline (void *closure,
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
cairo_path_bounder *bounder = closure;
_cairo_path_bounder_add_point (bounder, a);
_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_done_sub_path (void *closure, cairo_sub_path_done done)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_done_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
static cairo_path_callbacks_t cb = {
_cairo_path_bounder_add_edge,
_cairo_path_bounder_add_spline,
_cairo_path_bounder_done_sub_path,
_cairo_path_bounder_done_path
};
cairo_path_bounder bounder;
_cairo_path_bounder_init (&bounder);
status = _cairo_path_interpret (path, cairo_path_direction_forward, &cb, &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_cairo_path_bounder_fini (&bounder);
return status;
}
*x1 = XFixedToDouble (bounder.min_x);
*y1 = XFixedToDouble (bounder.min_y);
*x2 = XFixedToDouble (bounder.max_x);
*y2 = XFixedToDouble (bounder.max_y);
_cairo_path_bounder_fini (&bounder);
return CAIRO_STATUS_SUCCESS;
}

158
src/cairo_path_fill.c Normal file
View file

@ -0,0 +1,158 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
typedef struct _cairo_filler {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
cairo_polygon_t polygon;
} cairo_filler;
static void
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
static void
_cairo_filler_fini (cairo_filler *filler);
static cairo_status_t
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static cairo_status_t
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done);
static cairo_status_t
_cairo_filler_done_path (void *closure);
static void
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
filler->gstate = gstate;
filler->traps = traps;
_cairo_polygon_init (&filler->polygon);
}
static void
_cairo_filler_fini (cairo_filler *filler)
{
_cairo_polygon_fini (&filler->polygon);
}
static cairo_status_t
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_filler *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
return _cairo_polygon_add_edge (polygon, p1, p2);
}
static cairo_status_t
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
int i;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
cairo_gstate_t *gstate = filler->gstate;
cairo_spline_t spline;
status = _cairo_spline_init (&spline, a, b, c, d);
if (status == cairo_int_status_degenerate)
return CAIRO_STATUS_SUCCESS;
_cairo_spline_decompose (&spline, gstate->tolerance);
if (status)
goto CLEANUP_SPLINE;
for (i = 0; i < spline.num_pts - 1; i++) {
status = _cairo_polygon_add_edge (polygon, &spline.pts[i], &spline.pts[i+1]);
if (status)
goto CLEANUP_SPLINE;
}
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
return status;
}
static cairo_status_t
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_close (polygon);
return status;
}
static cairo_status_t
_cairo_filler_done_path (void *closure)
{
cairo_filler *filler = closure;
return cairo_traps_tessellate_polygon (filler->traps,
&filler->polygon,
filler->gstate->fill_rule);
}
cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
static const cairo_path_callbacks_t filler_callbacks = {
_cairo_filler_add_edge,
_cairo_filler_add_spline,
_cairo_filler_done_sub_path,
_cairo_filler_done_path
};
cairo_status_t status;
cairo_filler filler;
_cairo_filler_init (&filler, gstate, traps);
status = _cairo_path_interpret (path,
cairo_path_direction_forward,
&filler_callbacks, &filler);
if (status) {
_cairo_filler_fini (&filler);
return status;
}
_cairo_filler_fini (&filler);
return CAIRO_STATUS_SUCCESS;
}

715
src/cairo_path_stroke.c Normal file
View file

@ -0,0 +1,715 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
typedef struct _cairo_stroker {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
int have_prev;
int have_first;
int is_first;
cairo_stroke_face_t prev;
cairo_stroke_face_t first;
int dash_index;
int dash_on;
double dash_remain;
} cairo_stroker;
/* private functions */
static void
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps);
static void
_cairo_stroker_fini (cairo_stroker *stroker);
static cairo_status_t
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2);
static cairo_status_t
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static cairo_status_t
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done);
static cairo_status_t
_cairo_stroker_done_path (void *closure);
static void
_translate_point (XPointFixed *pt, XPointFixed *offset);
static int
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out);
static cairo_status_t
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
static void
_cairo_stroker_start_dash (cairo_stroker *stroker)
{
cairo_gstate_t *gstate = stroker->gstate;
double offset;
int on = 1;
int i = 0;
offset = gstate->dash_offset;
while (offset >= gstate->dash[i]) {
offset -= gstate->dash[i];
on = 1-on;
if (++i == gstate->num_dashes)
i = 0;
}
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_remain = gstate->dash[i] - offset;
}
static void
_cairo_stroker_step_dash (cairo_stroker *stroker, double step)
{
cairo_gstate_t *gstate = stroker->gstate;
stroker->dash_remain -= step;
if (stroker->dash_remain <= 0) {
stroker->dash_index++;
if (stroker->dash_index == gstate->num_dashes)
stroker->dash_index = 0;
stroker->dash_on = 1-stroker->dash_on;
stroker->dash_remain = gstate->dash[stroker->dash_index];
}
}
static void
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
stroker->gstate = gstate;
stroker->traps = traps;
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
if (gstate->dash)
_cairo_stroker_start_dash (stroker);
}
static void
_cairo_stroker_fini (cairo_stroker *stroker)
{
/* nothing to do here */
}
static void
_translate_point (XPointFixed *pt, XPointFixed *offset)
{
pt->x += offset->x;
pt->y += offset->y;
}
static int
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
XPointDouble d_in, d_out;
d_in.x = XFixedToDouble (in->cw.x - in->pt.x);
d_in.y = XFixedToDouble (in->cw.y - in->pt.y);
d_out.x = XFixedToDouble (out->cw.x - out->pt.x);
d_out.y = XFixedToDouble (out->cw.y - out->pt.y);
return d_out.y * d_in.x > d_in.y * d_out.x;
}
static cairo_status_t
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
cairo_status_t status;
cairo_gstate_t *gstate = stroker->gstate;
int clockwise = _cairo_stroker_face_clockwise (out, in);
XPointFixed *inpt, *outpt;
if (in->cw.x == out->cw.x
&& in->cw.y == out->cw.y
&& in->ccw.x == out->ccw.x
&& in->ccw.y == out->ccw.y) {
return CAIRO_STATUS_SUCCESS;
}
if (clockwise) {
inpt = &in->ccw;
outpt = &out->ccw;
} else {
inpt = &in->cw;
outpt = &out->cw;
}
switch (gstate->line_join) {
case CAIRO_LINE_JOIN_ROUND: {
int i;
int start, step, stop;
XPointFixed tri[3], initial, final;
cairo_pen_t *pen = &gstate->pen_regular;
tri[0] = in->pt;
if (clockwise) {
initial = in->ccw;
_cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
step = -1;
_cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
final = out->ccw;
} else {
initial = in->cw;
_cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
step = +1;
_cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
final = out->cw;
}
i = start;
tri[1] = initial;
while (i != stop) {
tri[2] = in->pt;
_translate_point (&tri[2], &pen->vertex[i].pt);
cairo_traps_tessellate_triangle (stroker->traps, tri);
tri[1] = tri[2];
i += step;
if (i < 0)
i = pen->num_vertices - 1;
if (i >= pen->num_vertices)
i = 0;
}
tri[2] = final;
return cairo_traps_tessellate_triangle (stroker->traps, tri);
}
case CAIRO_LINE_JOIN_MITER:
default: {
cairo_polygon_t polygon;
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
XDouble ml = gstate->miter_limit;
_cairo_polygon_init (&polygon);
if (2 <= ml * ml * (1 - c)) {
XDouble x1, y1, x2, y2;
XDouble mx, my;
XDouble dx1, dx2, dy1, dy2;
XPointFixed outer;
x1 = XFixedToDouble (inpt->x);
y1 = XFixedToDouble (inpt->y);
dx1 = in->usr_vector.x;
dy1 = in->usr_vector.y;
cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
x2 = XFixedToDouble (outpt->x);
y2 = XFixedToDouble (outpt->y);
dx2 = out->usr_vector.x;
dy2 = out->usr_vector.y;
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
(dx1 * dy2 - dx2 * dy1));
if (dy1)
mx = (my - y1) * dx1 / dy1 + x1;
else
mx = (my - y2) * dx2 / dy2 + x2;
outer.x = XDoubleToFixed (mx);
outer.y = XDoubleToFixed (my);
_cairo_polygon_add_edge (&polygon, &in->pt, inpt);
_cairo_polygon_add_edge (&polygon, inpt, &outer);
_cairo_polygon_add_edge (&polygon, &outer, outpt);
_cairo_polygon_add_edge (&polygon, outpt, &in->pt);
status = cairo_traps_tessellate_polygon (stroker->traps,
&polygon,
CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
return status;
}
/* fall through ... */
}
case CAIRO_LINE_JOIN_BEVEL: {
XPointFixed tri[3];
tri[0] = in->pt;
tri[1] = *inpt;
tri[2] = *outpt;
return cairo_traps_tessellate_triangle (stroker->traps, tri);
}
}
}
static cairo_status_t
_cairo_stroker_cap (cairo_stroker *stroker, cairo_stroke_face_t *f)
{
cairo_status_t status;
cairo_gstate_t *gstate = stroker->gstate;
if (gstate->line_cap == CAIRO_LINE_CAP_BUTT)
return CAIRO_STATUS_SUCCESS;
switch (gstate->line_cap) {
case CAIRO_LINE_CAP_ROUND: {
int i;
int start, stop;
cairo_slope_fixed_t slope;
XPointFixed tri[3];
cairo_pen_t *pen = &gstate->pen_regular;
slope = f->dev_vector;
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
tri[0] = f->pt;
tri[1] = f->cw;
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
tri[2] = f->pt;
_translate_point (&tri[2], &pen->vertex[i].pt);
cairo_traps_tessellate_triangle (stroker->traps, tri);
tri[1] = tri[2];
}
tri[2] = f->ccw;
return cairo_traps_tessellate_triangle (stroker->traps, tri);
}
case CAIRO_LINE_CAP_SQUARE: {
double dx, dy;
cairo_slope_fixed_t fvector;
XPointFixed occw, ocw;
cairo_polygon_t polygon;
_cairo_polygon_init (&polygon);
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= gstate->line_width / 2.0;
dy *= gstate->line_width / 2.0;
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
fvector.dx = XDoubleToFixed (dx);
fvector.dy = XDoubleToFixed (dy);
occw.x = f->ccw.x + fvector.dx;
occw.y = f->ccw.y + fvector.dy;
ocw.x = f->cw.x + fvector.dx;
ocw.y = f->cw.y + fvector.dy;
_cairo_polygon_add_edge (&polygon, &f->cw, &ocw);
_cairo_polygon_add_edge (&polygon, &ocw, &occw);
_cairo_polygon_add_edge (&polygon, &occw, &f->ccw);
_cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw);
status = cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
return status;
}
case CAIRO_LINE_CAP_BUTT:
default:
return CAIRO_STATUS_SUCCESS;
}
}
static void
_compute_face (XPointFixed *pt, cairo_slope_fixed_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
{
double mag, tmp;
double dx, dy;
XPointDouble usr_vector;
XPointFixed offset_ccw, offset_cw;
dx = XFixedToDouble (slope->dx);
dy = XFixedToDouble (slope->dy);
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
mag = sqrt (dx * dx + dy * dy);
if (mag == 0) {
/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
return;
}
dx /= mag;
dy /= mag;
usr_vector.x = dx;
usr_vector.y = dy;
tmp = dx;
dx = - dy * (gstate->line_width / 2.0);
dy = tmp * (gstate->line_width / 2.0);
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
offset_ccw.x = XDoubleToFixed (dx);
offset_ccw.y = XDoubleToFixed (dy);
offset_cw.x = -offset_ccw.x;
offset_cw.y = -offset_ccw.y;
face->ccw = *pt;
_translate_point (&face->ccw, &offset_ccw);
face->pt = *pt;
face->cw = *pt;
_translate_point (&face->cw, &offset_cw);
face->usr_vector.x = usr_vector.x;
face->usr_vector.y = usr_vector.y;
face->dev_vector = *slope;
}
static cairo_status_t
_cairo_stroker_add_sub_edge (cairo_stroker *stroker, XPointFixed *p1, XPointFixed *p2,
cairo_stroke_face_t *start, cairo_stroke_face_t *end)
{
cairo_gstate_t *gstate = stroker->gstate;
XPointFixed quad[4];
cairo_slope_fixed_t slope;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in _compute_face). The key behavior is that
degenerate paths should draw as much as possible. */
return CAIRO_STATUS_SUCCESS;
}
_compute_slope (p1, p2, &slope);
_compute_face (p1, &slope, gstate, start);
/* XXX: This could be optimized slightly by not calling
_compute_face again but rather translating the relevant
fields from start. */
_compute_face (p2, &slope, gstate, end);
quad[0] = start->cw;
quad[1] = start->ccw;
quad[2] = end->ccw;
quad[3] = end->cw;
return cairo_traps_tessellate_rectangle (stroker->traps, quad);
}
static cairo_status_t
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_status_t status;
cairo_stroker *stroker = closure;
cairo_stroke_face_t start, end;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in cairo_stroker_add_sub_edge and in _compute_face). The
key behavior is that degenerate paths should draw as much
as possible. */
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &start, &end);
if (status)
return status;
if (stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
return CAIRO_STATUS_SUCCESS;
}
/*
* Dashed lines. Cap each dash end, join around turns when on
*/
static cairo_status_t
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker *stroker = closure;
cairo_gstate_t *gstate = stroker->gstate;
double mag, remain, tmp;
double dx, dy;
double dx2, dy2;
XPointFixed fd1, fd2;
int first = 1;
cairo_stroke_face_t sub_start, sub_end;
dx = XFixedToDouble (p2->x - p1->x);
dy = XFixedToDouble (p2->y - p1->y);
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
mag = sqrt (dx *dx + dy * dy);
remain = mag;
fd1 = *p1;
while (remain) {
tmp = stroker->dash_remain;
if (tmp > remain)
tmp = remain;
remain -= tmp;
dx2 = dx * (mag - remain)/mag;
dy2 = dy * (mag - remain)/mag;
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
fd2.x = XDoubleToFixed (dx2);
fd2.y = XDoubleToFixed (dy2);
fd2.x += p1->x;
fd2.y += p1->y;
/*
* XXX simplify this case analysis
*/
if (stroker->dash_on) {
status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &sub_start, &sub_end);
if (status)
return status;
if (!first) {
/*
* Not first dash in this segment, cap start
*/
status = _cairo_stroker_cap (stroker, &sub_start);
if (status)
return status;
} else {
/*
* First in this segment, join to any prev, else
* if at start of sub-path, mark position, else
* cap
*/
if (stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start);
if (status)
return status;
} else {
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = sub_start;
} else {
status = _cairo_stroker_cap (stroker, &sub_start);
if (status)
return status;
}
}
}
if (remain) {
/*
* Cap if not at end of segment
*/
status = _cairo_stroker_cap (stroker, &sub_end);
if (status)
return status;
} else {
/*
* Mark previous line face and fix up next time
* through
*/
stroker->prev = sub_end;
stroker->have_prev = 1;
}
} else {
/*
* If starting with off dash, check previous face
* and cap if necessary
*/
if (first) {
if (stroker->have_prev) {
status = _cairo_stroker_cap (stroker, &stroker->prev);
if (status)
return status;
}
}
if (!remain)
stroker->have_prev = 0;
}
_cairo_stroker_step_dash (stroker, tmp);
fd1 = fd2;
first = 0;
}
stroker->is_first = 0;
return status;
}
static cairo_status_t
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker *stroker = closure;
cairo_gstate_t *gstate = stroker->gstate;
cairo_spline_t spline;
cairo_pen_t pen;
cairo_stroke_face_t start, end;
XPointFixed extra_points[4];
status = _cairo_spline_init (&spline, a, b, c, d);
if (status == cairo_int_status_degenerate)
return CAIRO_STATUS_SUCCESS;
status = _cairo_pen_init_copy (&pen, &gstate->pen_regular);
if (status)
goto CLEANUP_SPLINE;
_compute_face (a, &spline.initial_slope, gstate, &start);
_compute_face (d, &spline.final_slope, gstate, &end);
if (stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
extra_points[0] = start.cw;
extra_points[0].x -= start.pt.x;
extra_points[0].y -= start.pt.y;
extra_points[1] = start.ccw;
extra_points[1].x -= start.pt.x;
extra_points[1].y -= start.pt.y;
extra_points[2] = end.cw;
extra_points[2].x -= end.pt.x;
extra_points[2].y -= end.pt.y;
extra_points[3] = end.ccw;
extra_points[3].x -= end.pt.x;
extra_points[3].y -= end.pt.y;
status = _cairo_pen_add_points (&pen, extra_points, 4);
if (status)
goto CLEANUP_PEN;
status = _cairo_pen_stroke_spline (&pen, &spline, gstate->tolerance, stroker->traps);
if (status)
goto CLEANUP_PEN;
CLEANUP_PEN:
_cairo_pen_fini (&pen);
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
return status;
}
static cairo_status_t
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done)
{
cairo_status_t status;
cairo_stroker *stroker = closure;
switch (done) {
case cairo_sub_path_done_join:
if (stroker->have_first && stroker->have_prev) {
status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first);
if (status)
return status;
break;
}
/* fall through... */
case cairo_sub_path_done_cap:
if (stroker->have_first) {
XPointFixed t;
/* The initial cap needs an outward facing vector. Reverse everything */
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
t = stroker->first.cw;
stroker->first.cw = stroker->first.ccw;
stroker->first.ccw = t;
status = _cairo_stroker_cap (stroker, &stroker->first);
if (status)
return status;
}
if (stroker->have_prev) {
status = _cairo_stroker_cap (stroker, &stroker->prev);
if (status)
return status;
}
break;
}
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_stroker_done_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
static const cairo_path_callbacks_t stroker_solid_cb = {
_cairo_stroker_add_edge,
_cairo_stroker_add_spline,
_cairo_stroker_done_sub_path,
_cairo_stroker_done_path
};
static const cairo_path_callbacks_t stroker_dashed_cb = {
_cairo_stroker_add_edge_dashed,
_cairo_stroker_add_spline,
_cairo_stroker_done_sub_path,
_cairo_stroker_done_path
};
const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
cairo_status_t status;
cairo_stroker stroker;
_cairo_stroker_init (&stroker, gstate, traps);
status = _cairo_path_interpret (path,
cairo_path_direction_forward,
callbacks, &stroker);
if (status) {
_cairo_stroker_fini (&stroker);
return status;
}
_cairo_stroker_fini (&stroker);
return CAIRO_STATUS_SUCCESS;
}

398
src/cairo_pen.c Normal file
View file

@ -0,0 +1,398 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
static int
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix);
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen);
static int
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
static int
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
static int
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b);
static cairo_status_t
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_pen_stroke_direction_t dir, cairo_polygon_t *polygon);
cairo_status_t
_cairo_pen_init_empty (cairo_pen_t *pen)
{
pen->radius = 0;
pen->tolerance = 0;
pen->vertex = NULL;
pen->num_vertices = 0;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
{
int i;
cairo_pen_vertex *v;
double dx, dy;
if (pen->num_vertices) {
/* XXX: It would be nice to notice that the pen is already properly constructed.
However, this test would also have to account for possible changes in the transformation
matrix.
if (pen->radius == radius && pen->tolerance == tolerance)
return CAIRO_STATUS_SUCCESS;
*/
_cairo_pen_fini (pen);
}
pen->radius = radius;
pen->tolerance = gstate->tolerance;
pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, &gstate->ctm);
/* number of vertices must be even */
if (pen->num_vertices % 2)
pen->num_vertices++;
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
if (pen->vertex == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
for (i=0; i < pen->num_vertices; i++) {
v = &pen->vertex[i];
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
dx = radius * cos (v->theta);
dy = radius * sin (v->theta);
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
v->pt.x = XDoubleToFixed (dx);
v->pt.y = XDoubleToFixed (dy);
/* Recompute theta in device space */
v->theta = atan2 (v->pt.y, v->pt.x);
if (v->theta < 0)
v->theta += 2 * M_PI;
}
_cairo_pen_compute_slopes (pen);
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_pen_fini (cairo_pen_t *pen)
{
free (pen->vertex);
_cairo_pen_init_empty (pen);
}
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
*pen = *other;
if (pen->num_vertices) {
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
if (pen->vertex == NULL) {
return CAIRO_STATUS_NO_MEMORY;
}
memcpy (pen->vertex, other->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
}
return CAIRO_STATUS_SUCCESS;
}
static int
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b)
{
double diff;
const cairo_pen_vertex *va = a;
const cairo_pen_vertex *vb = b;
diff = va->theta - vb->theta;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
else
return 0;
}
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, XPointFixed *pt, int num_pts)
{
int i, j;
cairo_pen_vertex *v, *v_next, *new_vertex;
pen->num_vertices += num_pts;
new_vertex = realloc (pen->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
if (new_vertex == NULL) {
pen->num_vertices -= num_pts;
return CAIRO_STATUS_NO_MEMORY;
}
pen->vertex = new_vertex;
/* initialize new vertices */
for (i=0; i < num_pts; i++) {
v = &pen->vertex[pen->num_vertices-(i+1)];
v->pt = pt[i];
v->theta = atan2 (v->pt.y, v->pt.x);
if (v->theta < 0)
v->theta += 2 * M_PI;
}
qsort (pen->vertex, pen->num_vertices, sizeof (cairo_pen_vertex), _cairo_pen_vertex_compare_by_theta);
/* eliminate any duplicate vertices */
for (i=0; i < pen->num_vertices - 1; i++ ) {
v = &pen->vertex[i];
v_next = &pen->vertex[i+1];
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
for (j=i+1; j < pen->num_vertices - 1; j++)
pen->vertex[j] = pen->vertex[j+1];
pen->num_vertices--;
/* There may be more of the same duplicate, check again */
i--;
}
}
_cairo_pen_compute_slopes (pen);
return CAIRO_STATUS_SUCCESS;
}
static int
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix)
{
double expansion, theta;
/* The determinant represents the area expansion factor of the
transform. In the worst case, this is entirely in one
dimension, which is what we assume here. */
_cairo_matrix_compute_determinant (matrix, &expansion);
if (tolerance > expansion*radius) {
return 4;
}
theta = acos (1 - tolerance/(expansion * radius));
return ceil (M_PI / theta);
}
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen)
{
int i, i_prev;
cairo_pen_vertex *prev, *v, *next;
for (i=0, i_prev = pen->num_vertices - 1;
i < pen->num_vertices;
i_prev = i++) {
prev = &pen->vertex[i_prev];
v = &pen->vertex[i];
next = &pen->vertex[(i + 1) % pen->num_vertices];
_compute_slope (&prev->pt, &v->pt, &v->slope_cw);
_compute_slope (&v->pt, &next->pt, &v->slope_ccw);
}
}
/* Is a clockwise of b?
*
* NOTE: The strict equality here is not significant in and of itself,
* but there are functions up above that are sensitive to it,
* (cf. _cairo_pen_find_active_cw_vertex_index).
*/
static int
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
{
double a_dx = XFixedToDouble (a->dx);
double a_dy = XFixedToDouble (a->dy);
double b_dx = XFixedToDouble (b->dx);
double b_dy = XFixedToDouble (b->dy);
return b_dy * a_dx > a_dy * b_dx;
}
static int
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
{
return ! _slope_clockwise (a, b);
}
/* Find active pen vertex for clockwise edge of stroke at the given slope.
*
* NOTE: The behavior of this function is sensitive to the sense of
* the inequality within _slope_clockwise/_slope_counter_clockwise.
*
* The issue is that the slope_ccw member of one pen vertex will be
* equivalent to the slope_cw member of the next pen vertex in a
* counterclockwise order. However, for this function, we care
* strongly about which vertex is returned.
*/
cairo_status_t
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
cairo_slope_fixed_t *slope,
int *active)
{
int i;
for (i=0; i < pen->num_vertices; i++) {
if (_slope_clockwise (slope, &pen->vertex[i].slope_ccw)
&& _slope_counter_clockwise (slope, &pen->vertex[i].slope_cw))
break;
}
*active = i;
return CAIRO_STATUS_SUCCESS;
}
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
*
* NOTE: The behavior of this function is sensitive to the sense of
* the inequality within _slope_clockwise/_slope_counter_clockwise.
*/
cairo_status_t
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
cairo_slope_fixed_t *slope,
int *active)
{
int i;
cairo_slope_fixed_t slope_reverse;
slope_reverse = *slope;
slope_reverse.dx = -slope_reverse.dx;
slope_reverse.dy = -slope_reverse.dy;
for (i=pen->num_vertices-1; i >= 0; i--) {
if (_slope_counter_clockwise (&pen->vertex[i].slope_ccw, &slope_reverse)
&& _slope_clockwise (&pen->vertex[i].slope_cw, &slope_reverse))
break;
}
*active = i;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
cairo_spline_t *spline,
cairo_pen_stroke_direction_t dir,
cairo_polygon_t *polygon)
{
int i;
cairo_status_t status;
int start, stop, step;
int active = 0;
XPointFixed hull_pt;
cairo_slope_fixed_t slope, initial_slope, final_slope;
XPointFixed *pt = spline->pts;
int num_pts = spline->num_pts;
if (dir == cairo_pen_stroke_direction_forward) {
start = 0;
stop = num_pts;
step = 1;
initial_slope = spline->initial_slope;
final_slope = spline->final_slope;
} else {
start = num_pts - 1;
stop = -1;
step = -1;
initial_slope = spline->final_slope;
initial_slope.dx = -initial_slope.dx;
initial_slope.dy = -initial_slope.dy;
final_slope = spline->initial_slope;
final_slope.dx = -final_slope.dx;
final_slope.dy = -final_slope.dy;
}
_cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);
i = start;
while (i != stop) {
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
hull_pt.y = pt[i].y + pen->vertex[active].pt.y;
status = _cairo_polygon_add_point (polygon, &hull_pt);
if (status)
return status;
if (i + step == stop)
slope = final_slope;
else
_compute_slope (&pt[i], &pt[i+step], &slope);
if (_slope_counter_clockwise (&slope, &pen->vertex[active].slope_ccw)) {
if (++active == pen->num_vertices)
active = 0;
} else if (_slope_clockwise (&slope, &pen->vertex[active].slope_cw)) {
if (--active == -1)
active = pen->num_vertices - 1;
} else {
i += step;
}
}
return CAIRO_STATUS_SUCCESS;
}
/* Compute outline of a given spline using the pen.
The trapezoids needed to fill that outline will be added to traps
*/
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t *pen,
cairo_spline_t *spline,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_polygon_t polygon;
_cairo_polygon_init (&polygon);
status = _cairo_spline_decompose (spline, tolerance);
if (status)
return status;
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_forward, &polygon);
if (status)
return status;
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_reverse, &polygon);
if (status)
return status;
_cairo_polygon_close (&polygon);
cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
return CAIRO_STATUS_SUCCESS;
}

175
src/cairo_polygon.c Normal file
View file

@ -0,0 +1,175 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include "cairoint.h"
#define CAIRO_POLYGON_GROWTH_INC 10
/* private functions */
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
static void
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt);
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
polygon->num_edges = 0;
polygon->edges_size = 0;
polygon->edges = NULL;
polygon->first_pt_defined = 0;
polygon->last_pt_defined = 0;
polygon->closed = 0;
}
void
_cairo_polygon_fini (cairo_polygon_t *polygon)
{
if (polygon->edges_size) {
free (polygon->edges);
polygon->edges = NULL;
polygon->edges_size = 0;
polygon->num_edges = 0;
}
polygon->first_pt_defined = 0;
polygon->last_pt_defined = 0;
polygon->closed = 0;
}
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int new_size = polygon->num_edges + additional;
if (new_size <= polygon->edges_size) {
return CAIRO_STATUS_SUCCESS;
}
polygon->edges_size = new_size;
new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t));
if (new_edges == NULL) {
polygon->edges_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
polygon->edges = new_edges;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt)
{
polygon->last_pt = *pt;
polygon->last_pt_defined = 1;
}
cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, XPointFixed *p1, XPointFixed *p2)
{
cairo_status_t status;
cairo_edge_t *edge;
if (! polygon->first_pt_defined) {
polygon->first_pt = *p1;
polygon->first_pt_defined = 1;
polygon->closed = 0;
}
/* drop horizontal edges */
if (p1->y == p2->y) {
goto DONE;
}
if (polygon->num_edges >= polygon->edges_size) {
status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
if (status) {
return status;
}
}
edge = &polygon->edges[polygon->num_edges];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
edge->clockWise = True;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
edge->clockWise = False;
}
polygon->num_edges++;
DONE:
_cairo_polygon_set_last_point (polygon, p2);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_polygon_add_point (cairo_polygon_t *polygon, XPointFixed *pt)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (polygon->last_pt_defined) {
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, pt);
} else {
_cairo_polygon_set_last_point (polygon, pt);
}
return status;
}
cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon)
{
cairo_status_t status;
if (polygon->closed == 0 && polygon->last_pt_defined) {
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, &polygon->first_pt);
if (status)
return status;
polygon->closed = 1;
polygon->first_pt_defined = 0;
}
return CAIRO_STATUS_SUCCESS;
}

271
src/cairo_spline.c Normal file
View file

@ -0,0 +1,271 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include "cairoint.h"
static cairo_status_t
_cairo_spline_grow_by (cairo_spline_t *spline, int additional);
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt);
static void
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result);
static void
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2);
static double
_cairo_spline_error_squared (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
#define CAIRO_SPLINE_GROWTH_INC 100
cairo_int_status
_cairo_spline_init (cairo_spline_t *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
spline->a = *a;
spline->b = *b;
spline->c = *c;
spline->d = *d;
if (a->x != b->x || a->y != b->y) {
_compute_slope (&spline->a, &spline->b, &spline->initial_slope);
} else if (a->x != c->x || a->y != c->y) {
_compute_slope (&spline->a, &spline->c, &spline->initial_slope);
} else if (a->x != d->x || a->y != d->y) {
_compute_slope (&spline->a, &spline->d, &spline->initial_slope);
} else {
return cairo_int_status_degenerate;
}
if (c->x != d->x || c->y != d->y) {
_compute_slope (&spline->c, &spline->d, &spline->final_slope);
} else if (b->x != d->x || b->y != d->y) {
_compute_slope (&spline->b, &spline->d, &spline->final_slope);
} else {
_compute_slope (&spline->a, &spline->d, &spline->final_slope);
}
spline->num_pts = 0;
spline->pts_size = 0;
spline->pts = NULL;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_spline_fini (cairo_spline_t *spline)
{
spline->num_pts = 0;
spline->pts_size = 0;
free (spline->pts);
spline->pts = NULL;
}
static cairo_status_t
_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
{
XPointFixed *new_pts;
int old_size = spline->pts_size;
int new_size = spline->num_pts + additional;
if (new_size <= spline->pts_size)
return CAIRO_STATUS_SUCCESS;
spline->pts_size = new_size;
new_pts = realloc (spline->pts, spline->pts_size * sizeof (XPointFixed));
if (new_pts == NULL) {
spline->pts_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
spline->pts = new_pts;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt)
{
cairo_status_t status;
if (spline->num_pts >= spline->pts_size) {
status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
if (status)
return status;
}
spline->pts[spline->num_pts] = *pt;
spline->num_pts++;
return CAIRO_STATUS_SUCCESS;
}
static void
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result)
{
result->x = a->x + ((b->x - a->x) >> 1);
result->y = a->y + ((b->y - a->y) >> 1);
}
static void
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2)
{
XPointFixed ab, bc, cd;
XPointFixed abbc, bccd;
XPointFixed final;
_lerp_half (&spline->a, &spline->b, &ab);
_lerp_half (&spline->b, &spline->c, &bc);
_lerp_half (&spline->c, &spline->d, &cd);
_lerp_half (&ab, &bc, &abbc);
_lerp_half (&bc, &cd, &bccd);
_lerp_half (&abbc, &bccd, &final);
s1->a = spline->a;
s1->b = ab;
s1->c = abbc;
s1->d = final;
s2->a = final;
s2->b = bccd;
s2->c = cd;
s2->d = spline->d;
}
static double
_PointDistanceSquaredToPoint (XPointFixed *a, XPointFixed *b)
{
double dx = XFixedToDouble (b->x - a->x);
double dy = XFixedToDouble (b->y - a->y);
return dx*dx + dy*dy;
}
static double
_PointDistanceSquaredToSegment (XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
{
double u;
double dx, dy;
double pdx, pdy;
XPointFixed px;
/* intersection point (px):
px = p1 + u(p2 - p1)
(p - px) . (p2 - p1) = 0
Thus:
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
*/
dx = XFixedToDouble (p2->x - p1->x);
dy = XFixedToDouble (p2->y - p1->y);
if (dx == 0 && dy == 0)
return _PointDistanceSquaredToPoint (p, p1);
pdx = XFixedToDouble (p->x - p1->x);
pdy = XFixedToDouble (p->y - p1->y);
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
if (u <= 0)
return _PointDistanceSquaredToPoint (p, p1);
else if (u >= 1)
return _PointDistanceSquaredToPoint (p, p2);
px.x = p1->x + u * (p2->x - p1->x);
px.y = p1->y + u * (p2->y - p1->y);
return _PointDistanceSquaredToPoint (p, &px);
}
/* Return an upper bound on the error (squared) that could result from approximating
a spline as a line segment connecting the two endpoints */
static double
_cairo_spline_error_squared (cairo_spline_t *spline)
{
double berr, cerr;
berr = _PointDistanceSquaredToSegment (&spline->b, &spline->a, &spline->d);
cerr = _PointDistanceSquaredToSegment (&spline->c, &spline->a, &spline->d);
if (berr > cerr)
return berr;
else
return cerr;
}
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result)
{
cairo_status_t status;
cairo_spline_t s1, s2;
if (_cairo_spline_error_squared (spline) < tolerance_squared) {
return _cairo_spline_add_point (result, &spline->a);
}
_de_casteljau (spline, &s1, &s2);
status = _cairo_spline_decompose_into (&s1, tolerance_squared, result);
if (status)
return status;
status = _cairo_spline_decompose_into (&s2, tolerance_squared, result);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
{
cairo_status_t status;
if (spline->pts_size) {
_cairo_spline_fini (spline);
}
status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline);
if (status)
return status;
status = _cairo_spline_add_point (spline, &spline->d);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}

391
src/cairo_surface.c Normal file
View file

@ -0,0 +1,391 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <stdlib.h>
#include "cairoint.h"
cairo_surface_t *
cairo_surface_create_for_drawable (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL)
return NULL;
surface->dpy = dpy;
surface->image_data = NULL;
surface->xc_surface = XcSurfaceCreateForDrawable (dpy, drawable, visual, format, colormap);
if (surface->xc_surface == NULL) {
free (surface);
return NULL;
}
/* XXX: We should really get this value from somewhere like Xft.dpy */
surface->ppm = 3780;
surface->ref_count = 1;
return surface;
}
/* XXX: These definitions are 100% bogus. The problem that needs to be
fixed is that Ic needs to export a real API for passing in
formats. */
#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
((type) << 16) | \
((a) << 12) | \
((r) << 8) | \
((g) << 4) | \
((b)))
/*
* gray/color formats use a visual index instead of argb
*/
#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \
((type) << 16) | \
((vi)))
#define PICT_TYPE_A 1
#define PICT_TYPE_ARGB 2
#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2)
/* 32bpp formats */
#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8)
#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8)
#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0)
#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0)
static int
cairo_format_bpp (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_A1:
return 1;
break;
case CAIRO_FORMAT_A8:
return 8;
break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_ARGB32:
default:
return 32;
break;
}
}
cairo_surface_t *
cairo_surface_create_for_image (char *data,
cairo_format_t format,
int width,
int height,
int stride)
{
cairo_surface_t *surface;
IcFormat icformat;
IcImage *image;
int bpp;
/* XXX: This all needs to change, (but IcFormatInit interface needs to change first) */
switch (format) {
case CAIRO_FORMAT_ARGB32:
IcFormatInit (&icformat, PICT_a8r8g8b8);
bpp = 32;
break;
case CAIRO_FORMAT_RGB24:
IcFormatInit (&icformat, PICT_x8r8g8b8);
bpp = 32;
break;
case CAIRO_FORMAT_A8:
IcFormatInit (&icformat, PICT_a8);
bpp = 8;
break;
case CAIRO_FORMAT_A1:
IcFormatInit (&icformat, PICT_a1);
bpp = 1;
break;
default:
return NULL;
}
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL)
return NULL;
surface->dpy = NULL;
surface->image_data = NULL;
image = IcImageCreateForData ((IcBits *) data, &icformat, width, height, cairo_format_bpp (format), stride);
if (image == NULL) {
free (surface);
return NULL;
}
surface->xc_surface = XcSurfaceCreateForIcImage (image);
if (surface->xc_surface == NULL) {
IcImageDestroy (image);
free (surface);
return NULL;
}
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
return surface;
}
cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
int width,
int height)
{
return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
}
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_A1:
return 1;
case CAIRO_FORMAT_A8:
return 8;
case CAIRO_FORMAT_RGB24:
return 24;
case CAIRO_FORMAT_ARGB32:
default:
return 32;
}
}
cairo_surface_t *
cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
int width,
int height,
double red,
double green,
double blue,
double alpha)
{
cairo_surface_t *surface = NULL;
cairo_color_t color;
/* XXX: create_similar should perhaps move down to Xc, (then we
could drop xrsurface->dpy as well) */
if (other->dpy) {
Display *dpy = other->dpy;
int scr = DefaultScreen (dpy);
Pixmap pix = XCreatePixmap (dpy,
DefaultRootWindow (dpy),
width, height,
_CAIRO_FORMAT_DEPTH (format));
surface = cairo_surface_create_for_drawable (dpy, pix,
NULL,
format,
DefaultColormap (dpy, scr));
/* XXX: huh? This should be fine since we already created a picture
from the pixmap, right?? (Somehow, it seems to be causing some
breakage).
XFreePixmap (surface->dpy, pix);
*/
} else {
char *data;
int stride;
stride = ((width * cairo_format_bpp (format)) + 7) >> 3;
data = malloc (stride * height);
if (data == NULL)
return NULL;
surface = cairo_surface_create_for_image (data, format,
width, height, stride);
/* lodge data in the surface structure to be freed with the surface */
surface->image_data = data;
}
/* XXX: Initializing the color in this way assumes
non-pre-multiplied alpha. I'm not sure that that's what I want
to do or not. */
_cairo_color_init (&color);
_cairo_color_set_rgb (&color, red, green, blue);
_cairo_color_set_alpha (&color, alpha);
_cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SRC, &color, 0, 0, width, height);
return surface;
}
void
_cairo_surface_reference (cairo_surface_t *surface)
{
if (surface == NULL)
return;
surface->ref_count++;
}
void
cairo_surface_destroy (cairo_surface_t *surface)
{
if (surface == NULL)
return;
surface->ref_count--;
if (surface->ref_count)
return;
surface->dpy = 0;
XcSurfaceDestroy (surface->xc_surface);
surface->xc_surface = NULL;
if (surface->image_data)
free (surface->image_data);
surface->image_data = NULL;
free (surface);
}
cairo_status_t
cairo_surface_put_image (cairo_surface_t *surface,
char *data,
int width,
int height,
int stride)
{
XcSurfacePutImage (surface->xc_surface, data,
width, height, stride);
return CAIRO_STATUS_SUCCESS;
}
/* XXX: Symmetry demands an cairo_surface_get_image as well */
/* XXX: We may want to move to projective matrices at some point. If
nothing else, that would eliminate the two different transform data
structures we have here. */
cairo_status_t
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
{
XTransform xtransform;
xtransform.matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
xtransform.matrix[0][1] = XDoubleToFixed (matrix->m[1][0]);
xtransform.matrix[0][2] = XDoubleToFixed (matrix->m[2][0]);
xtransform.matrix[1][0] = XDoubleToFixed (matrix->m[0][1]);
xtransform.matrix[1][1] = XDoubleToFixed (matrix->m[1][1]);
xtransform.matrix[1][2] = XDoubleToFixed (matrix->m[2][1]);
xtransform.matrix[2][0] = 0;
xtransform.matrix[2][1] = 0;
xtransform.matrix[2][2] = XDoubleToFixed (1);
XcSurfaceSetTransform (surface->xc_surface,
&xtransform);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
{
XTransform xtransform;
XcSurfaceGetTransform (surface->xc_surface, &xtransform);
matrix->m[0][0] = XFixedToDouble (xtransform.matrix[0][0]);
matrix->m[1][0] = XFixedToDouble (xtransform.matrix[0][1]);
matrix->m[2][0] = XFixedToDouble (xtransform.matrix[0][2]);
matrix->m[0][1] = XFixedToDouble (xtransform.matrix[1][0]);
matrix->m[1][1] = XFixedToDouble (xtransform.matrix[1][1]);
matrix->m[2][1] = XFixedToDouble (xtransform.matrix[1][2]);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
{
XcSurfaceSetFilter (surface->xc_surface, filter);
return CAIRO_STATUS_SUCCESS;
}
/* XXX: The Xc version of this function isn't quite working yet
cairo_status_t
cairo_surface_set_clip_region (cairo_surface_t *surface, Region region)
{
XcSurfaceSetClipRegion (surface->xc_surface, region);
return CAIRO_STATUS_SUCCESS;
}
*/
cairo_status_t
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
{
XcSurfaceSetRepeat (surface->xc_surface, repeat);
return CAIRO_STATUS_SUCCESS;
}
/* XXX: This function is going away, right? */
Picture
_cairo_surface_get_picture (cairo_surface_t *surface)
{
return XcSurfaceGetPicture (surface->xc_surface);
}
void
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
cairo_color_t *color,
int x,
int y,
int width,
int height)
{
XcFillRectangle (operator,
surface->xc_surface,
&color->xc_color,
x, y,
width, height);
}

593
src/cairo_traps.c Normal file
View file

@ -0,0 +1,593 @@
/*
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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.
*
* 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
*/
#include "cairoint.h"
#define CAIRO_TRAPS_GROWTH_INC 10
/* private functions */
static cairo_status_t
cairo_traps_grow_by (cairo_traps_t *traps, int additional);
cairo_status_t
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
XLineFixed left, XLineFixed right);
cairo_status_t
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
XPointFixed left_p1, XPointFixed left_p2,
XPointFixed right_p1, XPointFixed right_p2);
static int
_compare_point_fixed_by_y (const void *av, const void *bv);
static int
_compare_cairo_edge_by_top (const void *av, const void *bv);
static XFixed
_compute_x (XLineFixed *line, XFixed y);
static double
_compute_inverse_slope (XLineFixed *l);
static double
_compute_x_intercept (XLineFixed *l, double inverse_slope);
static XFixed
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
void
cairo_traps_init (cairo_traps_t *traps)
{
traps->num_xtraps = 0;
traps->xtraps_size = 0;
traps->xtraps = NULL;
}
void
cairo_traps_fini (cairo_traps_t *traps)
{
if (traps->xtraps_size) {
free (traps->xtraps);
traps->xtraps = NULL;
traps->xtraps_size = 0;
traps->num_xtraps = 0;
}
}
cairo_status_t
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
XLineFixed left, XLineFixed right)
{
cairo_status_t status;
XTrapezoid *trap;
if (top == bottom) {
return CAIRO_STATUS_SUCCESS;
}
if (traps->num_xtraps >= traps->xtraps_size) {
status = cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC);
if (status)
return status;
}
trap = &traps->xtraps[traps->num_xtraps];
trap->top = top;
trap->bottom = bottom;
trap->left = left;
trap->right = right;
traps->num_xtraps++;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
XPointFixed left_p1, XPointFixed left_p2,
XPointFixed right_p1, XPointFixed right_p2)
{
XLineFixed left;
XLineFixed right;
left.p1 = left_p1;
left.p2 = left_p2;
right.p1 = right_p1;
right.p2 = right_p2;
return cairo_traps_add_trap (traps, top, bottom, left, right);
}
static cairo_status_t
cairo_traps_grow_by (cairo_traps_t *traps, int additional)
{
XTrapezoid *new_xtraps;
int old_size = traps->xtraps_size;
int new_size = traps->num_xtraps + additional;
if (new_size <= traps->xtraps_size) {
return CAIRO_STATUS_SUCCESS;
}
traps->xtraps_size = new_size;
new_xtraps = realloc (traps->xtraps, traps->xtraps_size * sizeof (XTrapezoid));
if (new_xtraps == NULL) {
traps->xtraps_size = old_size;
return CAIRO_STATUS_NO_MEMORY;
}
traps->xtraps = new_xtraps;
return CAIRO_STATUS_SUCCESS;
}
static int
_compare_point_fixed_by_y (const void *av, const void *bv)
{
const XPointFixed *a = av, *b = bv;
int ret = a->y - b->y;
if (ret == 0) {
ret = a->x - b->x;
}
return ret;
}
cairo_status_t
cairo_traps_tessellate_triangle (cairo_traps_t *traps, XPointFixed t[3])
{
cairo_status_t status;
XLineFixed line;
double intersect;
XPointFixed tsort[3];
memcpy (tsort, t, 3 * sizeof (XPointFixed));
qsort (tsort, 3, sizeof (XPointFixed), _compare_point_fixed_by_y);
/* horizontal top edge requires special handling */
if (tsort[0].y == tsort[1].y) {
if (tsort[0].x < tsort[1].x)
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
else
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
return status;
}
line.p1 = tsort[0];
line.p2 = tsort[1];
intersect = _compute_x (&line, tsort[2].y);
if (intersect < tsort[2].x) {
status = cairo_traps_add_trap_from_points (traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[1],
tsort[0], tsort[2]);
if (status)
return status;
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[1], tsort[2],
tsort[0], tsort[2]);
if (status)
return status;
} else {
status = cairo_traps_add_trap_from_points (traps,
tsort[0].y, tsort[1].y,
tsort[0], tsort[2],
tsort[0], tsort[1]);
if (status)
return status;
status = cairo_traps_add_trap_from_points (traps,
tsort[1].y, tsort[2].y,
tsort[0], tsort[2],
tsort[1], tsort[2]);
if (status)
return status;
}
return CAIRO_STATUS_SUCCESS;
}
/* Warning: This function reorders the elements of the array provided. */
cairo_status_t
cairo_traps_tessellate_rectangle (cairo_traps_t *traps, XPointFixed q[4])
{
cairo_status_t status;
qsort (q, 4, sizeof (XPointFixed), _compare_point_fixed_by_y);
if (q[1].x > q[2].x) {
status = cairo_traps_add_trap_from_points (traps,
q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
if (status)
return status;
status = cairo_traps_add_trap_from_points (traps,
q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
if (status)
return status;
status = cairo_traps_add_trap_from_points (traps,
q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
if (status)
return status;
} else {
status = cairo_traps_add_trap_from_points (traps,
q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
if (status)
return status;
status = cairo_traps_add_trap_from_points (traps,
q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
if (status)
return status;
status = cairo_traps_add_trap_from_points (traps,
q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
if (status)
return status;
}
return CAIRO_STATUS_SUCCESS;
}
static int
_compare_cairo_edge_by_top (const void *av, const void *bv)
{
const cairo_edge_t *a = av, *b = bv;
int ret;
ret = a->edge.p1.y - b->edge.p1.y;
if (ret == 0)
ret = a->edge.p1.x - b->edge.p1.x;
return ret;
}
/* Return value is:
> 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
== 0 if slope (a) == slope (b)
< 0 if a is "counter-clockwise" from b
*/
static int
_compare_cairo_edge_by_slope (const void *av, const void *bv)
{
const cairo_edge_t *a = av, *b = bv;
double a_dx = XFixedToDouble (a->edge.p2.x - a->edge.p1.x);
double a_dy = XFixedToDouble (a->edge.p2.y - a->edge.p1.y);
double b_dx = XFixedToDouble (b->edge.p2.x - b->edge.p1.x);
double b_dy = XFixedToDouble (b->edge.p2.y - b->edge.p1.y);
return b_dy * a_dx - a_dy * b_dx;
}
static int
_compare_cairo_edge_by_current_xthen_slope (const void *av, const void *bv)
{
const cairo_edge_t *a = av, *b = bv;
int ret;
ret = a->current_x - b->current_x;
if (ret == 0)
ret = _compare_cairo_edge_by_slope (a, b);
return ret;
}
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
for horizontal lines. Now, we "know" that when we are tessellating
polygons that the polygon data structure discards all horizontal
edges, but there's nothing here to guarantee that. I suggest the
following:
A) Move all of the polygon tessellation code out of xrtraps.c and
into xrpoly.c, (in order to be in the same module as the code
discarding horizontal lines).
OR
B) Re-implement the line intersection in a way that avoids all
division by zero. Here's one approach. The only disadvantage
might be that that there are not meaningful names for all of the
sub-computations -- just a bunch of determinants. I haven't
looked at complexity, (both are probably similar and it probably
doesn't matter much anyway).
static double
_det (double a, double b, double c, double d)
{
return a * d - b * c;
}
static int
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
{
double dx1 = XFixedToDouble (l1->p1.x - l1->p2.x);
double dy1 = XFixedToDouble (l1->p1.y - l1->p2.y);
double dx2 = XFixedToDouble (l2->p1.x - l2->p2.x);
double dy2 = XFixedToDouble (l2->p1.y - l2->p2.y);
double l1_det, l2_det;
double den_det = _det (dx1, dy1, dx2, dy2);
if (den_det == 0)
return 0;
l1_det = _det (l1->p1.x, l1->p1.y,
l1->p2.x, l1->p2.y);
l2_det = _det (l2->p1.x, l2->p1.y,
l2->p2.x, l2->p2.y);
*y_intersection = _det (l1_det, dy1,
l2_det, dy2) / den_det;
return 1;
}
*/
static XFixed
_compute_x (XLineFixed *line, XFixed y)
{
XFixed dx = line->p2.x - line->p1.x;
double ex = (double) (y - line->p1.y) * (double) dx;
XFixed dy = line->p2.y - line->p1.y;
return line->p1.x + (ex / dy);
}
static double
_compute_inverse_slope (XLineFixed *l)
{
return (XFixedToDouble (l->p2.x - l->p1.x) /
XFixedToDouble (l->p2.y - l->p1.y));
}
static double
_compute_x_intercept (XLineFixed *l, double inverse_slope)
{
return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y);
}
static int
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
{
/*
* x = m1y + b1
* x = m2y + b2
* m1y + b1 = m2y + b2
* y * (m1 - m2) = b2 - b1
* y = (b2 - b1) / (m1 - m2)
*/
double m1 = _compute_inverse_slope (l1);
double b1 = _compute_x_intercept (l1, m1);
double m2 = _compute_inverse_slope (l2);
double b2 = _compute_x_intercept (l2, m2);
if (m1 == m2)
return 0;
*y_intersection = XDoubleToFixed ((b2 - b1) / (m1 - m2));
return 1;
}
static void
_SortEdgeList (cairo_edge_t **active)
{
cairo_edge_t *e, *en, *next;
/* sort active list */
for (e = *active; e; e = next)
{
next = e->next;
/*
* Find one later in the list that belongs before the
* current one
*/
for (en = next; en; en = en->next)
{
if (_compare_cairo_edge_by_current_xthen_slope (e, en) > 0)
{
/*
* insert en before e
*
* extract en
*/
en->prev->next = en->next;
if (en->next)
en->next->prev = en->prev;
/*
* insert en
*/
if (e->prev)
e->prev->next = en;
else
*active = en;
en->prev = e->prev;
e->prev = en;
en->next = e;
/*
* start over at en
*/
next = en;
break;
}
}
}
}
/* The algorithm here is pretty simple:
inactive = [edges]
y = min_p1_y (inactive)
while (num_active || num_inactive) {
active = all edges containing y
next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )
fill_traps (active, y, next_y, fill_rule)
y = next_y
}
The invariants that hold during fill_traps are:
All edges in active contain both y and next_y
No edges in active intersect within y and next_y
These invariants mean that fill_traps is as simple as sorting the
active edges, forming a trapezoid between each adjacent pair. Then,
either the even-odd or winding rule is used to determine whether to
emit each of these trapezoids.
Warning: This function reorders the edges of the polygon provided.
*/
cairo_status_t
cairo_traps_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
int inactive;
cairo_edge_t *active;
cairo_edge_t *e, *en, *next;
XFixed y, next_y, intersect;
int in_out, num_edges = poly->num_edges;
cairo_edge_t *edges = poly->edges;
if (num_edges == 0)
return CAIRO_STATUS_SUCCESS;
qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
y = edges[0].edge.p1.y;
active = 0;
inactive = 0;
while (active || inactive < num_edges)
{
for (e = active; e; e = e->next) {
e->current_x = _compute_x (&e->edge, y);
}
/* insert new active edges into list */
while (inactive < num_edges)
{
e = &edges[inactive];
if (e->edge.p1.y > y)
break;
/* move this edge into the active list */
inactive++;
e->current_x = _compute_x (&e->edge, y);
/* insert e at head of list */
e->next = active;
e->prev = NULL;
if (active)
active->prev = e;
active = e;
}
_SortEdgeList (&active);
/* find next inflection point */
if (active)
next_y = active->edge.p2.y;
else
next_y = edges[inactive].edge.p1.y;
for (e = active; e; e = en)
{
en = e->next;
if (e->edge.p2.y < next_y)
next_y = e->edge.p2.y;
/* check intersect */
if (en && e->current_x != en->current_x)
{
if (_lines_intersect (&e->edge, &en->edge, &intersect))
if (intersect > y) {
/* Need to guarantee that we get all the way past
the intersection point so that the edges sort
properly next time through the loop. */
if (_compute_x (&e->edge, intersect) < _compute_x (&en->edge, intersect))
intersect++;
if (intersect < next_y)
next_y = intersect;
}
}
}
/* check next inactive point */
if (inactive < num_edges && edges[inactive].edge.p1.y < next_y)
next_y = edges[inactive].edge.p1.y;
/* walk the list generating trapezoids */
in_out = 0;
for (e = active; e && (en = e->next); e = e->next)
{
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
if (e->clockWise) {
in_out++;
} else {
in_out--;
}
if (in_out == 0) {
continue;
}
} else {
in_out++;
if (in_out % 2 == 0) {
continue;
}
}
status = cairo_traps_add_trap (traps, y, next_y, e->edge, en->edge);
if (status)
return status;
}
/* delete inactive edges from list */
for (e = active; e; e = next)
{
next = e->next;
if (e->edge.p2.y <= next_y)
{
if (e->prev)
e->prev->next = e->next;
else
active = e->next;
if (e->next)
e->next->prev = e->prev;
}
}
y = next_y;
}
return CAIRO_STATUS_SUCCESS;
}

710
src/cairoint.h Normal file
View file

@ -0,0 +1,710 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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.
*
* Author: Carl D. Worth <cworth@isi.edu>
*/
/*
* These definitions are solely for use by the implementation of Cairo
* and constitute no kind of standard. If you need any of these
* functions, please drop me a note. Either the library needs new
* functionality, or there's a way to do what you need using the
* existing published interfaces. cworth@isi.edu
*/
#ifndef _CAIROINT_H_
#define _CAIROINT_H_
#include <math.h>
#include <X11/Xlibint.h>
#include <X11/Xft/Xft.h>
#include "cairo.h"
#ifndef __GCC__
#define __attribute__(x)
#endif
/* Sure wish C had a real enum type so that this would be distinct
from cairo_status_t. Oh well, without that, I'll use this bogus 1000
offset */
typedef enum _cairo_int_status {
cairo_int_status_degenerate = 1000
} cairo_int_status;
typedef enum _cairo_path_op {
cairo_path_op_move_to = 0,
cairo_path_op_line_to = 1,
cairo_path_op_curve_to = 2,
cairo_path_op_close_path = 3
} __attribute__ ((packed)) cairo_path_op; /* Don't want 32 bits if we can avoid it. */
typedef enum _cairo_path_direction {
cairo_path_direction_forward,
cairo_path_direction_reverse
} cairo_path_direction;
typedef enum _cairo_sub_path_done {
cairo_sub_path_done_cap,
cairo_sub_path_done_join
} cairo_sub_path_done;
typedef struct cairo_path_callbacks {
cairo_status_t (*AddEdge) (void *closure, XPointFixed *p1, XPointFixed *p2);
cairo_status_t (*AddSpline) (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
cairo_status_t (*DoneSubPath) (void *closure, cairo_sub_path_done done);
cairo_status_t (*DonePath) (void *closure);
} cairo_path_callbacks_t;
#define CAIRO_PATH_BUF_SZ 64
typedef struct cairo_path_op_buf {
int num_ops;
cairo_path_op op[CAIRO_PATH_BUF_SZ];
struct cairo_path_op_buf *next, *prev;
} cairo_path_op_buf_t;
typedef struct cairo_path_arg_buf {
int num_pts;
XPointFixed pt[CAIRO_PATH_BUF_SZ];
struct cairo_path_arg_buf *next, *prev;
} cairo_path_arg_buf_t;
typedef struct cairo_path {
cairo_path_op_buf_t *op_head;
cairo_path_op_buf_t *op_tail;
cairo_path_arg_buf_t *arg_head;
cairo_path_arg_buf_t *arg_tail;
} cairo_path_t;
typedef struct cairo_edge {
XLineFixed edge;
Bool clockWise;
XFixed current_x;
struct cairo_edge *next, *prev;
} cairo_edge_t;
typedef struct cairo_polygon {
int num_edges;
int edges_size;
cairo_edge_t *edges;
XPointFixed first_pt;
int first_pt_defined;
XPointFixed last_pt;
int last_pt_defined;
int closed;
} cairo_polygon_t;
typedef struct cairo_slope_fixed
{
XFixed dx;
XFixed dy;
} cairo_slope_fixed_t;
typedef struct cairo_spline {
XPointFixed a, b, c, d;
cairo_slope_fixed_t initial_slope;
cairo_slope_fixed_t final_slope;
int num_pts;
int pts_size;
XPointFixed *pts;
} cairo_spline_t;
/* XXX: This can go away once incremental spline tessellation is working */
typedef enum cairo_pen_stroke_direction {
cairo_pen_stroke_direction_forward,
cairo_pen_stroke_direction_reverse
} cairo_pen_stroke_direction_t;
typedef struct _cairo_pen_vertex {
XPointFixed pt;
double theta;
cairo_slope_fixed_t slope_ccw;
cairo_slope_fixed_t slope_cw;
} cairo_pen_vertex;
typedef struct cairo_pen {
double radius;
double tolerance;
int num_vertices;
cairo_pen_vertex *vertex;
} cairo_pen_t;
struct cairo_surface_t {
Display *dpy;
char *image_data;
XcSurface *xc_surface;
double ppm;
unsigned int ref_count;
};
typedef struct cairo_color {
double red;
double green;
double blue;
double alpha;
XcColor xc_color;
} cairo_color_t;
struct cairo_matrix_t {
double m[3][2];
};
typedef struct cairo_traps {
int num_xtraps;
int xtraps_size;
XTrapezoid *xtraps;
} cairo_traps_t;
#define CAIRO_FONT_KEY_DEFAULT "serif"
typedef struct cairo_font {
unsigned char *key;
double scale;
cairo_matrix_t matrix;
Display *dpy;
XftFont *xft_font;
} cairo_font_t;
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
#define CAIRO_GSTATE_FILL_RULE_DEFAULT CAIRO_FILL_RULE_WINDING
#define CAIRO_GSTATE_LINE_WIDTH_DEFAULT 2.0
#define CAIRO_GSTATE_LINE_CAP_DEFAULT CAIRO_LINE_CAP_BUTT
#define CAIRO_GSTATE_LINE_JOIN_DEFAULT CAIRO_LINE_JOIN_MITER
#define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0
/* Need a name distinct from the cairo_clip function */
typedef struct cairo_clip_rec {
int x;
int y;
int width;
int height;
cairo_surface_t *surface;
} cairo_clip_rec_t;
typedef struct cairo_gstate {
cairo_operator_t operator;
double tolerance;
/* stroke style */
double line_width;
cairo_line_cap_t line_cap;
cairo_line_join_t line_join;
double miter_limit;
cairo_fill_rule_t fill_rule;
double *dash;
int num_dashes;
double dash_offset;
cairo_font_t font;
cairo_surface_t *surface;
cairo_surface_t *solid;
cairo_surface_t *pattern;
XPointDouble pattern_offset;
cairo_clip_rec_t clip;
double alpha;
cairo_color_t color;
double ppm;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
cairo_path_t path;
XPointDouble last_move_pt;
XPointDouble current_pt;
int has_current_pt;
cairo_pen_t pen_regular;
struct cairo_gstate *next;
} cairo_gstate_t;
struct cairo {
cairo_gstate_t *gstate;
cairo_status_t status;
};
typedef struct cairo_stroke_face {
XPointFixed ccw;
XPointFixed pt;
XPointFixed cw;
cairo_slope_fixed_t dev_vector;
XPointDouble usr_vector;
} cairo_stroke_face_t;
/* cairo_gstate_t.c */
cairo_gstate_t *
_cairo_gstate_create (void);
void
_cairo_gstate_init (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
void
_cairo_gstate_fini (cairo_gstate_t *gstate);
void
_cairo_gstate_destroy (cairo_gstate_t *gstate);
cairo_gstate_t *
_cairo_gstate_clone (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_begin_group (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_end_group (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_drawable (cairo_gstate_t *gstate, Drawable drawable);
cairo_status_t
_cairo_gstate_set_visual (cairo_gstate_t *gstate, Visual *visual);
cairo_status_t
_cairo_gstate_set_format (cairo_gstate_t *gstate, cairo_format_t format);
cairo_status_t
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface);
cairo_surface_t *
_cairo_gstate_get_target_surface (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern);
cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator);
cairo_operator_t
_cairo_gstate_get_operator (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue);
cairo_status_t
_cairo_gstate_get_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue);
cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
double
_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha);
double
_cairo_gstate_get_alpha (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
double
_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
cairo_line_cap_t
_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
cairo_line_join_t
_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset);
cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
double
_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
cairo_status_t
cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
cairo_status_t
_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
cairo_status_t
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
cairo_status_t
_cairo_gstate_default_matrix (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
cairo_status_t
cairo_gstateransform_point (cairo_gstate_t *gstate, double *x, double *y);
cairo_status_t
cairo_gstateransform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
cairo_status_t
_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y);
cairo_status_t
_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
cairo_status_t
_cairo_gstate_new_path (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y);
cairo_status_t
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y);
cairo_status_t
_cairo_gstate_curve_to (cairo_gstate_t *gstate,
double x1, double y1,
double x2, double y2,
double x3, double y3);
cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
cairo_status_t
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy);
cairo_status_t
_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
cairo_status_t
_cairo_gstate_close_path (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_get_current_point (cairo_gstate_t *gstate, double *x, double *y);
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate);
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate, const char *key);
cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale);
cairo_status_t
cairo_gstateransform_font (cairo_gstate_t *gstate,
double a, double b,
double c, double d);
cairo_status_t
cairo_gstateext_extents (cairo_gstate_t *gstate,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy);
cairo_status_t
_cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8);
cairo_status_t
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
cairo_surface_t *surface,
int width,
int height);
/* cairo_color_t.c */
void
_cairo_color_init (cairo_color_t *color);
void
_cairo_color_fini (cairo_color_t *color);
void
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue);
void
_cairo_color_set_alpha (cairo_color_t *color, double alpha);
/* cairo_font_t.c */
void
_cairo_font_init (cairo_font_t *font);
cairo_status_t
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other);
void
_cairo_font_fini (cairo_font_t *font);
cairo_status_t
_cairo_font_select (cairo_font_t *font, const char *key);
cairo_status_t
_cairo_font_scale (cairo_font_t *font, double scale);
cairo_status_t
cairo_font_transform (cairo_font_t *font,
double a, double b,
double c, double d);
cairo_status_t
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font);
/* cairo_path_t.c */
void
_cairo_path_init (cairo_path_t *path);
cairo_status_t
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other);
void
_cairo_path_fini (cairo_path_t *path);
cairo_status_t
_cairo_path_move_to (cairo_path_t *path, double x, double y);
cairo_status_t
_cairo_path_line_to (cairo_path_t *path, double x, double y);
cairo_status_t
_cairo_path_curve_to (cairo_path_t *path,
double x1, double y1,
double x2, double y2,
double x3, double y3);
cairo_status_t
_cairo_path_close_path (cairo_path_t *path);
cairo_status_t
_cairo_path_interpret (cairo_path_t *path,
cairo_path_direction dir,
const cairo_path_callbacks_t *cb,
void *closure);
cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
/* cairo_path_tfill.c */
cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_path_tstroke.c */
cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_surface_t.c */
void
_cairo_surface_reference (cairo_surface_t *surface);
XcSurface *
_cairo_surface_get_xc_surface (cairo_surface_t *surface);
/* XXX: This function is going away, right? */
Picture
_cairo_surface_get_picture (cairo_surface_t *surface);
void
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
cairo_color_t *color,
int x,
int y,
int width,
int height);
/* cairo_pen_t.c */
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate);
cairo_status_t
_cairo_pen_init_empty (cairo_pen_t *pen);
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other);
void
_cairo_pen_fini (cairo_pen_t *pen);
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, XPointFixed *pt, int num_pts);
cairo_status_t
_cairo_pen_add_points_for_slopes (cairo_pen_t *pen,
XPointFixed *a,
XPointFixed *b,
XPointFixed *c,
XPointFixed *d);
cairo_status_t
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
cairo_slope_fixed_t *slope,
int *active);
cairo_status_t
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
cairo_slope_fixed_t *slope,
int *active);
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t *pen,
cairo_spline_t *spline,
double tolerance,
cairo_traps_t *traps);
/* cairo_polygon_t.c */
void
_cairo_polygon_init (cairo_polygon_t *polygon);
void
_cairo_polygon_fini (cairo_polygon_t *polygon);
cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, XPointFixed *p1, XPointFixed *p2);
cairo_status_t
_cairo_polygon_add_point (cairo_polygon_t *polygon, XPointFixed *pt);
cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon);
/* cairo_spline_t.c */
cairo_int_status
_cairo_spline_init (cairo_spline_t *spline,
XPointFixed *a,
XPointFixed *b,
XPointFixed *c,
XPointFixed *d);
cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
void
_cairo_spline_fini (cairo_spline_t *spline);
/* cairo_matrix_t.c */
void
_cairo_matrix_init (cairo_matrix_t *matrix);
void
_cairo_matrix_fini (cairo_matrix_t *matrix);
cairo_status_t
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
double tx, double ty);
cairo_status_t
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
double sx, double sy);
cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double angle);
cairo_status_t
cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height);
cairo_status_t
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
cairo_status_t
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
/* cairo_traps.c */
void
cairo_traps_init (cairo_traps_t *traps);
void
cairo_traps_fini (cairo_traps_t *traps);
cairo_status_t
cairo_traps_tessellate_triangle (cairo_traps_t *traps, XPointFixed t[3]);
cairo_status_t
cairo_traps_tessellate_rectangle (cairo_traps_t *traps, XPointFixed q[4]);
cairo_status_t
cairo_traps_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule);
/* cairo_misc.c */
void
_compute_slope (XPointFixed *a, XPointFixed *b, cairo_slope_fixed_t *slope);
#endif

654
src/xr.c
View file

@ -1,654 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
#define _XR_CURRENT_GSTATE(xrs) (xrs->stack)
#define XR_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
static void
_XrClipValue(double *value, double min, double max);
XrState *
XrCreate(void)
{
return _XrStateCreate();
}
void
XrDestroy(XrState *xrs)
{
_XrStateDestroy(xrs);
}
void
XrSave(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrStatePush(xrs);
}
void
XrRestore(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrStatePop(xrs);
}
/* XXX: I want to rethink this API
void
XrPushGroup(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrStatePush(xrs);
if (xrs->status)
return;
xrs->status = _XrGStateBeginGroup(_XR_CURRENT_GSTATE(xrs));
}
void
XrPopGroup(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateEndGroup(_XR_CURRENT_GSTATE(xrs));
if (xrs->status)
return;
xrs->status = _XrStatePop(xrs);
}
*/
void
XrSetTargetSurface (XrState *xrs, XrSurface *surface)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetTargetSurface (_XR_CURRENT_GSTATE (xrs), surface);
}
XrSurface *
XrGetTargetSurface (XrState *xrs)
{
return _XrGStateGetTargetSurface (_XR_CURRENT_GSTATE (xrs));
}
void
XrSetTargetDrawable (XrState *xrs,
Display *dpy,
Drawable drawable)
{
XrSurface *surface;
if (xrs->status)
return;
surface = XrSurfaceCreateForDrawable (dpy, drawable,
DefaultVisual (dpy, DefaultScreen (dpy)),
0,
DefaultColormap (dpy, DefaultScreen (dpy)));
if (surface == NULL) {
xrs->status = XrStatusNoMemory;
return;
}
XrSetTargetSurface (xrs, surface);
XrSurfaceDestroy (surface);
}
void
XrSetTargetImage (XrState *xrs,
char *data,
XrFormat format,
int width,
int height,
int stride)
{
XrSurface *surface;
if (xrs->status)
return;
surface = XrSurfaceCreateForImage (data,
format,
width, height, stride);
if (surface == NULL) {
xrs->status = XrStatusNoMemory;
return;
}
XrSetTargetSurface (xrs, surface);
XrSurfaceDestroy (surface);
}
void
XrSetOperator(XrState *xrs, XrOperator op)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetOperator(_XR_CURRENT_GSTATE(xrs), op);
}
XrOperator
XrGetOperator(XrState *xrs)
{
return _XrGStateGetOperator(_XR_CURRENT_GSTATE(xrs));
}
void
XrSetRGBColor(XrState *xrs, double red, double green, double blue)
{
if (xrs->status)
return;
_XrClipValue(&red, 0.0, 1.0);
_XrClipValue(&green, 0.0, 1.0);
_XrClipValue(&blue, 0.0, 1.0);
xrs->status = _XrGStateSetRGBColor(_XR_CURRENT_GSTATE(xrs), red, green, blue);
}
void
XrGetRGBColor(XrState *xrs, double *red, double *green, double *blue)
{
/* XXX: Should we do anything with the return values in the error case? */
if (xrs->status)
return;
xrs->status = _XrGStateGetRGBColor(_XR_CURRENT_GSTATE(xrs), red, green, blue);
}
void
XrSetPattern(XrState *xrs, XrSurface *pattern)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetPattern(_XR_CURRENT_GSTATE(xrs), pattern);
}
void
XrSetTolerance(XrState *xrs, double tolerance)
{
if (xrs->status)
return;
_XrClipValue(&tolerance, XR_TOLERANCE_MINIMUM, tolerance);
xrs->status = _XrGStateSetTolerance(_XR_CURRENT_GSTATE(xrs), tolerance);
}
double
XrGetTolerance(XrState *xrs)
{
return _XrGStateGetTolerance(_XR_CURRENT_GSTATE(xrs));
}
void
XrSetAlpha(XrState *xrs, double alpha)
{
if (xrs->status)
return;
_XrClipValue(&alpha, 0.0, 1.0);
xrs->status = _XrGStateSetAlpha(_XR_CURRENT_GSTATE(xrs), alpha);
}
double
XrGetAlpha(XrState *xrs)
{
return _XrGStateGetAlpha(_XR_CURRENT_GSTATE(xrs));
}
void
XrSetFillRule(XrState *xrs, XrFillRule fill_rule)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetFillRule(_XR_CURRENT_GSTATE(xrs), fill_rule);
}
void
XrSetLineWidth(XrState *xrs, double width)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetLineWidth(_XR_CURRENT_GSTATE(xrs), width);
}
double
XrGetLineWidth(XrState *xrs)
{
return _XrGStateGetLineWidth(_XR_CURRENT_GSTATE(xrs));
}
void
XrSetLineCap(XrState *xrs, XrLineCap line_cap)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetLineCap(_XR_CURRENT_GSTATE(xrs), line_cap);
}
XrLineCap
XrGetLineCap(XrState *xrs)
{
return _XrGStateGetLineCap(_XR_CURRENT_GSTATE(xrs));
}
void
XrSetLineJoin(XrState *xrs, XrLineJoin line_join)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetLineJoin(_XR_CURRENT_GSTATE(xrs), line_join);
}
XrLineJoin
XrGetLineJoin(XrState *xrs)
{
return _XrGStateGetLineJoin(_XR_CURRENT_GSTATE(xrs));
}
void
XrSetDash(XrState *xrs, double *dashes, int ndash, double offset)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetDash(_XR_CURRENT_GSTATE(xrs), dashes, ndash, offset);
}
void
XrSetMiterLimit(XrState *xrs, double limit)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetMiterLimit(_XR_CURRENT_GSTATE(xrs), limit);
}
double
XrGetMiterLimit(XrState *xrs)
{
return _XrGStateGetMiterLimit(_XR_CURRENT_GSTATE(xrs));
}
void
XrTranslate(XrState *xrs, double tx, double ty)
{
if (xrs->status)
return;
xrs->status = _XrGStateTranslate(_XR_CURRENT_GSTATE(xrs), tx, ty);
}
void
XrScale(XrState *xrs, double sx, double sy)
{
if (xrs->status)
return;
xrs->status = _XrGStateScale(_XR_CURRENT_GSTATE(xrs), sx, sy);
}
void
XrRotate(XrState *xrs, double angle)
{
if (xrs->status)
return;
xrs->status = _XrGStateRotate(_XR_CURRENT_GSTATE(xrs), angle);
}
void
XrConcatMatrix(XrState *xrs,
XrMatrix *matrix)
{
if (xrs->status)
return;
xrs->status = _XrGStateConcatMatrix(_XR_CURRENT_GSTATE(xrs), matrix);
}
void
XrSetMatrix(XrState *xrs,
XrMatrix *matrix)
{
if (xrs->status)
return;
xrs->status = _XrGStateSetMatrix(_XR_CURRENT_GSTATE(xrs), matrix);
}
void
XrDefaultMatrix(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateDefaultMatrix(_XR_CURRENT_GSTATE(xrs));
}
void
XrIdentityMatrix(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateIdentityMatrix(_XR_CURRENT_GSTATE(xrs));
}
void
XrTransformPoint (XrState *xrs, double *x, double *y)
{
if (xrs->status)
return;
xrs->status = _XrGStateTransformPoint (_XR_CURRENT_GSTATE (xrs), x, y);
}
void
XrTransformDistance (XrState *xrs, double *dx, double *dy)
{
if (xrs->status)
return;
xrs->status = _XrGStateTransformDistance (_XR_CURRENT_GSTATE (xrs), dx, dy);
}
void
XrInverseTransformPoint (XrState *xrs, double *x, double *y)
{
if (xrs->status)
return;
xrs->status = _XrGStateInverseTransformPoint (_XR_CURRENT_GSTATE (xrs), x, y);
}
void
XrInverseTransformDistance (XrState *xrs, double *dx, double *dy)
{
if (xrs->status)
return;
xrs->status = _XrGStateInverseTransformDistance (_XR_CURRENT_GSTATE (xrs), dx, dy);
}
void
XrNewPath(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateNewPath(_XR_CURRENT_GSTATE(xrs));
}
void
XrMoveTo(XrState *xrs, double x, double y)
{
if (xrs->status)
return;
xrs->status = _XrGStateMoveTo(_XR_CURRENT_GSTATE(xrs), x, y);
}
void
XrLineTo(XrState *xrs, double x, double y)
{
if (xrs->status)
return;
xrs->status = _XrGStateLineTo(_XR_CURRENT_GSTATE(xrs), x, y);
}
void
XrCurveTo(XrState *xrs,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
if (xrs->status)
return;
xrs->status = _XrGStateCurveTo(_XR_CURRENT_GSTATE(xrs),
x1, y1,
x2, y2,
x3, y3);
}
void
XrRelMoveTo(XrState *xrs, double dx, double dy)
{
if (xrs->status)
return;
xrs->status = _XrGStateRelMoveTo(_XR_CURRENT_GSTATE(xrs), dx, dy);
}
void
XrRelLineTo(XrState *xrs, double dx, double dy)
{
if (xrs->status)
return;
xrs->status = _XrGStateRelLineTo(_XR_CURRENT_GSTATE(xrs), dx, dy);
}
void
XrRelCurveTo(XrState *xrs,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3)
{
if (xrs->status)
return;
xrs->status = _XrGStateRelCurveTo(_XR_CURRENT_GSTATE(xrs),
dx1, dy1,
dx2, dy2,
dx3, dy3);
}
void
XrRectangle (XrState *xrs,
double x, double y,
double width, double height)
{
if (xrs->status)
return;
XrMoveTo (xrs, x, y);
XrRelLineTo (xrs, width, 0);
XrRelLineTo (xrs, 0, height);
XrRelLineTo (xrs, -width, 0);
XrClosePath (xrs);
}
void
XrClosePath(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateClosePath(_XR_CURRENT_GSTATE(xrs));
}
void
XrGetCurrentPoint(XrState *xrs, double *x, double *y)
{
/* XXX: Should we do anything with the return values in the error case? */
if (xrs->status)
return;
xrs->status = _XrGStateGetCurrentPoint(_XR_CURRENT_GSTATE(xrs), x, y);
}
void
XrStroke(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateStroke(_XR_CURRENT_GSTATE(xrs));
}
void
XrFill(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateFill(_XR_CURRENT_GSTATE(xrs));
}
void
XrClip(XrState *xrs)
{
if (xrs->status)
return;
xrs->status = _XrGStateClip(_XR_CURRENT_GSTATE(xrs));
}
void
XrSelectFont(XrState *xrs, const char *key)
{
if (xrs->status)
return;
xrs->status = _XrGStateSelectFont(_XR_CURRENT_GSTATE(xrs), key);
}
void
XrScaleFont(XrState *xrs, double scale)
{
if (xrs->status)
return;
xrs->status = _XrGStateScaleFont(_XR_CURRENT_GSTATE(xrs), scale);
}
void
XrTransformFont(XrState *xrs,
double a, double b,
double c, double d)
{
if (xrs->status)
return;
xrs->status = _XrGStateTransformFont(_XR_CURRENT_GSTATE(xrs),
a, b, c, d);
}
void
XrTextExtents(XrState *xrs,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy)
{
if (xrs->status)
return;
xrs->status = _XrGStateTextExtents(_XR_CURRENT_GSTATE(xrs), utf8,
x, y, width, height, dx, dy);
}
void
XrShowText(XrState *xrs, const unsigned char *utf8)
{
if (xrs->status)
return;
xrs->status = _XrGStateShowText(_XR_CURRENT_GSTATE(xrs), utf8);
}
void
XrShowSurface (XrState *xrs,
XrSurface *surface,
int width,
int height)
{
if (xrs->status)
return;
xrs->status = _XrGStateShowSurface (_XR_CURRENT_GSTATE (xrs),
surface, width, height);
}
XrStatus
XrGetStatus(XrState *xrs)
{
return xrs->status;
}
const char *
XrGetStatusString(XrState *xrs)
{
switch (xrs->status) {
case XrStatusSuccess:
return "success";
case XrStatusNoMemory:
return "out of memory";
case XrStatusInvalidRestore:
return "XrRestore without matching XrSave";
case XrStatusInvalidPopGroup:
return "XrPopGroup without matching XrPushGroup";
case XrStatusNoCurrentPoint:
return "no current point defined";
case XrStatusInvalidMatrix:
return "invalid matrix (not invertible)";
}
return "";
}
static void
_XrClipValue(double *value, double min, double max)
{
if (*value < min)
*value = min;
else if (*value > max)
*value = max;
}

View file

@ -1,78 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
static XrColor XR_COLOR_DEFAULT = { 1.0, 1.0, 1.0, 1.0, {0xffff, 0xffff, 0xffff, 0xffff}};
static void
_XrColorComputeXcColor(XrColor *color);
void
_XrColorInit(XrColor *color)
{
*color = XR_COLOR_DEFAULT;
}
void
_XrColorDeinit(XrColor *color)
{
/* Nothing to do here */
}
static void
_XrColorComputeXcColor(XrColor *color)
{
color->xc_color.red = color->red * color->alpha * 0xffff;
color->xc_color.green = color->green * color->alpha * 0xffff;
color->xc_color.blue = color->blue * color->alpha * 0xffff;
color->xc_color.alpha = color->alpha * 0xffff;
}
void
_XrColorSetRGB(XrColor *color, double red, double green, double blue)
{
color->red = red;
color->green = green;
color->blue = blue;
_XrColorComputeXcColor(color);
}
void
_XrColorGetRGB(XrColor *color, double *red, double *green, double *blue)
{
*red = color->red;
*green = color->green;
*blue = color->blue;
}
void
_XrColorSetAlpha(XrColor *color, double alpha)
{
color->alpha = alpha;
_XrColorComputeXcColor(color);
}

View file

@ -1,103 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
void
_XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps)
{
filler->gstate = gstate;
filler->traps = traps;
_XrPolygonInit(&filler->polygon);
}
void
_XrFillerDeinit(XrFiller *filler)
{
_XrPolygonDeinit(&filler->polygon);
}
XrStatus
_XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
return _XrPolygonAddEdge(polygon, p1, p2);
}
XrStatus
_XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
int i;
XrStatus status = XrStatusSuccess;
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
XrGState *gstate = filler->gstate;
XrSpline spline;
status = _XrSplineInit(&spline, a, b, c, d);
if (status == XrIntStatusDegenerate)
return XrStatusSuccess;
_XrSplineDecompose(&spline, gstate->tolerance);
if (status)
goto CLEANUP_SPLINE;
for (i = 0; i < spline.num_pts - 1; i++) {
status = _XrPolygonAddEdge(polygon, &spline.pts[i], &spline.pts[i+1]);
if (status)
goto CLEANUP_SPLINE;
}
CLEANUP_SPLINE:
_XrSplineDeinit(&spline);
return status;
}
XrStatus
_XrFillerDoneSubPath (void *closure, XrSubPathDone done)
{
XrStatus status = XrStatusSuccess;
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
_XrPolygonClose(polygon);
return status;
}
XrStatus
_XrFillerDonePath (void *closure)
{
XrFiller *filler = closure;
return _XrTrapsTessellatePolygon(filler->traps,
&filler->polygon,
filler->gstate->fill_rule);
}

View file

@ -1,169 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "xrint.h"
void
_XrFontInit(XrFont *font)
{
font->key = (unsigned char *) strdup(XR_FONT_KEY_DEFAULT);
font->dpy = NULL;
font->xft_font = NULL;
XrMatrixSetIdentity(&font->matrix);
}
XrStatus
_XrFontInitCopy(XrFont *font, XrFont *other)
{
*font = *other;
if (other->key) {
font->key = (unsigned char *) strdup((char *) other->key);
if (font->key == NULL)
return XrStatusNoMemory;
}
if (other->xft_font) {
font->xft_font = XftFontCopy(other->dpy, other->xft_font);
if (font->xft_font == NULL)
return XrStatusNoMemory;
}
return XrStatusSuccess;
}
void
_XrFontDeinit(XrFont *font)
{
if (font->key)
free(font->key);
font->key = NULL;
_XrMatrixFini(&font->matrix);
if (font->xft_font)
XftFontClose(font->dpy, font->xft_font);
font->xft_font = NULL;
}
XrStatus
_XrFontSelect(XrFont *font, const char *key)
{
if (font->xft_font)
XftFontClose(font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->key)
free(font->key);
font->key = (unsigned char *) strdup((char *) key);
if (font->key == NULL)
return XrStatusNoMemory;
return XrStatusSuccess;
}
XrStatus
_XrFontScale(XrFont *font, double scale)
{
XrMatrixScale(&font->matrix, scale, scale);
return XrStatusSuccess;
}
XrStatus
_XrFontTransform(XrFont *font,
double a, double b,
double c, double d)
{
XrMatrix m;
XrMatrixSetAffine(&m, a, b, c, d, 0, 0);
XrMatrixMultiply (&font->matrix, &m, &font->matrix);
return XrStatusSuccess;
}
XrStatus
_XrFontResolveXftFont(XrFont *font, XrGState *gstate, XftFont **xft_font)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
XrMatrix matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font) {
*xft_font = font->xft_font;
return XrStatusSuccess;
}
pattern = FcNameParse(font->key);
matrix = gstate->ctm;
XrMatrixMultiply (&matrix, &font->matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling? */
_XrMatrixComputeDeterminant (&matrix, &expansion);
font_size = sqrt (expansion);
FcPatternAddDouble (pattern, "pixelsize", font_size);
XrMatrixScale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix(pattern, "matrix", &fc_matrix);
/* XXX: Need to abandon Xft and use Xc instead */
/* When I do that I can throw away these Display pointers */
font->dpy = gstate->surface->dpy;
match = XftFontMatch (font->dpy, DefaultScreen(font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
*xft_font = font->xft_font;
FcPatternDestroy (pattern);
return XrStatusSuccess;
}

File diff suppressed because it is too large Load diff

View file

@ -1,708 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH 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.
*/
/*
* These definitions are solely for use by the implementation of Xr
* and constitute no kind of standard. If you need any of these
* functions, please drop me a note. Either the library needs new
* functionality, or there's a way to do what you need using the
* existing published interfaces. cworth@isi.edu
*/
#ifndef _XRINT_H_
#define _XRINT_H_
#include <math.h>
#include <X11/Xlibint.h>
#include <X11/Xft/Xft.h>
#include "Xr.h"
#ifndef __GCC__
#define __attribute__(x)
#endif
/* Sure wish C had a real enum type so that this would be distinct
from XrStatus. Oh well, without that, I'll use this bogus 1000
offset */
typedef enum _XrIntStatus {
XrIntStatusDegenerate = 1000
} XrIntStatus;
typedef enum _XrPathOp {
XrPathOpMoveTo = 0,
XrPathOpLineTo = 1,
XrPathOpCurveTo = 2,
XrPathOpClosePath = 3
} __attribute__ ((packed)) XrPathOp; /* Don't want 32 bits if we can avoid it. */
typedef enum _XrPathDirection {
XrPathDirectionForward,
XrPathDirectionReverse
} XrPathDirection;
typedef enum _XrSubPathDone {
XrSubPathDoneCap,
XrSubPathDoneJoin
} XrSubPathDone;
typedef struct _XrPathCallbacks {
XrStatus (*AddEdge)(void *closure, XPointFixed *p1, XPointFixed *p2);
XrStatus (*AddSpline)(void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrStatus (*DoneSubPath) (void *closure, XrSubPathDone done);
XrStatus (*DonePath) (void *closure);
} XrPathCallbacks;
#define XR_PATH_BUF_SZ 64
typedef struct _XrPathOpBuf {
int num_ops;
XrPathOp op[XR_PATH_BUF_SZ];
struct _XrPathOpBuf *next, *prev;
} XrPathOpBuf;
typedef struct _XrPathArgBuf {
int num_pts;
XPointFixed pt[XR_PATH_BUF_SZ];
struct _XrPathArgBuf *next, *prev;
} XrPathArgBuf;
typedef struct _XrPath {
XrPathOpBuf *op_head;
XrPathOpBuf *op_tail;
XrPathArgBuf *arg_head;
XrPathArgBuf *arg_tail;
} XrPath;
typedef struct _XrEdge {
XLineFixed edge;
Bool clockWise;
XFixed current_x;
struct _XrEdge *next, *prev;
} XrEdge;
typedef struct _XrPolygon {
int num_edges;
int edges_size;
XrEdge *edges;
XPointFixed first_pt;
int first_pt_defined;
XPointFixed last_pt;
int last_pt_defined;
int closed;
} XrPolygon;
typedef struct _XrSlopeFixed
{
XFixed dx;
XFixed dy;
} XrSlopeFixed;
typedef struct _XrSpline {
XPointFixed a, b, c, d;
XrSlopeFixed initial_slope;
XrSlopeFixed final_slope;
int num_pts;
int pts_size;
XPointFixed *pts;
} XrSpline;
/* XXX: This can go away once incremental spline tessellation is working */
typedef enum _XrPenStrokeDirection {
XrPenStrokeDirectionForward,
XrPenStrokeDirectionReverse
} XrPenStrokeDirection;
typedef struct _XrPenVertex {
XPointFixed pt;
double theta;
XrSlopeFixed slope_ccw;
XrSlopeFixed slope_cw;
} XrPenVertex;
typedef struct _XrPen {
double radius;
double tolerance;
int num_vertices;
XrPenVertex *vertex;
} XrPen;
struct _XrSurface {
Display *dpy;
char *image_data;
XcSurface *xc_surface;
double ppm;
unsigned int ref_count;
};
typedef struct _XrColor {
double red;
double green;
double blue;
double alpha;
XcColor xc_color;
} XrColor;
struct _XrMatrix {
double m[3][2];
};
typedef struct _XrTraps {
int num_xtraps;
int xtraps_size;
XTrapezoid *xtraps;
} XrTraps;
#define XR_FONT_KEY_DEFAULT "serif"
typedef struct _XrFont {
unsigned char *key;
double scale;
XrMatrix matrix;
Display *dpy;
XftFont *xft_font;
} XrFont;
#define XR_GSTATE_OPERATOR_DEFAULT XrOperatorOver
#define XR_GSTATE_TOLERANCE_DEFAULT 0.1
#define XR_GSTATE_FILL_RULE_DEFAULT XrFillRuleWinding
#define XR_GSTATE_LINE_WIDTH_DEFAULT 2.0
#define XR_GSTATE_LINE_CAP_DEFAULT XrLineCapButt
#define XR_GSTATE_LINE_JOIN_DEFAULT XrLineJoinMiter
#define XR_GSTATE_MITER_LIMIT_DEFAULT 10.0
/* Need a name distinct from the XrClip function */
typedef struct _XrClipRec {
int x;
int y;
int width;
int height;
XrSurface *surface;
} XrClipRec;
typedef struct _XrGState {
XrOperator operator;
double tolerance;
/* stroke style */
double line_width;
XrLineCap line_cap;
XrLineJoin line_join;
double miter_limit;
XrFillRule fill_rule;
double *dash;
int num_dashes;
double dash_offset;
XrFont font;
XrSurface *surface;
XrSurface *solid;
XrSurface *pattern;
XPointDouble pattern_offset;
XrClipRec clip;
double alpha;
XrColor color;
double ppm;
XrMatrix ctm;
XrMatrix ctm_inverse;
XrPath path;
XPointDouble last_move_pt;
XPointDouble current_pt;
int has_current_pt;
XrPen pen_regular;
struct _XrGState *next;
} XrGState;
struct _XrState {
XrGState *stack;
XrStatus status;
};
typedef struct _XrStrokeFace {
XPointFixed ccw;
XPointFixed pt;
XPointFixed cw;
XrSlopeFixed dev_vector;
XPointDouble usr_vector;
} XrStrokeFace;
/* xrstate.c */
XrState *
_XrStateCreate(void);
XrStatus
_XrStateInit(XrState *state);
void
_XrStateDeinit(XrState *xrs);
void
_XrStateDestroy(XrState *state);
XrStatus
_XrStatePush(XrState *xrs);
XrStatus
_XrStatePop(XrState *xrs);
/* xrgstate.c */
XrGState *
_XrGStateCreate(void);
void
_XrGStateInit(XrGState *gstate);
XrStatus
_XrGStateInitCopy(XrGState *gstate, XrGState *other);
void
_XrGStateDeinit(XrGState *gstate);
void
_XrGStateDestroy(XrGState *gstate);
XrGState *
_XrGStateClone(XrGState *gstate);
XrStatus
_XrGStateBeginGroup(XrGState *gstate);
XrStatus
_XrGStateEndGroup(XrGState *gstate);
XrStatus
_XrGStateSetDrawable(XrGState *gstate, Drawable drawable);
XrStatus
_XrGStateSetVisual(XrGState *gstate, Visual *visual);
XrStatus
_XrGStateSetFormat(XrGState *gstate, XrFormat format);
XrStatus
_XrGStateSetTargetSurface (XrGState *gstate, XrSurface *surface);
XrSurface *
_XrGStateGetTargetSurface (XrGState *gstate);
XrStatus
_XrGStateSetPattern (XrGState *gstate, XrSurface *pattern);
XrStatus
_XrGStateSetOperator(XrGState *gstate, XrOperator operator);
XrOperator
_XrGStateGetOperator(XrGState *gstate);
XrStatus
_XrGStateSetRGBColor(XrGState *gstate, double red, double green, double blue);
XrStatus
_XrGStateGetRGBColor(XrGState *gstate, double *red, double *green, double *blue);
XrStatus
_XrGStateSetTolerance(XrGState *gstate, double tolerance);
double
_XrGStateGetTolerance(XrGState *gstate);
XrStatus
_XrGStateSetAlpha(XrGState *gstate, double alpha);
double
_XrGStateGetAlpha(XrGState *gstate);
XrStatus
_XrGStateSetFillRule(XrGState *gstate, XrFillRule fill_rule);
XrStatus
_XrGStateSetLineWidth(XrGState *gstate, double width);
double
_XrGStateGetLineWidth(XrGState *gstate);
XrStatus
_XrGStateSetLineCap(XrGState *gstate, XrLineCap line_cap);
XrLineCap
_XrGStateGetLineCap(XrGState *gstate);
XrStatus
_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join);
XrLineJoin
_XrGStateGetLineJoin(XrGState *gstate);
XrStatus
_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset);
XrStatus
_XrGStateSetMiterLimit(XrGState *gstate, double limit);
double
_XrGStateGetMiterLimit(XrGState *gstate);
XrStatus
_XrGStateTranslate(XrGState *gstate, double tx, double ty);
XrStatus
_XrGStateScale(XrGState *gstate, double sx, double sy);
XrStatus
_XrGStateRotate(XrGState *gstate, double angle);
XrStatus
_XrGStateConcatMatrix(XrGState *gstate,
XrMatrix *matrix);
XrStatus
_XrGStateSetMatrix(XrGState *gstate,
XrMatrix *matrix);
XrStatus
_XrGStateDefaultMatrix(XrGState *gstate);
XrStatus
_XrGStateIdentityMatrix(XrGState *xrs);
XrStatus
_XrGStateTransformPoint (XrGState *gstate, double *x, double *y);
XrStatus
_XrGStateTransformDistance (XrGState *gstate, double *dx, double *dy);
XrStatus
_XrGStateInverseTransformPoint (XrGState *gstate, double *x, double *y);
XrStatus
_XrGStateInverseTransformDistance (XrGState *gstate, double *dx, double *dy);
XrStatus
_XrGStateNewPath(XrGState *gstate);
XrStatus
_XrGStateMoveTo(XrGState *gstate, double x, double y);
XrStatus
_XrGStateLineTo(XrGState *gstate, double x, double y);
XrStatus
_XrGStateCurveTo(XrGState *gstate,
double x1, double y1,
double x2, double y2,
double x3, double y3);
XrStatus
_XrGStateRelMoveTo(XrGState *gstate, double dx, double dy);
XrStatus
_XrGStateRelLineTo(XrGState *gstate, double dx, double dy);
XrStatus
_XrGStateRelCurveTo(XrGState *gstate,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
XrStatus
_XrGStateClosePath(XrGState *gstate);
XrStatus
_XrGStateGetCurrentPoint(XrGState *gstate, double *x, double *y);
XrStatus
_XrGStateStroke(XrGState *gstate);
XrStatus
_XrGStateFill(XrGState *gstate);
XrStatus
_XrGStateClip(XrGState *gstate);
XrStatus
_XrGStateSelectFont(XrGState *gstate, const char *key);
XrStatus
_XrGStateScaleFont(XrGState *gstate, double scale);
XrStatus
_XrGStateTransformFont(XrGState *gstate,
double a, double b,
double c, double d);
XrStatus
_XrGStateTextExtents(XrGState *gstate,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy);
XrStatus
_XrGStateShowText(XrGState *gstate, const unsigned char *utf8);
XrStatus
_XrGStateShowSurface(XrGState *gstate,
XrSurface *surface,
int width,
int height);
/* xrcolor.c */
void
_XrColorInit(XrColor *color);
void
_XrColorDeinit(XrColor *color);
void
_XrColorSetRGB(XrColor *color, double red, double green, double blue);
void
_XrColorGetRGB(XrColor *color, double *red, double *green, double *blue);
void
_XrColorSetAlpha(XrColor *color, double alpha);
/* xrfont.c */
void
_XrFontInit(XrFont *font);
XrStatus
_XrFontInitCopy(XrFont *font, XrFont *other);
void
_XrFontDeinit(XrFont *font);
XrStatus
_XrFontSelect(XrFont *font, const char *key);
XrStatus
_XrFontScale(XrFont *font, double scale);
XrStatus
_XrFontTransform(XrFont *font,
double a, double b,
double c, double d);
XrStatus
_XrFontResolveXftFont(XrFont *font, XrGState *gstate, XftFont **xft_font);
/* xrpath.c */
void
_XrPathInit(XrPath *path);
XrStatus
_XrPathInitCopy(XrPath *path, XrPath *other);
void
_XrPathDeinit(XrPath *path);
XrStatus
_XrPathMoveTo(XrPath *path, double x, double y);
XrStatus
_XrPathLineTo(XrPath *path, double x, double y);
XrStatus
_XrPathCurveTo(XrPath *path,
double x1, double y1,
double x2, double y2,
double x3, double y3);
XrStatus
_XrPathClosePath(XrPath *path);
XrStatus
_XrPathInterpret(XrPath *path, XrPathDirection dir, const XrPathCallbacks *cb, void *closure);
XrStatus
_XrPathBounds(XrPath *path, double *x1, double *y1, double *x2, double *y2);
/* xrpathfill.c */
XrStatus
_XrPathFillToTraps(XrPath *path, XrGState *gstate, XrTraps *traps);
/* xrpathstroke.c */
XrStatus
_XrPathStrokeToTraps (XrPath *path, XrGState *gstate, XrTraps *traps);
/* xrsurface.c */
void
_XrSurfaceReference(XrSurface *surface);
XcSurface *
_XrSurfaceGetXcSurface(XrSurface *surface);
/* XXX: This function is going away, right? */
Picture
_XrSurfaceGetPicture(XrSurface *surface);
void
_XrSurfaceFillRectangle (XrSurface *surface,
XrOperator operator,
XrColor *color,
int x,
int y,
int width,
int height);
/* xrpen.c */
XrStatus
_XrPenInit(XrPen *pen, double radius, XrGState *gstate);
XrStatus
_XrPenInitEmpty(XrPen *pen);
XrStatus
_XrPenInitCopy(XrPen *pen, XrPen *other);
void
_XrPenDeinit(XrPen *pen);
XrStatus
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts);
XrStatus
_XrPenAddPointsForSlopes(XrPen *pen, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrStatus
_XrPenFindActiveCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active);
XrStatus
_XrPenFindActiveCCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active);
XrStatus
_XrPenStrokeSpline(XrPen *pen, XrSpline *spline, double tolerance, XrTraps *traps);
/* xrpolygon.c */
void
_XrPolygonInit(XrPolygon *polygon);
void
_XrPolygonDeinit(XrPolygon *polygon);
XrStatus
_XrPolygonAddEdge(XrPolygon *polygon, XPointFixed *p1, XPointFixed *p2);
XrStatus
_XrPolygonAddPoint(XrPolygon *polygon, XPointFixed *pt);
XrStatus
_XrPolygonClose(XrPolygon *polygon);
/* xrspline.c */
XrIntStatus
_XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
XrStatus
_XrSplineDecompose(XrSpline *spline, double tolerance);
void
_XrSplineDeinit(XrSpline *spline);
/* xrmatrix.c */
void
_XrMatrixInit(XrMatrix *matrix);
void
_XrMatrixFini(XrMatrix *matrix);
XrStatus
_XrMatrixSetTranslate(XrMatrix *matrix,
double tx, double ty);
XrStatus
_XrMatrixSetScale(XrMatrix *matrix,
double sx, double sy);
XrStatus
_XrMatrixSetRotate(XrMatrix *matrix,
double angle);
XrStatus
_XrMatrixTransformBoundingBox(XrMatrix *matrix,
double *x, double *y,
double *width, double *height);
XrStatus
_XrMatrixComputeDeterminant(XrMatrix *matrix, double *det);
XrStatus
_XrMatrixComputeEigenValues(XrMatrix *matrix, double *lambda1, double *lambda2);
/* xrtraps.c */
void
_XrTrapsInit(XrTraps *traps);
void
_XrTrapsDeinit(XrTraps *traps);
XrStatus
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3]);
XrStatus
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4]);
XrStatus
_XrTrapsTessellatePolygon (XrTraps *traps, XrPolygon *poly, XrFillRule fill_rule);
/* xrmisc.c */
void
_ComputeSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope);
#endif

View file

@ -1,378 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "xrint.h"
static XrMatrix XR_MATRIX_IDENTITY = {
{
{1, 0},
{0, 1},
{0, 0}
}
};
static void
_XrMatrixScalarMultiply(XrMatrix *matrix, double scalar);
static void
_XrMatrixComputeAdjoint(XrMatrix *matrix);
XrMatrix *
XrMatrixCreate (void)
{
XrMatrix *matrix;
matrix = malloc (sizeof (XrMatrix));
if (matrix == NULL)
return NULL;
_XrMatrixInit (matrix);
return matrix;
}
void
_XrMatrixInit(XrMatrix *matrix)
{
XrMatrixSetIdentity (matrix);
}
void
_XrMatrixFini(XrMatrix *matrix)
{
/* nothing to do here */
}
void
XrMatrixDestroy (XrMatrix *matrix)
{
_XrMatrixFini (matrix);
free (matrix);
}
XrStatus
XrMatrixCopy(XrMatrix *matrix, const XrMatrix *other)
{
*matrix = *other;
return XrStatusSuccess;
}
XrStatus
XrMatrixSetIdentity(XrMatrix *matrix)
{
*matrix = XR_MATRIX_IDENTITY;
return XrStatusSuccess;
}
XrStatus
XrMatrixSetAffine (XrMatrix *matrix,
double a, double b,
double c, double d,
double tx, double ty)
{
matrix->m[0][0] = a; matrix->m[0][1] = b;
matrix->m[1][0] = c; matrix->m[1][1] = d;
matrix->m[2][0] = tx; matrix->m[2][1] = ty;
return XrStatusSuccess;
}
XrStatus
XrMatrixGetAffine (XrMatrix *matrix,
double *a, double *b,
double *c, double *d,
double *tx, double *ty)
{
*a = matrix->m[0][0]; *b = matrix->m[0][1];
*c = matrix->m[1][0]; *d = matrix->m[1][1];
*tx = matrix->m[2][0]; *ty = matrix->m[2][1];
return XrStatusSuccess;
}
XrStatus
_XrMatrixSetTranslate(XrMatrix *matrix,
double tx, double ty)
{
return XrMatrixSetAffine(matrix,
1, 0,
0, 1,
tx, ty);
}
XrStatus
XrMatrixTranslate (XrMatrix *matrix, double tx, double ty)
{
XrMatrix tmp;
_XrMatrixSetTranslate(&tmp, tx, ty);
return XrMatrixMultiply (matrix, &tmp, matrix);
}
XrStatus
_XrMatrixSetScale(XrMatrix *matrix,
double sx, double sy)
{
return XrMatrixSetAffine(matrix,
sx, 0,
0, sy,
0, 0);
}
XrStatus
XrMatrixScale (XrMatrix *matrix, double sx, double sy)
{
XrMatrix tmp;
_XrMatrixSetScale (&tmp, sx, sy);
return XrMatrixMultiply (matrix, &tmp, matrix);
}
XrStatus
_XrMatrixSetRotate(XrMatrix *matrix,
double radians)
{
return XrMatrixSetAffine(matrix,
cos(radians), sin(radians),
-sin(radians), cos(radians),
0, 0);
}
XrStatus
XrMatrixRotate (XrMatrix *matrix, double radians)
{
XrMatrix tmp;
_XrMatrixSetRotate (&tmp, radians);
return XrMatrixMultiply (matrix, &tmp, matrix);
}
XrStatus
XrMatrixMultiply(XrMatrix *result, const XrMatrix *a, const XrMatrix *b)
{
XrMatrix r;
int row, col, n;
double t;
for (row = 0; row < 3; row++) {
for (col = 0; col < 2; col++) {
if (row == 2)
t = b->m[2][col];
else
t = 0;
for (n = 0; n < 2; n++) {
t += a->m[row][n] * b->m[n][col];
}
r.m[row][col] = t;
}
}
*result = r;
return XrStatusSuccess;
}
XrStatus
XrMatrixTransformDistance(XrMatrix *matrix, double *dx, double *dy)
{
double new_x, new_y;
new_x = (matrix->m[0][0] * *dx
+ matrix->m[1][0] * *dy);
new_y = (matrix->m[0][1] * *dx
+ matrix->m[1][1] * *dy);
*dx = new_x;
*dy = new_y;
return XrStatusSuccess;
}
XrStatus
XrMatrixTransformPoint(XrMatrix *matrix, double *x, double *y)
{
XrMatrixTransformDistance(matrix, x, y);
*x += matrix->m[2][0];
*y += matrix->m[2][1];
return XrStatusSuccess;
}
XrStatus
_XrMatrixTransformBoundingBox(XrMatrix *matrix,
double *x, double *y,
double *width, double *height)
{
int i;
double quad_x[4], quad_y[4];
double dx1, dy1;
double dx2, dy2;
double min_x, max_x;
double min_y, max_y;
quad_x[0] = *x;
quad_y[0] = *y;
XrMatrixTransformPoint(matrix, &quad_x[0], &quad_y[0]);
dx1 = *width;
dy1 = 0;
XrMatrixTransformDistance(matrix, &dx1, &dy1);
quad_x[1] = quad_x[0] + dx1;
quad_y[1] = quad_y[0] + dy1;
dx2 = 0;
dy2 = *height;
XrMatrixTransformDistance(matrix, &dx2, &dy2);
quad_x[2] = quad_x[0] + dx2;
quad_y[2] = quad_y[0] + dy2;
quad_x[3] = quad_x[0] + dx1 + dx2;
quad_y[3] = quad_y[0] + dy1 + dy2;
min_x = max_x = quad_x[0];
min_y = max_y = quad_y[0];
for (i=1; i < 4; i++) {
if (quad_x[i] < min_x)
min_x = quad_x[i];
if (quad_x[i] > max_x)
max_x = quad_x[i];
if (quad_y[i] < min_y)
min_y = quad_y[i];
if (quad_y[i] > max_y)
max_y = quad_y[i];
}
*x = min_x;
*y = min_y;
*width = max_x - min_x;
*height = max_y - min_y;
return XrStatusSuccess;
}
static void
_XrMatrixScalarMultiply(XrMatrix *matrix, double scalar)
{
int row, col;
for (row = 0; row < 3; row++)
for (col = 0; col < 2; col++)
matrix->m[row][col] *= scalar;
}
/* This function isn't a correct adjoint in that the implicit 1 in the
homogeneous result should actually be ad-bc instead. But, since this
adjoint is only used in the computation of the inverse, which
divides by det(A)=ad-bc anyway, everything works out in the end. */
static void
_XrMatrixComputeAdjoint(XrMatrix *matrix)
{
/* adj(A) = transpose(C:cofactor(A,i,j)) */
double a, b, c, d, tx, ty;
a = matrix->m[0][0]; b = matrix->m[0][1];
c = matrix->m[1][0]; d = matrix->m[1][1];
tx = matrix->m[2][0]; ty = matrix->m[2][1];
XrMatrixSetAffine(matrix,
d, -b,
-c, a,
c*ty - d*tx, b*tx - a*ty);
}
XrStatus
XrMatrixInvert (XrMatrix *matrix)
{
/* inv(A) = 1/det(A) * adj(A) */
double det;
_XrMatrixComputeDeterminant (matrix, &det);
if (det == 0)
return XrStatusInvalidMatrix;
_XrMatrixComputeAdjoint (matrix);
_XrMatrixScalarMultiply (matrix, 1 / det);
return XrStatusSuccess;
}
XrStatus
_XrMatrixComputeDeterminant(XrMatrix *matrix, double *det)
{
double a, b, c, d;
a = matrix->m[0][0]; b = matrix->m[0][1];
c = matrix->m[1][0]; d = matrix->m[1][1];
*det = a*d - b*c;
return XrStatusSuccess;
}
XrStatus
_XrMatrixComputeEigenValues (XrMatrix *matrix, double *lambda1, double *lambda2)
{
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
det(M - lI) = 0
The zeros in our homogeneous 3x3 matrix make this equation equal
to that formed by the sub-matrix:
M = a b
c d
by which:
l^2 - (a+d)l + (ad - bc) = 0
l = (a+d +/- sqrt(a^2 + 2ad + d^2 - 4(ad-bc))) / 2;
*/
double a, b, c, d, rad;
a = matrix->m[0][0];
b = matrix->m[0][1];
c = matrix->m[1][0];
d = matrix->m[1][1];
rad = sqrt(a*a + 2*a*d + d*d - 4*(a*d - b*c));
*lambda1 = (a + d + rad) / 2.0;
*lambda2 = (a + d - rad) / 2.0;
return XrStatusSuccess;
}

View file

@ -1,34 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
void
_ComputeSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope)
{
slope->dx = b->x - a->x;
slope->dy = b->y - a->y;
}

View file

@ -1,434 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "xrint.h"
/* private functions */
static XrStatus
_XrPathAdd(XrPath *path, XrPathOp op, XPointFixed *pts, int num_pts);
static void
_XrPathAddOpBuf(XrPath *path, XrPathOpBuf *op);
static XrStatus
_XrPathNewOpBuf(XrPath *path);
static void
_XrPathAddArgBuf(XrPath *path, XrPathArgBuf *arg);
static XrStatus
_XrPathNewArgBuf(XrPath *path);
static XrPathOpBuf *
_XrPathOpBufCreate(void);
static void
_XrPathOpBufDestroy(XrPathOpBuf *buf);
static void
_XrPathOpBufAdd(XrPathOpBuf *op_buf, XrPathOp op);
static XrPathArgBuf *
_XrPathArgBufCreate(void);
static void
_XrPathArgBufDestroy(XrPathArgBuf *buf);
static void
_XrPathArgBufAdd(XrPathArgBuf *arg, XPointFixed *pts, int num_pts);
void
_XrPathInit(XrPath *path)
{
path->op_head = NULL;
path->op_tail = NULL;
path->arg_head = NULL;
path->arg_tail = NULL;
}
XrStatus
_XrPathInitCopy(XrPath *path, XrPath *other)
{
XrPathOpBuf *op, *other_op;
XrPathArgBuf *arg, *other_arg;
_XrPathInit(path);
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _XrPathOpBufCreate();
if (op == NULL) {
return XrStatusNoMemory;
}
*op = *other_op;
_XrPathAddOpBuf(path, op);
}
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
arg = _XrPathArgBufCreate();
if (arg == NULL) {
return XrStatusNoMemory;
}
*arg = *other_arg;
_XrPathAddArgBuf(path, arg);
}
return XrStatusSuccess;
}
void
_XrPathDeinit(XrPath *path)
{
XrPathOpBuf *op;
XrPathArgBuf *arg;
while (path->op_head) {
op = path->op_head;
path->op_head = op->next;
_XrPathOpBufDestroy(op);
}
path->op_tail = NULL;
while (path->arg_head) {
arg = path->arg_head;
path->arg_head = arg->next;
_XrPathArgBufDestroy(arg);
}
path->arg_tail = NULL;
}
XrStatus
_XrPathMoveTo(XrPath *path, double x, double y)
{
XPointFixed pt;
pt.x = XDoubleToFixed(x);
pt.y = XDoubleToFixed(y);
return _XrPathAdd(path, XrPathOpMoveTo, &pt, 1);
}
XrStatus
_XrPathLineTo(XrPath *path, double x, double y)
{
XPointFixed pt;
pt.x = XDoubleToFixed(x);
pt.y = XDoubleToFixed(y);
return _XrPathAdd(path, XrPathOpLineTo, &pt, 1);
}
XrStatus
_XrPathCurveTo(XrPath *path,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
XPointFixed pt[3];
pt[0].x = XDoubleToFixed(x1);
pt[0].y = XDoubleToFixed(y1);
pt[1].x = XDoubleToFixed(x2);
pt[1].y = XDoubleToFixed(y2);
pt[2].x = XDoubleToFixed(x3);
pt[2].y = XDoubleToFixed(y3);
return _XrPathAdd(path, XrPathOpCurveTo, pt, 3);
}
XrStatus
_XrPathClosePath(XrPath *path)
{
return _XrPathAdd(path, XrPathOpClosePath, NULL, 0);
}
static XrStatus
_XrPathAdd(XrPath *path, XrPathOp op, XPointFixed *pts, int num_pts)
{
XrStatus status;
if (path->op_tail == NULL || path->op_tail->num_ops + 1 > XR_PATH_BUF_SZ) {
status = _XrPathNewOpBuf(path);
if (status)
return status;
}
_XrPathOpBufAdd(path->op_tail, op);
if (path->arg_tail == NULL || path->arg_tail->num_pts + num_pts > XR_PATH_BUF_SZ) {
status = _XrPathNewArgBuf(path);
if (status)
return status;
}
_XrPathArgBufAdd(path->arg_tail, pts, num_pts);
return XrStatusSuccess;
}
static void
_XrPathAddOpBuf(XrPath *path, XrPathOpBuf *op)
{
op->next = NULL;
op->prev = path->op_tail;
if (path->op_tail) {
path->op_tail->next = op;
} else {
path->op_head = op;
}
path->op_tail = op;
}
static XrStatus
_XrPathNewOpBuf(XrPath *path)
{
XrPathOpBuf *op;
op = _XrPathOpBufCreate();
if (op == NULL)
return XrStatusNoMemory;
_XrPathAddOpBuf(path, op);
return XrStatusSuccess;
}
static void
_XrPathAddArgBuf(XrPath *path, XrPathArgBuf *arg)
{
arg->next = NULL;
arg->prev = path->arg_tail;
if (path->arg_tail) {
path->arg_tail->next = arg;
} else {
path->arg_head = arg;
}
path->arg_tail = arg;
}
static XrStatus
_XrPathNewArgBuf(XrPath *path)
{
XrPathArgBuf *arg;
arg = _XrPathArgBufCreate();
if (arg == NULL)
return XrStatusNoMemory;
_XrPathAddArgBuf(path, arg);
return XrStatusSuccess;
}
static XrPathOpBuf *
_XrPathOpBufCreate(void)
{
XrPathOpBuf *op;
op = malloc(sizeof(XrPathOpBuf));
if (op) {
op->num_ops = 0;
op->next = NULL;
}
return op;
}
static void
_XrPathOpBufDestroy(XrPathOpBuf *op)
{
free(op);
}
static void
_XrPathOpBufAdd(XrPathOpBuf *op_buf, XrPathOp op)
{
op_buf->op[op_buf->num_ops++] = op;
}
static XrPathArgBuf *
_XrPathArgBufCreate(void)
{
XrPathArgBuf *arg;
arg = malloc(sizeof(XrPathArgBuf));
if (arg) {
arg->num_pts = 0;
arg->next = NULL;
}
return arg;
}
static void
_XrPathArgBufDestroy(XrPathArgBuf *arg)
{
free(arg);
}
static void
_XrPathArgBufAdd(XrPathArgBuf *arg, XPointFixed *pts, int num_pts)
{
int i;
for (i=0; i < num_pts; i++) {
arg->pt[arg->num_pts++] = pts[i];
}
}
#define XR_PATH_OP_MAX_ARGS 3
static int num_args[] =
{
1, /* XrPathMoveTo */
1, /* XrPathOpLineTo */
3, /* XrPathOpCurveTo */
0, /* XrPathOpClosePath */
};
XrStatus
_XrPathInterpret(XrPath *path, XrPathDirection dir, const XrPathCallbacks *cb, void *closure)
{
XrStatus status;
int i, arg;
XrPathOpBuf *op_buf;
XrPathOp op;
XrPathArgBuf *arg_buf = path->arg_head;
int buf_i = 0;
XPointFixed pt[XR_PATH_OP_MAX_ARGS];
XPointFixed current = {0, 0};
XPointFixed first = {0, 0};
int has_current = 0;
int has_edge = 0;
int step = (dir == XrPathDirectionForward) ? 1 : -1;
for (op_buf = (dir == XrPathDirectionForward) ? path->op_head : path->op_tail;
op_buf;
op_buf = (dir == XrPathDirectionForward) ? op_buf->next : op_buf->prev)
{
int start, stop;
if (dir == XrPathDirectionForward) {
start = 0;
stop = op_buf->num_ops;
} else {
start = op_buf->num_ops - 1;
stop = -1;
}
for (i=start; i != stop; i += step) {
op = op_buf->op[i];
if (dir == XrPathDirectionReverse) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_pts;
}
buf_i -= num_args[op];
}
for (arg = 0; arg < num_args[op]; arg++) {
pt[arg] = arg_buf->pt[buf_i];
buf_i++;
if (buf_i >= arg_buf->num_pts) {
arg_buf = arg_buf->next;
buf_i = 0;
}
}
if (dir == XrPathDirectionReverse) {
buf_i -= num_args[op];
}
switch (op) {
case XrPathOpMoveTo:
if (has_edge) {
status = (*cb->DoneSubPath) (closure, XrSubPathDoneCap);
if (status)
return status;
}
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
break;
case XrPathOpLineTo:
if (has_current) {
status = (*cb->AddEdge)(closure, &current, &pt[0]);
if (status)
return status;
current = pt[0];
has_edge = 1;
} else {
first = pt[0];
current = pt[0];
has_current = 1;
has_edge = 0;
}
break;
case XrPathOpCurveTo:
if (has_current) {
status = (*cb->AddSpline)(closure, &current, &pt[0], &pt[1], &pt[2]);
if (status)
return status;
current = pt[2];
has_edge = 1;
} else {
first = pt[2];
current = pt[2];
has_current = 1;
has_edge = 0;
}
break;
case XrPathOpClosePath:
if (has_edge) {
(*cb->AddEdge)(closure, &current, &first);
(*cb->DoneSubPath) (closure, XrSubPathDoneJoin);
}
current.x = 0;
current.y = 0;
first.x = 0;
first.y = 0;
has_current = 0;
has_edge = 0;
break;
}
}
}
if (has_edge)
(*cb->DoneSubPath) (closure, XrSubPathDoneCap);
return (*cb->DonePath)(closure);
}

View file

@ -1,168 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2003 USC, Information Sciences Institute
*
* 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
* Information Sciences Institute not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. Information Sciences Institute
* makes no representations about the suitability of this software for
* any purpose. It is provided "as is" without express or implied
* warranty.
*
* INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
* INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
typedef struct _XrPathBounder {
int has_pt;
XFixed min_x;
XFixed min_y;
XFixed max_x;
XFixed max_y;
} XrPathBounder;
static void
_XrPathBounderInit(XrPathBounder *bounder);
static void
_XrPathBounderDeinit(XrPathBounder *bounder);
static XrStatus
_XrPathBounderAddPoint(XrPathBounder *bounder, XPointFixed *pt);
static XrStatus
_XrPathBounderAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
static XrStatus
_XrPathBounderAddSpline(void *closure,
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static XrStatus
_XrPathBounderDoneSubPath(void *closure, XrSubPathDone done);
static XrStatus
_XrPathBounderDonePath(void *closure);
static void
_XrPathBounderInit(XrPathBounder *bounder)
{
bounder->has_pt = 0;
}
static void
_XrPathBounderDeinit(XrPathBounder *bounder)
{
bounder->has_pt = 0;
}
static XrStatus
_XrPathBounderAddPoint(XrPathBounder *bounder, XPointFixed *pt)
{
if (bounder->has_pt) {
if (pt->x < bounder->min_x)
bounder->min_x = pt->x;
if (pt->y < bounder->min_y)
bounder->min_y = pt->y;
if (pt->x > bounder->max_x)
bounder->max_x = pt->x;
if (pt->y > bounder->max_y)
bounder->max_y = pt->y;
} else {
bounder->min_x = pt->x;
bounder->min_y = pt->y;
bounder->max_x = pt->x;
bounder->max_y = pt->y;
bounder->has_pt = 1;
}
return XrStatusSuccess;
}
static XrStatus
_XrPathBounderAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrPathBounder *bounder = closure;
_XrPathBounderAddPoint(bounder, p1);
_XrPathBounderAddPoint(bounder, p2);
return XrStatusSuccess;
}
static XrStatus
_XrPathBounderAddSpline(void *closure,
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
XrPathBounder *bounder = closure;
_XrPathBounderAddPoint(bounder, a);
_XrPathBounderAddPoint(bounder, b);
_XrPathBounderAddPoint(bounder, c);
_XrPathBounderAddPoint(bounder, d);
return XrStatusSuccess;
}
static XrStatus
_XrPathBounderDoneSubPath(void *closure, XrSubPathDone done)
{
return XrStatusSuccess;
}
static XrStatus
_XrPathBounderDonePath(void *closure)
{
return XrStatusSuccess;
}
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
XrStatus
_XrPathBounds(XrPath *path, double *x1, double *y1, double *x2, double *y2)
{
XrStatus status;
static XrPathCallbacks cb = {
_XrPathBounderAddEdge,
_XrPathBounderAddSpline,
_XrPathBounderDoneSubPath,
_XrPathBounderDonePath
};
XrPathBounder bounder;
_XrPathBounderInit(&bounder);
status = _XrPathInterpret(path, XrPathDirectionForward, &cb, &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_XrPathBounderDeinit(&bounder);
return status;
}
*x1 = XFixedToDouble(bounder.min_x);
*y1 = XFixedToDouble(bounder.min_y);
*x2 = XFixedToDouble(bounder.max_x);
*y2 = XFixedToDouble(bounder.max_y);
_XrPathBounderDeinit(&bounder);
return XrStatusSuccess;
}

View file

@ -1,156 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
typedef struct _XrFiller {
XrGState *gstate;
XrTraps *traps;
XrPolygon polygon;
} XrFiller;
static void
_XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps);
static void
_XrFillerDeinit(XrFiller *filler);
static XrStatus
_XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
static XrStatus
_XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static XrStatus
_XrFillerDoneSubPath (void *closure, XrSubPathDone done);
static XrStatus
_XrFillerDonePath (void *closure);
static void
_XrFillerInit(XrFiller *filler, XrGState *gstate, XrTraps *traps)
{
filler->gstate = gstate;
filler->traps = traps;
_XrPolygonInit(&filler->polygon);
}
static void
_XrFillerDeinit(XrFiller *filler)
{
_XrPolygonDeinit(&filler->polygon);
}
static XrStatus
_XrFillerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
return _XrPolygonAddEdge(polygon, p1, p2);
}
static XrStatus
_XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
int i;
XrStatus status = XrStatusSuccess;
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
XrGState *gstate = filler->gstate;
XrSpline spline;
status = _XrSplineInit(&spline, a, b, c, d);
if (status == XrIntStatusDegenerate)
return XrStatusSuccess;
_XrSplineDecompose(&spline, gstate->tolerance);
if (status)
goto CLEANUP_SPLINE;
for (i = 0; i < spline.num_pts - 1; i++) {
status = _XrPolygonAddEdge(polygon, &spline.pts[i], &spline.pts[i+1]);
if (status)
goto CLEANUP_SPLINE;
}
CLEANUP_SPLINE:
_XrSplineDeinit(&spline);
return status;
}
static XrStatus
_XrFillerDoneSubPath (void *closure, XrSubPathDone done)
{
XrStatus status = XrStatusSuccess;
XrFiller *filler = closure;
XrPolygon *polygon = &filler->polygon;
_XrPolygonClose(polygon);
return status;
}
static XrStatus
_XrFillerDonePath (void *closure)
{
XrFiller *filler = closure;
return _XrTrapsTessellatePolygon(filler->traps,
&filler->polygon,
filler->gstate->fill_rule);
}
XrStatus
_XrPathFillToTraps(XrPath *path, XrGState *gstate, XrTraps *traps)
{
static const XrPathCallbacks filler_callbacks = {
_XrFillerAddEdge,
_XrFillerAddSpline,
_XrFillerDoneSubPath,
_XrFillerDonePath
};
XrStatus status;
XrFiller filler;
_XrFillerInit(&filler, gstate, traps);
status = _XrPathInterpret(path,
XrPathDirectionForward,
&filler_callbacks, &filler);
if (status) {
_XrFillerDeinit(&filler);
return status;
}
_XrFillerDeinit(&filler);
return XrStatusSuccess;
}

View file

@ -1,713 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
typedef struct _XrStroker {
XrGState *gstate;
XrTraps *traps;
int have_prev;
int have_first;
int is_first;
XrStrokeFace prev;
XrStrokeFace first;
int dash_index;
int dash_on;
double dash_remain;
} XrStroker;
/* private functions */
static void
_XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps);
static void
_XrStrokerDeinit(XrStroker *stroker);
static XrStatus
_XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2);
static XrStatus
_XrStrokerAddEdgeDashed(void *closure, XPointFixed *p1, XPointFixed *p2);
static XrStatus
_XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
static XrStatus
_XrStrokerDoneSubPath (void *closure, XrSubPathDone done);
static XrStatus
_XrStrokerDonePath (void *closure);
static void
_TranslatePoint(XPointFixed *pt, XPointFixed *offset);
static int
_XrStrokerFaceClockwise(XrStrokeFace *in, XrStrokeFace *out);
static XrStatus
_XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out);
static void
_XrStrokerStartDash (XrStroker *stroker)
{
XrGState *gstate = stroker->gstate;
double offset;
int on = 1;
int i = 0;
offset = gstate->dash_offset;
while (offset >= gstate->dash[i]) {
offset -= gstate->dash[i];
on = 1-on;
if (++i == gstate->num_dashes)
i = 0;
}
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_remain = gstate->dash[i] - offset;
}
static void
_XrStrokerStepDash (XrStroker *stroker, double step)
{
XrGState *gstate = stroker->gstate;
stroker->dash_remain -= step;
if (stroker->dash_remain <= 0) {
stroker->dash_index++;
if (stroker->dash_index == gstate->num_dashes)
stroker->dash_index = 0;
stroker->dash_on = 1-stroker->dash_on;
stroker->dash_remain = gstate->dash[stroker->dash_index];
}
}
static void
_XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps)
{
stroker->gstate = gstate;
stroker->traps = traps;
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
if (gstate->dash)
_XrStrokerStartDash (stroker);
}
static void
_XrStrokerDeinit(XrStroker *stroker)
{
/* nothing to do here */
}
static void
_TranslatePoint(XPointFixed *pt, XPointFixed *offset)
{
pt->x += offset->x;
pt->y += offset->y;
}
static int
_XrStrokerFaceClockwise(XrStrokeFace *in, XrStrokeFace *out)
{
XPointDouble d_in, d_out;
d_in.x = XFixedToDouble(in->cw.x - in->pt.x);
d_in.y = XFixedToDouble(in->cw.y - in->pt.y);
d_out.x = XFixedToDouble(out->cw.x - out->pt.x);
d_out.y = XFixedToDouble(out->cw.y - out->pt.y);
return d_out.y * d_in.x > d_in.y * d_out.x;
}
static XrStatus
_XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
{
XrStatus status;
XrGState *gstate = stroker->gstate;
int clockwise = _XrStrokerFaceClockwise (out, in);
XPointFixed *inpt, *outpt;
if (in->cw.x == out->cw.x
&& in->cw.y == out->cw.y
&& in->ccw.x == out->ccw.x
&& in->ccw.y == out->ccw.y) {
return XrStatusSuccess;
}
if (clockwise) {
inpt = &in->ccw;
outpt = &out->ccw;
} else {
inpt = &in->cw;
outpt = &out->cw;
}
switch (gstate->line_join) {
case XrLineJoinRound: {
int i;
int start, step, stop;
XPointFixed tri[3], initial, final;
XrPen *pen = &gstate->pen_regular;
tri[0] = in->pt;
if (clockwise) {
initial = in->ccw;
_XrPenFindActiveCCWVertexIndex(pen, &in->dev_vector, &start);
step = -1;
_XrPenFindActiveCCWVertexIndex(pen, &out->dev_vector, &stop);
final = out->ccw;
} else {
initial = in->cw;
_XrPenFindActiveCWVertexIndex(pen, &in->dev_vector, &start);
step = +1;
_XrPenFindActiveCWVertexIndex(pen, &out->dev_vector, &stop);
final = out->cw;
}
i = start;
tri[1] = initial;
while (i != stop) {
tri[2] = in->pt;
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
_XrTrapsTessellateTriangle(stroker->traps, tri);
tri[1] = tri[2];
i += step;
if (i < 0)
i = pen->num_vertices - 1;
if (i >= pen->num_vertices)
i = 0;
}
tri[2] = final;
return _XrTrapsTessellateTriangle(stroker->traps, tri);
}
case XrLineJoinMiter:
default: {
XrPolygon polygon;
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
XDouble ml = gstate->miter_limit;
_XrPolygonInit (&polygon);
if (2 <= ml * ml * (1 - c)) {
XDouble x1, y1, x2, y2;
XDouble mx, my;
XDouble dx1, dx2, dy1, dy2;
XPointFixed outer;
x1 = XFixedToDouble(inpt->x);
y1 = XFixedToDouble(inpt->y);
dx1 = in->usr_vector.x;
dy1 = in->usr_vector.y;
XrMatrixTransformDistance(&gstate->ctm, &dx1, &dy1);
x2 = XFixedToDouble(outpt->x);
y2 = XFixedToDouble(outpt->y);
dx2 = out->usr_vector.x;
dy2 = out->usr_vector.y;
XrMatrixTransformDistance(&gstate->ctm, &dx2, &dy2);
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
(dx1 * dy2 - dx2 * dy1));
if (dy1)
mx = (my - y1) * dx1 / dy1 + x1;
else
mx = (my - y2) * dx2 / dy2 + x2;
outer.x = XDoubleToFixed(mx);
outer.y = XDoubleToFixed(my);
_XrPolygonAddEdge (&polygon, &in->pt, inpt);
_XrPolygonAddEdge (&polygon, inpt, &outer);
_XrPolygonAddEdge (&polygon, &outer, outpt);
_XrPolygonAddEdge (&polygon, outpt, &in->pt);
status = _XrTrapsTessellatePolygon (stroker->traps,
&polygon,
XrFillRuleWinding);
_XrPolygonDeinit (&polygon);
return status;
}
/* fall through ... */
}
case XrLineJoinBevel: {
XPointFixed tri[3];
tri[0] = in->pt;
tri[1] = *inpt;
tri[2] = *outpt;
return _XrTrapsTessellateTriangle (stroker->traps, tri);
}
}
}
static XrStatus
_XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
{
XrStatus status;
XrGState *gstate = stroker->gstate;
if (gstate->line_cap == XrLineCapButt)
return XrStatusSuccess;
switch (gstate->line_cap) {
case XrLineCapRound: {
int i;
int start, stop;
XrSlopeFixed slope;
XPointFixed tri[3];
XrPen *pen = &gstate->pen_regular;
slope = f->dev_vector;
_XrPenFindActiveCWVertexIndex(pen, &slope, &start);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
_XrPenFindActiveCWVertexIndex(pen, &slope, &stop);
tri[0] = f->pt;
tri[1] = f->cw;
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
tri[2] = f->pt;
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
_XrTrapsTessellateTriangle(stroker->traps, tri);
tri[1] = tri[2];
}
tri[2] = f->ccw;
return _XrTrapsTessellateTriangle(stroker->traps, tri);
}
case XrLineCapSquare: {
double dx, dy;
XrSlopeFixed fvector;
XPointFixed occw, ocw;
XrPolygon polygon;
_XrPolygonInit (&polygon);
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= gstate->line_width / 2.0;
dy *= gstate->line_width / 2.0;
XrMatrixTransformDistance(&gstate->ctm, &dx, &dy);
fvector.dx = XDoubleToFixed(dx);
fvector.dy = XDoubleToFixed(dy);
occw.x = f->ccw.x + fvector.dx;
occw.y = f->ccw.y + fvector.dy;
ocw.x = f->cw.x + fvector.dx;
ocw.y = f->cw.y + fvector.dy;
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
_XrPolygonAddEdge (&polygon, &ocw, &occw);
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
_XrPolygonDeinit (&polygon);
return status;
}
case XrLineCapButt:
default:
return XrStatusSuccess;
}
}
static void
_ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFace *face)
{
double mag, tmp;
double dx, dy;
XPointDouble usr_vector;
XPointFixed offset_ccw, offset_cw;
dx = XFixedToDouble(slope->dx);
dy = XFixedToDouble(slope->dy);
XrMatrixTransformDistance(&gstate->ctm_inverse, &dx, &dy);
mag = sqrt(dx * dx + dy * dy);
if (mag == 0) {
/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
return;
}
dx /= mag;
dy /= mag;
usr_vector.x = dx;
usr_vector.y = dy;
tmp = dx;
dx = - dy * (gstate->line_width / 2.0);
dy = tmp * (gstate->line_width / 2.0);
XrMatrixTransformDistance(&gstate->ctm, &dx, &dy);
offset_ccw.x = XDoubleToFixed(dx);
offset_ccw.y = XDoubleToFixed(dy);
offset_cw.x = -offset_ccw.x;
offset_cw.y = -offset_ccw.y;
face->ccw = *pt;
_TranslatePoint(&face->ccw, &offset_ccw);
face->pt = *pt;
face->cw = *pt;
_TranslatePoint(&face->cw, &offset_cw);
face->usr_vector.x = usr_vector.x;
face->usr_vector.y = usr_vector.y;
face->dev_vector = *slope;
}
static XrStatus
_XrStrokerAddSubEdge (XrStroker *stroker, XPointFixed *p1, XPointFixed *p2,
XrStrokeFace *start, XrStrokeFace *end)
{
XrGState *gstate = stroker->gstate;
XPointFixed quad[4];
XrSlopeFixed slope;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in _ComputeFace). The key behavior is that
degenerate paths should draw as much as possible. */
return XrStatusSuccess;
}
_ComputeSlope(p1, p2, &slope);
_ComputeFace(p1, &slope, gstate, start);
/* XXX: This could be optimized slightly by not calling
_ComputeFace again but rather translating the relevant
fields from start. */
_ComputeFace(p2, &slope, gstate, end);
quad[0] = start->cw;
quad[1] = start->ccw;
quad[2] = end->ccw;
quad[3] = end->cw;
return _XrTrapsTessellateRectangle(stroker->traps, quad);
}
static XrStatus
_XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrStatus status;
XrStroker *stroker = closure;
XrStrokeFace start, end;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in XrStrokerAddSubEdge and in _ComputeFace). The
key behavior is that degenerate paths should draw as much
as possible. */
return XrStatusSuccess;
}
status = _XrStrokerAddSubEdge (stroker, p1, p2, &start, &end);
if (status)
return status;
if (stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
return XrStatusSuccess;
}
/*
* Dashed lines. Cap each dash end, join around turns when on
*/
static XrStatus
_XrStrokerAddEdgeDashed (void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrStatus status = XrStatusSuccess;
XrStroker *stroker = closure;
XrGState *gstate = stroker->gstate;
double mag, remain, tmp;
double dx, dy;
double dx2, dy2;
XPointFixed fd1, fd2;
int first = 1;
XrStrokeFace sub_start, sub_end;
dx = XFixedToDouble(p2->x - p1->x);
dy = XFixedToDouble(p2->y - p1->y);
XrMatrixTransformDistance(&gstate->ctm_inverse, &dx, &dy);
mag = sqrt(dx *dx + dy * dy);
remain = mag;
fd1 = *p1;
while (remain) {
tmp = stroker->dash_remain;
if (tmp > remain)
tmp = remain;
remain -= tmp;
dx2 = dx * (mag - remain)/mag;
dy2 = dy * (mag - remain)/mag;
XrMatrixTransformDistance (&gstate->ctm, &dx2, &dy2);
fd2.x = XDoubleToFixed (dx2);
fd2.y = XDoubleToFixed (dy2);
fd2.x += p1->x;
fd2.y += p1->y;
/*
* XXX simplify this case analysis
*/
if (stroker->dash_on) {
status = _XrStrokerAddSubEdge (stroker, &fd1, &fd2, &sub_start, &sub_end);
if (status)
return status;
if (!first) {
/*
* Not first dash in this segment, cap start
*/
status = _XrStrokerCap (stroker, &sub_start);
if (status)
return status;
} else {
/*
* First in this segment, join to any prev, else
* if at start of sub-path, mark position, else
* cap
*/
if (stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &sub_start);
if (status)
return status;
} else {
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = sub_start;
} else {
status = _XrStrokerCap (stroker, &sub_start);
if (status)
return status;
}
}
}
if (remain) {
/*
* Cap if not at end of segment
*/
status = _XrStrokerCap (stroker, &sub_end);
if (status)
return status;
} else {
/*
* Mark previous line face and fix up next time
* through
*/
stroker->prev = sub_end;
stroker->have_prev = 1;
}
} else {
/*
* If starting with off dash, check previous face
* and cap if necessary
*/
if (first) {
if (stroker->have_prev) {
status = _XrStrokerCap (stroker, &stroker->prev);
if (status)
return status;
}
}
if (!remain)
stroker->have_prev = 0;
}
_XrStrokerStepDash (stroker, tmp);
fd1 = fd2;
first = 0;
}
stroker->is_first = 0;
return status;
}
static XrStatus
_XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
XrStatus status = XrStatusSuccess;
XrStroker *stroker = closure;
XrGState *gstate = stroker->gstate;
XrSpline spline;
XrPen pen;
XrStrokeFace start, end;
XPointFixed extra_points[4];
status = _XrSplineInit(&spline, a, b, c, d);
if (status == XrIntStatusDegenerate)
return XrStatusSuccess;
status = _XrPenInitCopy(&pen, &gstate->pen_regular);
if (status)
goto CLEANUP_SPLINE;
_ComputeFace(a, &spline.initial_slope, gstate, &start);
_ComputeFace(d, &spline.final_slope, gstate, &end);
if (stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
extra_points[0] = start.cw;
extra_points[0].x -= start.pt.x;
extra_points[0].y -= start.pt.y;
extra_points[1] = start.ccw;
extra_points[1].x -= start.pt.x;
extra_points[1].y -= start.pt.y;
extra_points[2] = end.cw;
extra_points[2].x -= end.pt.x;
extra_points[2].y -= end.pt.y;
extra_points[3] = end.ccw;
extra_points[3].x -= end.pt.x;
extra_points[3].y -= end.pt.y;
status = _XrPenAddPoints(&pen, extra_points, 4);
if (status)
goto CLEANUP_PEN;
status = _XrPenStrokeSpline(&pen, &spline, gstate->tolerance, stroker->traps);
if (status)
goto CLEANUP_PEN;
CLEANUP_PEN:
_XrPenDeinit(&pen);
CLEANUP_SPLINE:
_XrSplineDeinit(&spline);
return status;
}
static XrStatus
_XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
{
XrStatus status;
XrStroker *stroker = closure;
switch (done) {
case XrSubPathDoneJoin:
if (stroker->have_first && stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &stroker->first);
if (status)
return status;
break;
}
/* fall through... */
case XrSubPathDoneCap:
if (stroker->have_first) {
XPointFixed t;
/* The initial cap needs an outward facing vector. Reverse everything */
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
t = stroker->first.cw;
stroker->first.cw = stroker->first.ccw;
stroker->first.ccw = t;
status = _XrStrokerCap (stroker, &stroker->first);
if (status)
return status;
}
if (stroker->have_prev) {
status = _XrStrokerCap (stroker, &stroker->prev);
if (status)
return status;
}
break;
}
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
return XrStatusSuccess;
}
static XrStatus
_XrStrokerDonePath (void *closure)
{
return XrStatusSuccess;
}
XrStatus
_XrPathStrokeToTraps (XrPath *path, XrGState *gstate, XrTraps *traps)
{
static const XrPathCallbacks stroker_solid_cb = {
_XrStrokerAddEdge,
_XrStrokerAddSpline,
_XrStrokerDoneSubPath,
_XrStrokerDonePath
};
static const XrPathCallbacks stroker_dashed_cb = {
_XrStrokerAddEdgeDashed,
_XrStrokerAddSpline,
_XrStrokerDoneSubPath,
_XrStrokerDonePath
};
const XrPathCallbacks *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
XrStatus status;
XrStroker stroker;
_XrStrokerInit(&stroker, gstate, traps);
status = _XrPathInterpret(path,
XrPathDirectionForward,
callbacks, &stroker);
if (status) {
_XrStrokerDeinit(&stroker);
return status;
}
_XrStrokerDeinit(&stroker);
return XrStatusSuccess;
}

View file

@ -1,389 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
static int
_XrPenVerticesNeeded(double radius, double tolerance, XrMatrix *matrix);
static void
_XrPenComputeSlopes(XrPen *pen);
static int
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b);
static int
_SlopeCounterClockwise(XrSlopeFixed *a, XrSlopeFixed *b);
static int
_XrPenVertexCompareByTheta(const void *a, const void *b);
static XrStatus
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon);
XrStatus
_XrPenInitEmpty(XrPen *pen)
{
pen->radius = 0;
pen->tolerance = 0;
pen->vertex = NULL;
pen->num_vertices = 0;
return XrStatusSuccess;
}
XrStatus
_XrPenInit(XrPen *pen, double radius, XrGState *gstate)
{
int i;
XrPenVertex *v;
double dx, dy;
if (pen->num_vertices) {
/* XXX: It would be nice to notice that the pen is already properly constructed.
However, this test would also have to account for possible changes in the transformation
matrix.
if (pen->radius == radius && pen->tolerance == tolerance)
return XrStatusSuccess;
*/
_XrPenDeinit(pen);
}
pen->radius = radius;
pen->tolerance = gstate->tolerance;
pen->num_vertices = _XrPenVerticesNeeded(radius, gstate->tolerance, &gstate->ctm);
/* number of vertices must be even */
if (pen->num_vertices % 2)
pen->num_vertices++;
pen->vertex = malloc(pen->num_vertices * sizeof(XrPenVertex));
if (pen->vertex == NULL) {
return XrStatusNoMemory;
}
for (i=0; i < pen->num_vertices; i++) {
v = &pen->vertex[i];
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
dx = radius * cos(v->theta);
dy = radius * sin(v->theta);
XrMatrixTransformDistance(&gstate->ctm, &dx, &dy);
v->pt.x = XDoubleToFixed(dx);
v->pt.y = XDoubleToFixed(dy);
/* Recompute theta in device space */
v->theta = atan2(v->pt.y, v->pt.x);
if (v->theta < 0)
v->theta += 2 * M_PI;
}
_XrPenComputeSlopes(pen);
return XrStatusSuccess;
}
void
_XrPenDeinit(XrPen *pen)
{
free(pen->vertex);
_XrPenInitEmpty(pen);
}
XrStatus
_XrPenInitCopy(XrPen *pen, XrPen *other)
{
*pen = *other;
if (pen->num_vertices) {
pen->vertex = malloc(pen->num_vertices * sizeof(XrPenVertex));
if (pen->vertex == NULL) {
return XrStatusNoMemory;
}
memcpy(pen->vertex, other->vertex, pen->num_vertices * sizeof(XrPenVertex));
}
return XrStatusSuccess;
}
static int
_XrPenVertexCompareByTheta(const void *a, const void *b)
{
double diff;
const XrPenVertex *va = a;
const XrPenVertex *vb = b;
diff = va->theta - vb->theta;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
else
return 0;
}
XrStatus
_XrPenAddPoints(XrPen *pen, XPointFixed *pt, int num_pts)
{
int i, j;
XrPenVertex *v, *v_next, *new_vertex;
pen->num_vertices += num_pts;
new_vertex = realloc(pen->vertex, pen->num_vertices * sizeof(XrPenVertex));
if (new_vertex == NULL) {
pen->num_vertices -= num_pts;
return XrStatusNoMemory;
}
pen->vertex = new_vertex;
/* initialize new vertices */
for (i=0; i < num_pts; i++) {
v = &pen->vertex[pen->num_vertices-(i+1)];
v->pt = pt[i];
v->theta = atan2(v->pt.y, v->pt.x);
if (v->theta < 0)
v->theta += 2 * M_PI;
}
qsort(pen->vertex, pen->num_vertices, sizeof(XrPenVertex), _XrPenVertexCompareByTheta);
/* eliminate any duplicate vertices */
for (i=0; i < pen->num_vertices - 1; i++ ) {
v = &pen->vertex[i];
v_next = &pen->vertex[i+1];
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
for (j=i+1; j < pen->num_vertices - 1; j++)
pen->vertex[j] = pen->vertex[j+1];
pen->num_vertices--;
/* There may be more of the same duplicate, check again */
i--;
}
}
_XrPenComputeSlopes(pen);
return XrStatusSuccess;
}
static int
_XrPenVerticesNeeded(double radius, double tolerance, XrMatrix *matrix)
{
double expansion, theta;
/* The determinant represents the area expansion factor of the
transform. In the worst case, this is entirely in one
dimension, which is what we assume here. */
_XrMatrixComputeDeterminant(matrix, &expansion);
if (tolerance > expansion*radius) {
return 4;
}
theta = acos(1 - tolerance/(expansion * radius));
return ceil(M_PI / theta);
}
static void
_XrPenComputeSlopes(XrPen *pen)
{
int i, i_prev;
XrPenVertex *prev, *v, *next;
for (i=0, i_prev = pen->num_vertices - 1;
i < pen->num_vertices;
i_prev = i++) {
prev = &pen->vertex[i_prev];
v = &pen->vertex[i];
next = &pen->vertex[(i + 1) % pen->num_vertices];
_ComputeSlope(&prev->pt, &v->pt, &v->slope_cw);
_ComputeSlope(&v->pt, &next->pt, &v->slope_ccw);
}
}
/* Is a clockwise of b?
*
* NOTE: The strict equality here is not significant in and of itself,
* but there are functions up above that are sensitive to it,
* (cf. _XrPenFindActiveCWVertexIndex).
*/
static int
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
{
double a_dx = XFixedToDouble(a->dx);
double a_dy = XFixedToDouble(a->dy);
double b_dx = XFixedToDouble(b->dx);
double b_dy = XFixedToDouble(b->dy);
return b_dy * a_dx > a_dy * b_dx;
}
static int
_SlopeCounterClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
{
return ! _SlopeClockwise(a, b);
}
/* Find active pen vertex for clockwise edge of stroke at the given slope.
*
* NOTE: The behavior of this function is sensitive to the sense of
* the inequality within _SlopeClockwise/_SlopeCounterClockwise.
*
* The issue is that the slope_ccw member of one pen vertex will be
* equivalent to the slope_cw member of the next pen vertex in a
* counterclockwise order. However, for this function, we care
* strongly about which vertex is returned.
*/
XrStatus
_XrPenFindActiveCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active)
{
int i;
for (i=0; i < pen->num_vertices; i++) {
if (_SlopeClockwise(slope, &pen->vertex[i].slope_ccw)
&& _SlopeCounterClockwise(slope, &pen->vertex[i].slope_cw))
break;
}
*active = i;
return XrStatusSuccess;
}
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
*
* NOTE: The behavior of this function is sensitive to the sense of
* the inequality within _SlopeClockwise/_SlopeCounterClockwise.
*/
XrStatus
_XrPenFindActiveCCWVertexIndex(XrPen *pen, XrSlopeFixed *slope, int *active)
{
int i;
XrSlopeFixed slope_reverse;
slope_reverse = *slope;
slope_reverse.dx = -slope_reverse.dx;
slope_reverse.dy = -slope_reverse.dy;
for (i=pen->num_vertices-1; i >= 0; i--) {
if (_SlopeCounterClockwise(&pen->vertex[i].slope_ccw, &slope_reverse)
&& _SlopeClockwise(&pen->vertex[i].slope_cw, &slope_reverse))
break;
}
*active = i;
return XrStatusSuccess;
}
static XrStatus
_XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenStrokeDirection dir, XrPolygon *polygon)
{
int i;
XrStatus status;
int start, stop, step;
int active = 0;
XPointFixed hull_pt;
XrSlopeFixed slope, initial_slope, final_slope;
XPointFixed *pt = spline->pts;
int num_pts = spline->num_pts;
if (dir == XrPenStrokeDirectionForward) {
start = 0;
stop = num_pts;
step = 1;
initial_slope = spline->initial_slope;
final_slope = spline->final_slope;
} else {
start = num_pts - 1;
stop = -1;
step = -1;
initial_slope = spline->final_slope;
initial_slope.dx = -initial_slope.dx;
initial_slope.dy = -initial_slope.dy;
final_slope = spline->initial_slope;
final_slope.dx = -final_slope.dx;
final_slope.dy = -final_slope.dy;
}
_XrPenFindActiveCWVertexIndex(pen, &initial_slope, &active);
i = start;
while (i != stop) {
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
hull_pt.y = pt[i].y + pen->vertex[active].pt.y;
status = _XrPolygonAddPoint(polygon, &hull_pt);
if (status)
return status;
if (i + step == stop)
slope = final_slope;
else
_ComputeSlope(&pt[i], &pt[i+step], &slope);
if (_SlopeCounterClockwise(&slope, &pen->vertex[active].slope_ccw)) {
if (++active == pen->num_vertices)
active = 0;
} else if (_SlopeClockwise(&slope, &pen->vertex[active].slope_cw)) {
if (--active == -1)
active = pen->num_vertices - 1;
} else {
i += step;
}
}
return XrStatusSuccess;
}
/* Compute outline of a given spline using the pen.
The trapezoids needed to fill that outline will be added to traps
*/
XrStatus
_XrPenStrokeSpline(XrPen *pen,
XrSpline *spline,
double tolerance,
XrTraps *traps)
{
XrStatus status;
XrPolygon polygon;
_XrPolygonInit(&polygon);
status = _XrSplineDecompose(spline, tolerance);
if (status)
return status;
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionForward, &polygon);
if (status)
return status;
status = _XrPenStrokeSplineHalf(pen, spline, XrPenStrokeDirectionReverse, &polygon);
if (status)
return status;
_XrPolygonClose(&polygon);
_XrTrapsTessellatePolygon(traps, &polygon, XrFillRuleWinding);
_XrPolygonDeinit(&polygon);
return XrStatusSuccess;
}

View file

@ -1,173 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "xrint.h"
#define XR_POLYGON_GROWTH_INC 10
/* private functions */
static XrStatus
_XrPolygonGrowBy(XrPolygon *polygon, int additional);
static void
_XrPolygonSetLastPoint(XrPolygon *polygon, XPointFixed *pt);
void
_XrPolygonInit(XrPolygon *polygon)
{
polygon->num_edges = 0;
polygon->edges_size = 0;
polygon->edges = NULL;
polygon->first_pt_defined = 0;
polygon->last_pt_defined = 0;
polygon->closed = 0;
}
void
_XrPolygonDeinit(XrPolygon *polygon)
{
if (polygon->edges_size) {
free(polygon->edges);
polygon->edges = NULL;
polygon->edges_size = 0;
polygon->num_edges = 0;
}
polygon->first_pt_defined = 0;
polygon->last_pt_defined = 0;
polygon->closed = 0;
}
static XrStatus
_XrPolygonGrowBy(XrPolygon *polygon, int additional)
{
XrEdge *new_edges;
int old_size = polygon->edges_size;
int new_size = polygon->num_edges + additional;
if (new_size <= polygon->edges_size) {
return XrStatusSuccess;
}
polygon->edges_size = new_size;
new_edges = realloc(polygon->edges, polygon->edges_size * sizeof(XrEdge));
if (new_edges == NULL) {
polygon->edges_size = old_size;
return XrStatusNoMemory;
}
polygon->edges = new_edges;
return XrStatusSuccess;
}
static void
_XrPolygonSetLastPoint(XrPolygon *polygon, XPointFixed *pt)
{
polygon->last_pt = *pt;
polygon->last_pt_defined = 1;
}
XrStatus
_XrPolygonAddEdge(XrPolygon *polygon, XPointFixed *p1, XPointFixed *p2)
{
XrStatus status;
XrEdge *edge;
if (! polygon->first_pt_defined) {
polygon->first_pt = *p1;
polygon->first_pt_defined = 1;
polygon->closed = 0;
}
/* drop horizontal edges */
if (p1->y == p2->y) {
goto DONE;
}
if (polygon->num_edges >= polygon->edges_size) {
status = _XrPolygonGrowBy(polygon, XR_POLYGON_GROWTH_INC);
if (status) {
return status;
}
}
edge = &polygon->edges[polygon->num_edges];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
edge->clockWise = True;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
edge->clockWise = False;
}
polygon->num_edges++;
DONE:
_XrPolygonSetLastPoint(polygon, p2);
return XrStatusSuccess;
}
XrStatus
_XrPolygonAddPoint(XrPolygon *polygon, XPointFixed *pt)
{
XrStatus status = XrStatusSuccess;
if (polygon->last_pt_defined) {
status = _XrPolygonAddEdge(polygon, &polygon->last_pt, pt);
} else {
_XrPolygonSetLastPoint(polygon, pt);
}
return status;
}
XrStatus
_XrPolygonClose(XrPolygon *polygon)
{
XrStatus status;
if (polygon->closed == 0 && polygon->last_pt_defined) {
status = _XrPolygonAddEdge(polygon, &polygon->last_pt, &polygon->first_pt);
if (status)
return status;
polygon->closed = 1;
polygon->first_pt_defined = 0;
}
return XrStatusSuccess;
}

View file

@ -1,269 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
static XrStatus
_XrSplineGrowBy(XrSpline *spline, int additional);
static XrStatus
_XrSplineAddPoint(XrSpline *spline, XPointFixed *pt);
static void
_LerpHalf(XPointFixed *a, XPointFixed *b, XPointFixed *result);
static void
_DeCastlejau(XrSpline *spline, XrSpline *s1, XrSpline *s2);
static double
_XrSplineErrorSquared(XrSpline *spline);
static XrStatus
_XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *result);
#define XR_SPLINE_GROWTH_INC 100
XrIntStatus
_XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
spline->a = *a;
spline->b = *b;
spline->c = *c;
spline->d = *d;
if (a->x != b->x || a->y != b->y) {
_ComputeSlope(&spline->a, &spline->b, &spline->initial_slope);
} else if (a->x != c->x || a->y != c->y) {
_ComputeSlope(&spline->a, &spline->c, &spline->initial_slope);
} else if (a->x != d->x || a->y != d->y) {
_ComputeSlope(&spline->a, &spline->d, &spline->initial_slope);
} else {
return XrIntStatusDegenerate;
}
if (c->x != d->x || c->y != d->y) {
_ComputeSlope(&spline->c, &spline->d, &spline->final_slope);
} else if (b->x != d->x || b->y != d->y) {
_ComputeSlope(&spline->b, &spline->d, &spline->final_slope);
} else {
_ComputeSlope(&spline->a, &spline->d, &spline->final_slope);
}
spline->num_pts = 0;
spline->pts_size = 0;
spline->pts = NULL;
return XrStatusSuccess;
}
void
_XrSplineDeinit(XrSpline *spline)
{
spline->num_pts = 0;
spline->pts_size = 0;
free(spline->pts);
spline->pts = NULL;
}
static XrStatus
_XrSplineGrowBy(XrSpline *spline, int additional)
{
XPointFixed *new_pts;
int old_size = spline->pts_size;
int new_size = spline->num_pts + additional;
if (new_size <= spline->pts_size)
return XrStatusSuccess;
spline->pts_size = new_size;
new_pts = realloc(spline->pts, spline->pts_size * sizeof(XPointFixed));
if (new_pts == NULL) {
spline->pts_size = old_size;
return XrStatusNoMemory;
}
spline->pts = new_pts;
return XrStatusSuccess;
}
static XrStatus
_XrSplineAddPoint(XrSpline *spline, XPointFixed *pt)
{
XrStatus status;
if (spline->num_pts >= spline->pts_size) {
status = _XrSplineGrowBy(spline, XR_SPLINE_GROWTH_INC);
if (status)
return status;
}
spline->pts[spline->num_pts] = *pt;
spline->num_pts++;
return XrStatusSuccess;
}
static void
_LerpHalf(XPointFixed *a, XPointFixed *b, XPointFixed *result)
{
result->x = a->x + ((b->x - a->x) >> 1);
result->y = a->y + ((b->y - a->y) >> 1);
}
static void
_DeCastlejau(XrSpline *spline, XrSpline *s1, XrSpline *s2)
{
XPointFixed ab, bc, cd;
XPointFixed abbc, bccd;
XPointFixed final;
_LerpHalf(&spline->a, &spline->b, &ab);
_LerpHalf(&spline->b, &spline->c, &bc);
_LerpHalf(&spline->c, &spline->d, &cd);
_LerpHalf(&ab, &bc, &abbc);
_LerpHalf(&bc, &cd, &bccd);
_LerpHalf(&abbc, &bccd, &final);
s1->a = spline->a;
s1->b = ab;
s1->c = abbc;
s1->d = final;
s2->a = final;
s2->b = bccd;
s2->c = cd;
s2->d = spline->d;
}
static double
_PointDistanceSquaredToPoint(XPointFixed *a, XPointFixed *b)
{
double dx = XFixedToDouble(b->x - a->x);
double dy = XFixedToDouble(b->y - a->y);
return dx*dx + dy*dy;
}
static double
_PointDistanceSquaredToSegment(XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
{
double u;
double dx, dy;
double pdx, pdy;
XPointFixed px;
/* intersection point (px):
px = p1 + u(p2 - p1)
(p - px) . (p2 - p1) = 0
Thus:
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
*/
dx = XFixedToDouble(p2->x - p1->x);
dy = XFixedToDouble(p2->y - p1->y);
if (dx == 0 && dy == 0)
return _PointDistanceSquaredToPoint(p, p1);
pdx = XFixedToDouble(p->x - p1->x);
pdy = XFixedToDouble(p->y - p1->y);
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
if (u <= 0)
return _PointDistanceSquaredToPoint(p, p1);
else if (u >= 1)
return _PointDistanceSquaredToPoint(p, p2);
px.x = p1->x + u * (p2->x - p1->x);
px.y = p1->y + u * (p2->y - p1->y);
return _PointDistanceSquaredToPoint(p, &px);
}
/* Return an upper bound on the error (squared) that could result from approximating
a spline as a line segment connecting the two endpoints */
static double
_XrSplineErrorSquared(XrSpline *spline)
{
double berr, cerr;
berr = _PointDistanceSquaredToSegment(&spline->b, &spline->a, &spline->d);
cerr = _PointDistanceSquaredToSegment(&spline->c, &spline->a, &spline->d);
if (berr > cerr)
return berr;
else
return cerr;
}
static XrStatus
_XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *result)
{
XrStatus status;
XrSpline s1, s2;
if (_XrSplineErrorSquared(spline) < tolerance_squared) {
return _XrSplineAddPoint(result, &spline->a);
}
_DeCastlejau(spline, &s1, &s2);
status = _XrSplineDecomposeInto(&s1, tolerance_squared, result);
if (status)
return status;
status = _XrSplineDecomposeInto(&s2, tolerance_squared, result);
if (status)
return status;
return XrStatusSuccess;
}
XrStatus
_XrSplineDecompose(XrSpline *spline, double tolerance)
{
XrStatus status;
if (spline->pts_size) {
_XrSplineDeinit(spline);
}
status = _XrSplineDecomposeInto(spline, tolerance * tolerance, spline);
if (status)
return status;
status = _XrSplineAddPoint(spline, &spline->d);
if (status)
return status;
return XrStatusSuccess;
}

View file

@ -1,108 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "xrint.h"
XrState *
_XrStateCreate(void)
{
XrStatus status;
XrState *xrs;
xrs = malloc(sizeof(XrState));
if (xrs) {
status = _XrStateInit(xrs);
if (status) {
free(xrs);
return NULL;
}
}
return xrs;
}
XrStatus
_XrStateInit(XrState *xrs)
{
xrs->stack = NULL;
xrs->status = XrStatusSuccess;
return _XrStatePush(xrs);
}
void
_XrStateDeinit(XrState *xrs)
{
while (xrs->stack) {
_XrStatePop(xrs);
}
}
void
_XrStateDestroy(XrState *xrs)
{
_XrStateDeinit(xrs);
free(xrs);
}
XrStatus
_XrStatePush(XrState *xrs)
{
XrGState *top;
if (xrs->stack) {
top = _XrGStateClone(xrs->stack);
} else {
top = _XrGStateCreate();
}
if (top == NULL)
return XrStatusNoMemory;
top->next = xrs->stack;
xrs->stack = top;
return XrStatusSuccess;
}
XrStatus
_XrStatePop(XrState *xrs)
{
XrGState *top;
if (xrs->stack == NULL)
return XrStatusInvalidRestore;
top = xrs->stack;
xrs->stack = top->next;
_XrGStateDestroy(top);
return XrStatusSuccess;
}

View file

@ -1,643 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xrint.h"
/* private functions */
static void
_TranslatePoint(XPointFixed *pt, XPointFixed *offset);
static int
_XrStrokerFaceClockwise(XrStrokeFace *in, XrStrokeFace *out);
static XrStatus
_XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out);
static void
_XrStrokerStartDash (XrStroker *stroker)
{
XrGState *gstate = stroker->gstate;
double offset;
int on = 1;
int i = 0;
offset = gstate->dash_offset;
while (offset >= gstate->dash[i]) {
offset -= gstate->dash[i];
on = 1-on;
if (++i == gstate->num_dashes)
i = 0;
}
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_remain = gstate->dash[i] - offset;
}
static void
_XrStrokerStepDash (XrStroker *stroker, double step)
{
XrGState *gstate = stroker->gstate;
stroker->dash_remain -= step;
if (stroker->dash_remain <= 0) {
stroker->dash_index++;
if (stroker->dash_index == gstate->num_dashes)
stroker->dash_index = 0;
stroker->dash_on = 1-stroker->dash_on;
stroker->dash_remain = gstate->dash[stroker->dash_index];
}
}
void
_XrStrokerInit(XrStroker *stroker, XrGState *gstate, XrTraps *traps)
{
stroker->gstate = gstate;
stroker->traps = traps;
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
if (gstate->dash)
_XrStrokerStartDash (stroker);
}
void
_XrStrokerDeinit(XrStroker *stroker)
{
/* nothing to do here */
}
static void
_TranslatePoint(XPointFixed *pt, XPointFixed *offset)
{
pt->x += offset->x;
pt->y += offset->y;
}
static int
_XrStrokerFaceClockwise(XrStrokeFace *in, XrStrokeFace *out)
{
XPointDouble d_in, d_out;
d_in.x = XFixedToDouble(in->cw.x - in->pt.x);
d_in.y = XFixedToDouble(in->cw.y - in->pt.y);
d_out.x = XFixedToDouble(out->cw.x - out->pt.x);
d_out.y = XFixedToDouble(out->cw.y - out->pt.y);
return d_out.y * d_in.x > d_in.y * d_out.x;
}
static XrStatus
_XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out)
{
XrStatus status;
XrGState *gstate = stroker->gstate;
int clockwise = _XrStrokerFaceClockwise (out, in);
XPointFixed *inpt, *outpt;
if (in->cw.x == out->cw.x
&& in->cw.y == out->cw.y
&& in->ccw.x == out->ccw.x
&& in->ccw.y == out->ccw.y) {
return XrStatusSuccess;
}
if (clockwise) {
inpt = &in->ccw;
outpt = &out->ccw;
} else {
inpt = &in->cw;
outpt = &out->cw;
}
switch (gstate->line_join) {
case XrLineJoinRound: {
int i;
int start, step, stop;
XPointFixed tri[3], initial, final;
XrPen *pen = &gstate->pen_regular;
tri[0] = in->pt;
if (clockwise) {
initial = in->ccw;
_XrPenFindActiveCCWVertexIndex(pen, &in->dev_vector, &start);
step = -1;
_XrPenFindActiveCCWVertexIndex(pen, &out->dev_vector, &stop);
final = out->ccw;
} else {
initial = in->cw;
_XrPenFindActiveCWVertexIndex(pen, &in->dev_vector, &start);
step = +1;
_XrPenFindActiveCWVertexIndex(pen, &out->dev_vector, &stop);
final = out->cw;
}
i = start;
tri[1] = initial;
while (i != stop) {
tri[2] = in->pt;
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
_XrTrapsTessellateTriangle(stroker->traps, tri);
tri[1] = tri[2];
i += step;
if (i < 0)
i = pen->num_vertices - 1;
if (i >= pen->num_vertices)
i = 0;
}
tri[2] = final;
return _XrTrapsTessellateTriangle(stroker->traps, tri);
}
case XrLineJoinMiter:
default: {
XrPolygon polygon;
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
XDouble ml = gstate->miter_limit;
_XrPolygonInit (&polygon);
if (2 <= ml * ml * (1 - c)) {
XDouble x1, y1, x2, y2;
XDouble mx, my;
XDouble dx1, dx2, dy1, dy2;
XPointFixed outer;
x1 = XFixedToDouble(inpt->x);
y1 = XFixedToDouble(inpt->y);
dx1 = in->usr_vector.x;
dy1 = in->usr_vector.y;
_XrTransformDistance(&gstate->ctm, &dx1, &dy1);
x2 = XFixedToDouble(outpt->x);
y2 = XFixedToDouble(outpt->y);
dx2 = out->usr_vector.x;
dy2 = out->usr_vector.y;
_XrTransformDistance(&gstate->ctm, &dx2, &dy2);
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
(dx1 * dy2 - dx2 * dy1));
if (dy1)
mx = (my - y1) * dx1 / dy1 + x1;
else
mx = (my - y2) * dx2 / dy2 + x2;
outer.x = XDoubleToFixed(mx);
outer.y = XDoubleToFixed(my);
_XrPolygonAddEdge (&polygon, &in->pt, inpt);
_XrPolygonAddEdge (&polygon, inpt, &outer);
_XrPolygonAddEdge (&polygon, &outer, outpt);
_XrPolygonAddEdge (&polygon, outpt, &in->pt);
status = _XrTrapsTessellatePolygon (stroker->traps,
&polygon,
XrFillRuleWinding);
_XrPolygonDeinit (&polygon);
return status;
}
/* fall through ... */
}
case XrLineJoinBevel: {
XPointFixed tri[3];
tri[0] = in->pt;
tri[1] = *inpt;
tri[2] = *outpt;
return _XrTrapsTessellateTriangle (stroker->traps, tri);
}
}
}
static XrStatus
_XrStrokerCap(XrStroker *stroker, XrStrokeFace *f)
{
XrStatus status;
XrGState *gstate = stroker->gstate;
if (gstate->line_cap == XrLineCapButt)
return XrStatusSuccess;
switch (gstate->line_cap) {
case XrLineCapRound: {
int i;
int start, stop;
XrSlopeFixed slope;
XPointFixed tri[3];
XrPen *pen = &gstate->pen_regular;
slope = f->dev_vector;
_XrPenFindActiveCWVertexIndex(pen, &slope, &start);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
_XrPenFindActiveCWVertexIndex(pen, &slope, &stop);
tri[0] = f->pt;
tri[1] = f->cw;
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
tri[2] = f->pt;
_TranslatePoint(&tri[2], &pen->vertex[i].pt);
_XrTrapsTessellateTriangle(stroker->traps, tri);
tri[1] = tri[2];
}
tri[2] = f->ccw;
return _XrTrapsTessellateTriangle(stroker->traps, tri);
}
case XrLineCapSquare: {
double dx, dy;
XrSlopeFixed fvector;
XPointFixed occw, ocw;
XrPolygon polygon;
_XrPolygonInit (&polygon);
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= gstate->line_width / 2.0;
dy *= gstate->line_width / 2.0;
_XrTransformDistance(&gstate->ctm, &dx, &dy);
fvector.dx = XDoubleToFixed(dx);
fvector.dy = XDoubleToFixed(dy);
occw.x = f->ccw.x + fvector.dx;
occw.y = f->ccw.y + fvector.dy;
ocw.x = f->cw.x + fvector.dx;
ocw.y = f->cw.y + fvector.dy;
_XrPolygonAddEdge (&polygon, &f->cw, &ocw);
_XrPolygonAddEdge (&polygon, &ocw, &occw);
_XrPolygonAddEdge (&polygon, &occw, &f->ccw);
_XrPolygonAddEdge (&polygon, &f->ccw, &f->cw);
status = _XrTrapsTessellatePolygon (stroker->traps, &polygon, XrFillRuleWinding);
_XrPolygonDeinit (&polygon);
return status;
}
case XrLineCapButt:
default:
return XrStatusSuccess;
}
}
static void
_ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFace *face)
{
double mag, tmp;
double dx, dy;
XPointDouble usr_vector;
XPointFixed offset_ccw, offset_cw;
dx = XFixedToDouble(slope->dx);
dy = XFixedToDouble(slope->dy);
_XrTransformDistance(&gstate->ctm_inverse, &dx, &dy);
mag = sqrt(dx * dx + dy * dy);
if (mag == 0) {
/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
return;
}
dx /= mag;
dy /= mag;
usr_vector.x = dx;
usr_vector.y = dy;
tmp = dx;
dx = - dy * (gstate->line_width / 2.0);
dy = tmp * (gstate->line_width / 2.0);
_XrTransformDistance(&gstate->ctm, &dx, &dy);
offset_ccw.x = XDoubleToFixed(dx);
offset_ccw.y = XDoubleToFixed(dy);
offset_cw.x = -offset_ccw.x;
offset_cw.y = -offset_ccw.y;
face->ccw = *pt;
_TranslatePoint(&face->ccw, &offset_ccw);
face->pt = *pt;
face->cw = *pt;
_TranslatePoint(&face->cw, &offset_cw);
face->usr_vector.x = usr_vector.x;
face->usr_vector.y = usr_vector.y;
face->dev_vector = *slope;
}
static XrStatus
_XrStrokerAddSubEdge (XrStroker *stroker, XPointFixed *p1, XPointFixed *p2,
XrStrokeFace *start, XrStrokeFace *end)
{
XrGState *gstate = stroker->gstate;
XPointFixed quad[4];
XrSlopeFixed slope;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in _ComputeFace). The key behavior is that
degenerate paths should draw as much as possible. */
return XrStatusSuccess;
}
_ComputeSlope(p1, p2, &slope);
_ComputeFace(p1, &slope, gstate, start);
/* XXX: This could be optimized slightly by not calling
_ComputeFace again but rather translating the relevant
fields from start. */
_ComputeFace(p2, &slope, gstate, end);
quad[0] = start->cw;
quad[1] = start->ccw;
quad[2] = end->ccw;
quad[3] = end->cw;
return _XrTrapsTessellateRectangle(stroker->traps, quad);
}
XrStatus
_XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrStatus status;
XrStroker *stroker = closure;
XrStrokeFace start, end;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in XrStrokerAddSubEdge and in _ComputeFace). The
key behavior is that degenerate paths should draw as much
as possible. */
return XrStatusSuccess;
}
status = _XrStrokerAddSubEdge (stroker, p1, p2, &start, &end);
if (status)
return status;
if (stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
return XrStatusSuccess;
}
/*
* Dashed lines. Cap each dash end, join around turns when on
*/
XrStatus
_XrStrokerAddEdgeDashed (void *closure, XPointFixed *p1, XPointFixed *p2)
{
XrStatus status = XrStatusSuccess;
XrStroker *stroker = closure;
XrGState *gstate = stroker->gstate;
double mag, remain, tmp;
double dx, dy;
double dx2, dy2;
XPointFixed fd1, fd2;
int first = 1;
XrStrokeFace sub_start, sub_end;
dx = XFixedToDouble(p2->x - p1->x);
dy = XFixedToDouble(p2->y - p1->y);
_XrTransformDistance(&gstate->ctm_inverse, &dx, &dy);
mag = sqrt(dx *dx + dy * dy);
remain = mag;
fd1 = *p1;
while (remain) {
tmp = stroker->dash_remain;
if (tmp > remain)
tmp = remain;
remain -= tmp;
dx2 = dx * (mag - remain)/mag;
dy2 = dy * (mag - remain)/mag;
_XrTransformDistance (&gstate->ctm, &dx2, &dy2);
fd2.x = XDoubleToFixed (dx2);
fd2.y = XDoubleToFixed (dy2);
fd2.x += p1->x;
fd2.y += p1->y;
/*
* XXX simplify this case analysis
*/
if (stroker->dash_on) {
status = _XrStrokerAddSubEdge (stroker, &fd1, &fd2, &sub_start, &sub_end);
if (status)
return status;
if (!first) {
/*
* Not first dash in this segment, cap start
*/
status = _XrStrokerCap (stroker, &sub_start);
if (status)
return status;
} else {
/*
* First in this segment, join to any prev, else
* if at start of sub-path, mark position, else
* cap
*/
if (stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &sub_start);
if (status)
return status;
} else {
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = sub_start;
} else {
status = _XrStrokerCap (stroker, &sub_start);
if (status)
return status;
}
}
}
if (remain) {
/*
* Cap if not at end of segment
*/
status = _XrStrokerCap (stroker, &sub_end);
if (status)
return status;
} else {
/*
* Mark previous line face and fix up next time
* through
*/
stroker->prev = sub_end;
stroker->have_prev = 1;
}
} else {
/*
* If starting with off dash, check previous face
* and cap if necessary
*/
if (first) {
if (stroker->have_prev) {
status = _XrStrokerCap (stroker, &stroker->prev);
if (status)
return status;
}
}
if (!remain)
stroker->have_prev = 0;
}
_XrStrokerStepDash (stroker, tmp);
fd1 = fd2;
first = 0;
}
stroker->is_first = 0;
return status;
}
XrStatus
_XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
{
XrStatus status = XrStatusSuccess;
XrStroker *stroker = closure;
XrGState *gstate = stroker->gstate;
XrSpline spline;
XrPen pen;
XrStrokeFace start, end;
XPointFixed extra_points[4];
status = _XrSplineInit(&spline, a, b, c, d);
if (status == XrIntStatusDegenerate)
return XrStatusSuccess;
status = _XrPenInitCopy(&pen, &gstate->pen_regular);
if (status)
goto CLEANUP_SPLINE;
_ComputeFace(a, &spline.initial_slope, gstate, &start);
_ComputeFace(d, &spline.final_slope, gstate, &end);
if (stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &start);
if (status)
return status;
} else {
stroker->have_prev = 1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
extra_points[0] = start.cw;
extra_points[0].x -= start.pt.x;
extra_points[0].y -= start.pt.y;
extra_points[1] = start.ccw;
extra_points[1].x -= start.pt.x;
extra_points[1].y -= start.pt.y;
extra_points[2] = end.cw;
extra_points[2].x -= end.pt.x;
extra_points[2].y -= end.pt.y;
extra_points[3] = end.ccw;
extra_points[3].x -= end.pt.x;
extra_points[3].y -= end.pt.y;
status = _XrPenAddPoints(&pen, extra_points, 4);
if (status)
goto CLEANUP_PEN;
status = _XrPenStrokeSpline(&pen, &spline, gstate->tolerance, stroker->traps);
if (status)
goto CLEANUP_PEN;
CLEANUP_PEN:
_XrPenDeinit(&pen);
CLEANUP_SPLINE:
_XrSplineDeinit(&spline);
return status;
}
XrStatus
_XrStrokerDoneSubPath (void *closure, XrSubPathDone done)
{
XrStatus status;
XrStroker *stroker = closure;
switch (done) {
case XrSubPathDoneJoin:
if (stroker->have_first && stroker->have_prev) {
status = _XrStrokerJoin (stroker, &stroker->prev, &stroker->first);
if (status)
return status;
break;
}
/* fall through... */
case XrSubPathDoneCap:
if (stroker->have_first) {
XPointFixed t;
/* The initial cap needs an outward facing vector. Reverse everything */
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
t = stroker->first.cw;
stroker->first.cw = stroker->first.ccw;
stroker->first.ccw = t;
status = _XrStrokerCap (stroker, &stroker->first);
if (status)
return status;
}
if (stroker->have_prev) {
status = _XrStrokerCap (stroker, &stroker->prev);
if (status)
return status;
}
break;
}
stroker->have_prev = 0;
stroker->have_first = 0;
stroker->is_first = 1;
return XrStatusSuccess;
}
XrStatus
_XrStrokerDonePath (void *closure)
{
return XrStatusSuccess;
}

View file

@ -1,386 +0,0 @@
/*
* $XFree86: $
*
* Copyright © 2002 Carl D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carl
* D. Worth not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Carl D. Worth makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "xrint.h"
XrSurface *
XrSurfaceCreateForDrawable (Display *dpy,
Drawable drawable,
Visual *visual,
XrFormat format,
Colormap colormap)
{
XrSurface *surface;
surface = malloc(sizeof(XrSurface));
if (surface == NULL)
return NULL;
surface->dpy = dpy;
surface->image_data = NULL;
surface->xc_surface = XcSurfaceCreateForDrawable (dpy, drawable, visual, format, colormap);
if (surface->xc_surface == NULL) {
free (surface);
return NULL;
}
/* XXX: We should really get this value from somewhere like Xft.dpy */
surface->ppm = 3780;
surface->ref_count = 1;
return surface;
}
/* XXX: These definitions are 100% bogus. The problem that needs to be
fixed is that Ic needs to export a real API for passing in
formats. */
#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
((type) << 16) | \
((a) << 12) | \
((r) << 8) | \
((g) << 4) | \
((b)))
/*
* gray/color formats use a visual index instead of argb
*/
#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \
((type) << 16) | \
((vi)))
#define PICT_TYPE_A 1
#define PICT_TYPE_ARGB 2
#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2)
/* 32bpp formats */
#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8)
#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8)
#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0)
#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0)
static int
_XrFormatBPP (XrFormat format)
{
switch (format) {
case XrFormatA1:
return 1;
break;
case XrFormatA8:
return 8;
break;
case XrFormatRGB24:
case XrFormatARGB32:
default:
return 32;
break;
}
}
XrSurface *
XrSurfaceCreateForImage (char *data,
XrFormat format,
int width,
int height,
int stride)
{
XrSurface *surface;
IcFormat icformat;
IcImage *image;
int bpp;
/* XXX: This all needs to change, (but IcFormatInit interface needs to change first) */
switch (format) {
case XrFormatARGB32:
IcFormatInit (&icformat, PICT_a8r8g8b8);
bpp = 32;
break;
case XrFormatRGB24:
IcFormatInit (&icformat, PICT_x8r8g8b8);
bpp = 32;
break;
case XrFormatA8:
IcFormatInit (&icformat, PICT_a8);
bpp = 8;
break;
case XrFormatA1:
IcFormatInit (&icformat, PICT_a1);
bpp = 1;
break;
default:
return NULL;
}
surface = malloc(sizeof(XrSurface));
if (surface == NULL)
return NULL;
surface->dpy = NULL;
surface->image_data = NULL;
image = IcImageCreateForData ((IcBits *) data, &icformat, width, height, _XrFormatBPP (format), stride);
if (image == NULL) {
free (surface);
return NULL;
}
surface->xc_surface = XcSurfaceCreateForIcImage (image);
if (surface->xc_surface == NULL) {
IcImageDestroy (image);
free (surface);
return NULL;
}
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
return surface;
}
XrSurface *
XrSurfaceCreateNextTo (XrSurface *neighbor, XrFormat format, int width, int height)
{
return XrSurfaceCreateNextToSolid (neighbor, format, width, height, 0, 0, 0, 0);
}
static int
_XrFormatDepth (XrFormat format)
{
switch (format) {
case XrFormatA1:
return 1;
case XrFormatA8:
return 8;
case XrFormatRGB24:
return 24;
case XrFormatARGB32:
default:
return 32;
}
}
XrSurface *
XrSurfaceCreateNextToSolid (XrSurface *neighbor,
XrFormat format,
int width,
int height,
double red,
double green,
double blue,
double alpha)
{
XrSurface *surface = NULL;
XrColor color;
/* XXX: CreateNextTo should perhaps move down to Xc, (then we
could drop xrsurface->dpy as well) */
if (neighbor->dpy) {
Display *dpy = neighbor->dpy;
int scr = DefaultScreen (dpy);
Pixmap pix = XCreatePixmap(dpy,
DefaultRootWindow (dpy),
width, height,
_XrFormatDepth (format));
surface = XrSurfaceCreateForDrawable (dpy, pix,
NULL,
format,
DefaultColormap (dpy, scr));
/* XXX: huh? This should be fine since we already created a picture
from the pixmap, right?? (Somehow, it seems to be causing some
breakage).
XFreePixmap(surface->dpy, pix);
*/
} else {
char *data;
int stride;
stride = ((width * _XrFormatBPP (format)) + 7) >> 3;
data = malloc (stride * height);
if (data == NULL)
return NULL;
surface = XrSurfaceCreateForImage (data, format,
width, height, stride);
/* lodge data in the surface structure to be freed with the surface */
surface->image_data = data;
}
/* XXX: Initializing the color in this way assumes
non-pre-multiplied alpha. I'm not sure that that's what I want
to do or not. */
_XrColorInit (&color);
_XrColorSetRGB (&color, red, green, blue);
_XrColorSetAlpha (&color, alpha);
_XrSurfaceFillRectangle (surface, XrOperatorSrc, &color, 0, 0, width, height);
return surface;
}
void
_XrSurfaceReference(XrSurface *surface)
{
if (surface == NULL)
return;
surface->ref_count++;
}
void
XrSurfaceDestroy(XrSurface *surface)
{
if (surface == NULL)
return;
surface->ref_count--;
if (surface->ref_count)
return;
surface->dpy = 0;
XcSurfaceDestroy (surface->xc_surface);
surface->xc_surface = NULL;
if (surface->image_data)
free(surface->image_data);
surface->image_data = NULL;
free(surface);
}
XrStatus
XrSurfacePutImage (XrSurface *surface,
char *data,
int width,
int height,
int stride)
{
XcSurfacePutImage (surface->xc_surface, data,
width, height, stride);
return XrStatusSuccess;
}
/* XXX: Symmetry demands an XrSurfaceGetImage as well */
/* XXX: We may want to move to projective matrices at some point. If
nothing else, that would eliminate the two different transform data
structures we have here. */
XrStatus
XrSurfaceSetMatrix(XrSurface *surface, XrMatrix *matrix)
{
XTransform xtransform;
xtransform.matrix[0][0] = XDoubleToFixed(matrix->m[0][0]);
xtransform.matrix[0][1] = XDoubleToFixed(matrix->m[1][0]);
xtransform.matrix[0][2] = XDoubleToFixed(matrix->m[2][0]);
xtransform.matrix[1][0] = XDoubleToFixed(matrix->m[0][1]);
xtransform.matrix[1][1] = XDoubleToFixed(matrix->m[1][1]);
xtransform.matrix[1][2] = XDoubleToFixed(matrix->m[2][1]);
xtransform.matrix[2][0] = 0;
xtransform.matrix[2][1] = 0;
xtransform.matrix[2][2] = XDoubleToFixed(1);
XcSurfaceSetTransform(surface->xc_surface,
&xtransform);
return XrStatusSuccess;
}
XrStatus
XrSurfaceGetMatrix (XrSurface *surface, XrMatrix *matrix)
{
XTransform xtransform;
XcSurfaceGetTransform (surface->xc_surface, &xtransform);
matrix->m[0][0] = XFixedToDouble (xtransform.matrix[0][0]);
matrix->m[1][0] = XFixedToDouble (xtransform.matrix[0][1]);
matrix->m[2][0] = XFixedToDouble (xtransform.matrix[0][2]);
matrix->m[0][1] = XFixedToDouble (xtransform.matrix[1][0]);
matrix->m[1][1] = XFixedToDouble (xtransform.matrix[1][1]);
matrix->m[2][1] = XFixedToDouble (xtransform.matrix[1][2]);
return XrStatusSuccess;
}
XrStatus
XrSurfaceSetFilter(XrSurface *surface, XrFilter filter)
{
XcSurfaceSetFilter(surface->xc_surface, filter);
return XrStatusSuccess;
}
/* XXX: The Xc version of this function isn't quite working yet
XrStatus
XrSurfaceSetClipRegion (XrSurface *surface, Region region)
{
XcSurfaceSetClipRegion (surface->xc_surface, region);
return XrStatusSuccess;
}
*/
XrStatus
XrSurfaceSetRepeat (XrSurface *surface, int repeat)
{
XcSurfaceSetRepeat (surface->xc_surface, repeat);
return XrStatusSuccess;
}
/* XXX: This function is going away, right? */
Picture
_XrSurfaceGetPicture(XrSurface *surface)
{
return XcSurfaceGetPicture(surface->xc_surface);
}
void
_XrSurfaceFillRectangle (XrSurface *surface,
XrOperator operator,
XrColor *color,
int x,
int y,
int width,
int height)
{
XcFillRectangle (operator,
surface->xc_surface,
&color->xc_color,
x, y,
width, height);
}

49
util/xr2cairo Executable file
View file

@ -0,0 +1,49 @@
#!/bin/sh
set -e
if [ $# -lt 1 ]; then
argv0=`basename $0`
echo "$argv0: Convert source code written for Xr to use Cairo instead." >&2
echo "" >&2
echo "Usage: $argv0 file [...]" >&2
exit 1
fi
xr2cairo() {
file=$1
backup=$file.xr
if [ -e $backup ]; then
echo "Warning: Backup file $backup already exists --- not backing up this time." >&2
else
cp $file $backup
fi
sed -e '
s/\(Xr[a-zA-Z]*\)RGB/\1Rgb/g
s/\(Xr[a-zA-Z]*\)NextTo/\1Similar/g
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3_\4_\5\E/g
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3_\4\E/g
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3\E/g
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z0-9]\+\)/\Lcairo_\1_\2\E/g
s/Xr\([A-Z]\+[a-z]\+\)/\Lcairo_\1\E/g
s/\(cairo_\(operator\|status\|fill_rule\|line_cap\|line_join\|filter\|format\)_[a-z0-9_]\{2,\}\)/\U\1/g
s/cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)$/cairo_\1_t/g
s/cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)\([^_]\)/cairo_\1_t\2/g
s/_cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)_t/cairo_\1/g
s/cairo_state/cairo_t/g
s/_cairo_t/cairo/g
s/Xr\.h/cairo.h/g
' $backup > $file
}
while [ $# -gt 0 ]; do
file=$1
shift
xr2cairo $file
done