diff options
author | Carl Worth <cworth@cworth.org> | 2003-07-18 11:34:19 +0000 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2003-07-18 11:34:19 +0000 |
commit | dc1e96ae3502a81729839f4bcafcbc1fd00fc1bc (patch) | |
tree | 859d5aa4a6315c8355b3c5e87826e8722c50c6c5 /src | |
parent | 4a57fd0881b242d98ea74abb46c8c402faeb1960 (diff) |
Renamed everything from Xr* to cairo_*
Diffstat (limited to 'src')
50 files changed, 11645 insertions, 7321 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4cb40d263..b63772e52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/Xr.h b/src/Xr.h deleted file mode 100644 index 6462e10e2..000000000 --- a/src/Xr.h +++ /dev/null @@ -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 - diff --git a/src/cairo-color.c b/src/cairo-color.c new file mode 100644 index 000000000..dab09ad27 --- /dev/null +++ b/src/cairo-color.c @@ -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); +} diff --git a/src/cairo-font.c b/src/cairo-font.c new file mode 100644 index 000000000..001ea0aca --- /dev/null +++ b/src/cairo-font.c @@ -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; +} diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c new file mode 100644 index 000000000..f83833aea --- /dev/null +++ b/src/cairo-gstate.c @@ -0,0 +1,1123 @@ +/* + * 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 void +_cairo_gstate_set_current_pt (cairo_gstate_t *gstate, double x, double y); + +static cairo_status_t +_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, + cairo_surface_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps); + +cairo_gstate_t * +_cairo_gstate_create () +{ + cairo_gstate_t *gstate; + + gstate = malloc (sizeof (cairo_gstate_t)); + + if (gstate) + _cairo_gstate_init (gstate); + + return gstate; +} + +void +_cairo_gstate_init (cairo_gstate_t *gstate) +{ + gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT; + + gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; + + gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT; + gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT; + gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT; + gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT; + + gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; + + gstate->dash = NULL; + gstate->num_dashes = 0; + gstate->dash_offset = 0.0; + + _cairo_font_init (&gstate->font); + + gstate->surface = NULL; + gstate->solid = NULL; + gstate->pattern = NULL; + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; + + gstate->clip.surface = NULL; + + gstate->alpha = 1.0; + _cairo_color_init (&gstate->color); + + /* 3780 PPM (~96DPI) is a good enough assumption until we get a surface */ + gstate->ppm = 3780; + _cairo_gstate_default_matrix (gstate); + + _cairo_path_init (&gstate->path); + + gstate->has_current_pt = 0; + + _cairo_pen_init_empty (&gstate->pen_regular); + + gstate->next = NULL; +} + +cairo_status_t +_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) +{ + cairo_status_t status; + + *gstate = *other; + if (other->dash) { + gstate->dash = malloc (other->num_dashes * sizeof (double)); + if (gstate->dash == NULL) + return CAIRO_STATUS_NO_MEMORY; + memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double)); + } + + status = _cairo_font_init_copy (&gstate->font, &other->font); + if (status) + goto CLEANUP_DASHES; + + _cairo_surface_reference (gstate->surface); + _cairo_surface_reference (gstate->solid); + _cairo_surface_reference (gstate->pattern); + _cairo_surface_reference (gstate->clip.surface); + + status = _cairo_path_init_copy (&gstate->path, &other->path); + if (status) + goto CLEANUP_FONT; + + status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular); + if (status) + goto CLEANUP_PATH; + + return status; + + CLEANUP_PATH: + _cairo_path_fini (&gstate->path); + CLEANUP_FONT: + _cairo_font_fini (&gstate->font); + CLEANUP_DASHES: + free (gstate->dash); + gstate->dash = NULL; + + return status; +} + +void +_cairo_gstate_fini (cairo_gstate_t *gstate) +{ + _cairo_font_fini (&gstate->font); + + cairo_surface_destroy (gstate->surface); + gstate->surface = NULL; + + cairo_surface_destroy (gstate->solid); + gstate->solid = NULL; + + cairo_surface_destroy (gstate->pattern); + gstate->pattern = NULL; + + cairo_surface_destroy (gstate->clip.surface); + gstate->clip.surface = NULL; + + _cairo_color_fini (&gstate->color); + + _cairo_matrix_fini (&gstate->ctm); + _cairo_matrix_fini (&gstate->ctm_inverse); + + _cairo_path_fini (&gstate->path); + + _cairo_pen_fini (&gstate->pen_regular); + + if (gstate->dash) { + free (gstate->dash); + gstate->dash = NULL; + } +} + +void +_cairo_gstate_destroy (cairo_gstate_t *gstate) +{ + _cairo_gstate_fini (gstate); + free (gstate); +} + +cairo_gstate_t* +_cairo_gstate_clone (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_gstate_t *clone; + + clone = malloc (sizeof (cairo_gstate_t)); + if (clone) { + status = _cairo_gstate_init_copy (clone, gstate); + if (status) { + free (clone); + return NULL; + } + } + + return clone; +} + +/* Push rendering off to an off-screen group. */ +/* XXX: Rethinking this API +cairo_status_t +_cairo_gstate_begin_group (cairo_gstate_t *gstate) +{ + Pixmap pix; + cairo_color_t clear; + unsigned int width, height; + + gstate->parent_surface = gstate->surface; + + width = _cairo_surface_get_width (gstate->surface); + height = _cairo_surface_get_height (gstate->surface); + + pix = XCreatePixmap (gstate->dpy, + _cairo_surface_get_drawable (gstate->surface), + width, height, + _cairo_surface_get_depth (gstate->surface)); + if (pix == 0) + return CAIRO_STATUS_NO_MEMORY; + + gstate->surface = cairo_surface_create (gstate->dpy); + if (gstate->surface == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _cairo_surface_set_drawableWH (gstate->surface, pix, width, height); + + _cairo_color_init (&clear); + _cairo_color_set_alpha (&clear, 0); + + XcFillRectangle (CAIRO_OPERATOR_SRC, + _cairo_surface_get_xc_surface (gstate->surface), + &clear.xc_color, + 0, 0, + _cairo_surface_get_width (gstate->surface), + _cairo_surface_get_height (gstate->surface)); + + return CAIRO_STATUS_SUCCESS; +} +*/ + +/* Complete the current offscreen group, composing its contents onto the parent surface. */ +/* XXX: Rethinking this API +cairo_status_t +_cairo_gstate_end_group (cairo_gstate_t *gstate) +{ + Pixmap pix; + cairo_color_t mask_color; + cairo_surface_t mask; + + if (gstate->parent_surface == NULL) + return CAIRO_STATUS_INVALID_POP_GROUP; + + _cairo_surface_init (&mask, gstate->dpy); + _cairo_color_init (&mask_color); + _cairo_color_set_alpha (&mask_color, gstate->alpha); + + _cairo_surface_set_solid_color (&mask, &mask_color); + + * XXX: This could be made much more efficient by using + _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept + track of such informaton. * + XcComposite (gstate->operator, + _cairo_surface_get_xc_surface (gstate->surface), + _cairo_surface_get_xc_surface (&mask), + _cairo_surface_get_xc_surface (gstate->parent_surface), + 0, 0, + 0, 0, + 0, 0, + _cairo_surface_get_width (gstate->surface), + _cairo_surface_get_height (gstate->surface)); + + _cairo_surface_fini (&mask); + + pix = _cairo_surface_get_drawable (gstate->surface); + XFreePixmap (gstate->dpy, pix); + + cairo_surface_destroy (gstate->surface); + gstate->surface = gstate->parent_surface; + gstate->parent_surface = NULL; + + return CAIRO_STATUS_SUCCESS; +} +*/ + +cairo_status_t +_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface) +{ + double scale; + + cairo_surface_destroy (gstate->surface); + + gstate->surface = surface; + _cairo_surface_reference (gstate->surface); + + scale = surface->ppm / gstate->ppm; + _cairo_gstate_scale (gstate, scale, scale); + gstate->ppm = surface->ppm; + + return CAIRO_STATUS_SUCCESS; +} + +/* XXX: Need to decide the memory mangement semantics of this + function. Should it reference the surface again? */ +cairo_surface_t * +_cairo_gstate_get_target_surface (cairo_gstate_t *gstate) +{ + if (gstate == NULL) + return NULL; + + return gstate->surface; +} + +cairo_status_t +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern) +{ + cairo_surface_destroy (gstate->pattern); + + gstate->pattern = pattern; + _cairo_surface_reference (gstate->pattern); + + gstate->pattern_offset.x = 0; + gstate->pattern_offset.y = 0; + cairo_matrix_transform_point (&gstate->ctm, + &gstate->pattern_offset.x, + &gstate->pattern_offset.y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator) +{ + gstate->operator = operator; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_operator_t +_cairo_gstate_get_operator (cairo_gstate_t *gstate) +{ + return gstate->operator; +} + +cairo_status_t +_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue) +{ + _cairo_color_set_rgb (&gstate->color, red, green, blue); + + cairo_surface_destroy (gstate->pattern); + gstate->pattern = NULL; + + cairo_surface_destroy (gstate->solid); + gstate->solid = cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_ARGB32, + 1, 1, + red, green, blue, + gstate->alpha); + cairo_surface_set_repeat (gstate->solid, 1); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_get_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue) +{ + _cairo_color_get_rgb (&gstate->color, red, green, blue); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance) +{ + gstate->tolerance = tolerance; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_tolerance (cairo_gstate_t *gstate) +{ + return gstate->tolerance; +} + +cairo_status_t +_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha) +{ + gstate->alpha = alpha; + + _cairo_color_set_alpha (&gstate->color, alpha); + + cairo_surface_destroy (gstate->solid); + gstate->solid = cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_ARGB32, + 1, 1, + gstate->color.red, + gstate->color.green, + gstate->color.blue, + gstate->color.alpha); + cairo_surface_set_repeat (gstate->solid, 1); + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_alpha (cairo_gstate_t *gstate) +{ + return gstate->alpha; +} + +cairo_status_t +_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule) +{ + gstate->fill_rule = fill_rule; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width) +{ + gstate->line_width = width; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_line_width (cairo_gstate_t *gstate) +{ + return gstate->line_width; +} + +cairo_status_t +_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap) +{ + gstate->line_cap = line_cap; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_line_cap_t +_cairo_gstate_get_line_cap (cairo_gstate_t *gstate) +{ + return gstate->line_cap; +} + +cairo_status_t +_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join) +{ + gstate->line_join = line_join; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_line_join_t +_cairo_gstate_get_line_join (cairo_gstate_t *gstate) +{ + return gstate->line_join; +} + +cairo_status_t +_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset) +{ + if (gstate->dash) { + free (gstate->dash); + gstate->dash = NULL; + } + + gstate->num_dashes = num_dashes; + if (gstate->num_dashes) { + gstate->dash = malloc (gstate->num_dashes * sizeof (double)); + if (gstate->dash == NULL) { + gstate->num_dashes = 0; + return CAIRO_STATUS_NO_MEMORY; + } + } + + memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); + gstate->dash_offset = offset; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit) +{ + gstate->miter_limit = limit; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate) +{ + return gstate->miter_limit; +} + +cairo_status_t +cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) +{ + cairo_matrix_t tmp; + + _cairo_matrix_set_translate (&tmp, tx, ty); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + _cairo_matrix_set_translate (&tmp, -tx, -ty); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) +{ + cairo_matrix_t tmp; + + if (sx == 0 || sy == 0) + return CAIRO_STATUS_INVALID_MATRIX; + + _cairo_matrix_set_scale (&tmp, sx, sy); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) +{ + cairo_matrix_t tmp; + + _cairo_matrix_set_rotate (&tmp, angle); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + _cairo_matrix_set_rotate (&tmp, -angle); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_concat_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + cairo_matrix_t tmp; + + cairo_matrix_copy (&tmp, matrix); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + cairo_matrix_invert (&tmp); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + cairo_status_t status; + + cairo_matrix_copy (&gstate->ctm, matrix); + + cairo_matrix_copy (&gstate->ctm_inverse, matrix); + status = cairo_matrix_invert (&gstate->ctm_inverse); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_default_matrix (cairo_gstate_t *gstate) +{ +#define CAIRO_GSTATE_DEFAULT_PPM 3780.0 + + int scale = gstate->ppm / CAIRO_GSTATE_DEFAULT_PPM + 0.5; + if (scale == 0) + scale = 1; + + cairo_matrix_set_identity (&gstate->ctm); + cairo_matrix_scale (&gstate->ctm, scale, scale); + cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm); + cairo_matrix_invert (&gstate->ctm_inverse); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_identity_matrix (cairo_gstate_t *gstate) +{ + cairo_matrix_set_identity (&gstate->ctm); + cairo_matrix_set_identity (&gstate->ctm_inverse); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_gstateransform_point (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm, x, y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_gstateransform_distance (cairo_gstate_t *gstate, double *dx, double *dy) +{ + cairo_matrix_transform_distance (&gstate->ctm, dx, dy); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy) +{ + cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_gstate_set_current_pt (cairo_gstate_t *gstate, double x, double y) +{ + gstate->current_pt.x = x; + gstate->current_pt.y = y; + + gstate->has_current_pt = 1; +} + +cairo_status_t +_cairo_gstate_new_path (cairo_gstate_t *gstate) +{ + _cairo_path_fini (&gstate->path); + gstate->has_current_pt = 0; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y) +{ + cairo_status_t status; + + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + + status = _cairo_path_move_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + gstate->last_move_pt = gstate->current_pt; + + return status; +} + +cairo_status_t +_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y) +{ + cairo_status_t status; + + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + + status = _cairo_path_line_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + return status; +} + +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 status; + + cairo_matrix_transform_point (&gstate->ctm, &x1, &y1); + cairo_matrix_transform_point (&gstate->ctm, &x2, &y2); + cairo_matrix_transform_point (&gstate->ctm, &x3, &y3); + + status = _cairo_path_curve_to (&gstate->path, + x1, y1, + x2, y2, + x3, y3); + + _cairo_gstate_set_current_pt (gstate, x3, y3); + + return status; +} + +cairo_status_t +_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy) +{ + cairo_status_t status; + double x, y; + + cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); + + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; + + status = _cairo_path_move_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + gstate->last_move_pt = gstate->current_pt; + + return status; +} + +cairo_status_t +_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy) +{ + cairo_status_t status; + double x, y; + + cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); + + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; + + status = _cairo_path_line_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + return status; +} + +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 status; + + cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1); + cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2); + cairo_matrix_transform_distance (&gstate->ctm, &dx3, &dy3); + + status = _cairo_path_curve_to (&gstate->path, + gstate->current_pt.x + dx1, gstate->current_pt.y + dy1, + gstate->current_pt.x + dx2, gstate->current_pt.y + dy2, + gstate->current_pt.x + dx3, gstate->current_pt.y + dy3); + + _cairo_gstate_set_current_pt (gstate, + gstate->current_pt.x + dx3, + gstate->current_pt.y + dy3); + + return status; +} + +cairo_status_t +_cairo_gstate_close_path (cairo_gstate_t *gstate) +{ + cairo_status_t status; + + status = _cairo_path_close_path (&gstate->path); + + _cairo_gstate_set_current_pt (gstate, + gstate->last_move_pt.x, + gstate->last_move_pt.y); + + return status; +} + +cairo_status_t +_cairo_gstate_get_current_point (cairo_gstate_t *gstate, double *x, double *y) +{ + *x = gstate->current_pt.x; + *y = gstate->current_pt.y; + + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_stroke (cairo_gstate_t *gstate) +{ + cairo_status_t status; + + cairo_traps_t traps; + + _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); + + cairo_traps_init (&traps); + + status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps); + if (status) { + cairo_traps_fini (&traps); + return status; + } + + _cairo_gstate_clip_and_composite_trapezoids (gstate, + gstate->pattern ? gstate->pattern : gstate->solid, + gstate->operator, + gstate->surface, + &traps); + + cairo_traps_fini (&traps); + + _cairo_gstate_new_path (gstate); + + return CAIRO_STATUS_SUCCESS; +} + +/* Warning: This call modifies the coordinates of traps */ +static cairo_status_t +_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, + cairo_surface_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps) +{ + if (traps->num_xtraps == 0) + return CAIRO_STATUS_SUCCESS; + + if (gstate->clip.surface) { + XFixed xoff, yoff; + XTrapezoid *t; + int i; + + cairo_surface_t *intermediate, *white; + + white = cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, + 1, 1, + 1.0, 1.0, 1.0, 1.0); + cairo_surface_set_repeat (white, 1); + + intermediate = cairo_surface_create_similar_solid (gstate->clip.surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + 0.0, 0.0, 0.0, 0.0); + + /* Ugh. The Xc/ (Render) interface doesn't allow an offset for + the trapezoids. Need to manually shift all the coordinates + to align with the offset origin of the clip surface. */ + xoff = XDoubleToFixed (gstate->clip.x); + yoff = XDoubleToFixed (gstate->clip.y); + for (i=0, t=traps->xtraps; i < traps->num_xtraps; i++, t++) { + t->top -= yoff; + t->bottom -= yoff; + t->left.p1.x -= xoff; + t->left.p1.y -= yoff; + t->left.p2.x -= xoff; + t->left.p2.y -= yoff; + t->right.p1.x -= xoff; + t->right.p1.y -= yoff; + t->right.p2.x -= xoff; + t->right.p2.y -= yoff; + } + + XcCompositeTrapezoids (CAIRO_OPERATOR_ADD, + white->xc_surface, + intermediate->xc_surface, + 0, 0, + traps->xtraps, + traps->num_xtraps); + XcComposite (CAIRO_OPERATOR_IN, + gstate->clip.surface->xc_surface, + NULL, + intermediate->xc_surface, + 0, 0, 0, 0, 0, 0, + gstate->clip.width, gstate->clip.height); + XcComposite (operator, + src->xc_surface, + intermediate->xc_surface, + dst->xc_surface, + 0, 0, + 0, 0, + gstate->clip.x, + gstate->clip.y, + gstate->clip.width, + gstate->clip.height); + cairo_surface_destroy (intermediate); + cairo_surface_destroy (white); + + } else { + double xoff, yoff; + + if (traps->xtraps[0].left.p1.y < traps->xtraps[0].left.p2.y) { + xoff = traps->xtraps[0].left.p1.x; + yoff = traps->xtraps[0].left.p1.y; + } else { + xoff = traps->xtraps[0].left.p2.x; + yoff = traps->xtraps[0].left.p2.y; + } + + XcCompositeTrapezoids (gstate->operator, + src->xc_surface, + dst->xc_surface, + XFixedToDouble (xoff) - gstate->pattern_offset.x, + XFixedToDouble (yoff) - gstate->pattern_offset.y, + traps->xtraps, + traps->num_xtraps); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_fill (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_traps_t traps; + + cairo_traps_init (&traps); + + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) { + cairo_traps_fini (&traps); + return status; + } + + _cairo_gstate_clip_and_composite_trapezoids (gstate, + gstate->pattern ? gstate->pattern : gstate->solid, + gstate->operator, + gstate->surface, + &traps); + cairo_traps_fini (&traps); + + _cairo_gstate_new_path (gstate); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_surface_t *alpha_one; + cairo_traps_t traps; + + if (gstate->clip.surface == NULL) { + double x1, y1, x2, y2; + _cairo_path_bounds (&gstate->path, + &x1, &y1, &x2, &y2); + gstate->clip.x = floor (x1); + gstate->clip.y = floor (y1); + gstate->clip.width = ceil (x2 - gstate->clip.x); + gstate->clip.height = ceil (y2 - gstate->clip.y); + gstate->clip.surface = cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + 1.0, 1.0, 1.0, 1.0); + } + + alpha_one = cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, + 1, 1, + 0.0, 0.0, 0.0, 1.0); + cairo_surface_set_repeat (alpha_one, 1); + + cairo_traps_init (&traps); + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) { + cairo_traps_fini (&traps); + return status; + } + + _cairo_gstate_clip_and_composite_trapezoids (gstate, + alpha_one, + CAIRO_OPERATOR_IN, + gstate->clip.surface, + &traps); + + cairo_traps_fini (&traps); + + cairo_surface_destroy (alpha_one); + + return status; +} + +cairo_status_t +_cairo_gstate_select_font (cairo_gstate_t *gstate, const char *key) +{ + return _cairo_font_select (&gstate->font, key); +} + +cairo_status_t +_cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale) +{ + return _cairo_font_scale (&gstate->font, scale); +} + +cairo_status_t +cairo_gstateransform_font (cairo_gstate_t *gstate, + double a, double b, + double c, double d) +{ + return cairo_font_transform (&gstate->font, + a, b, c, 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) +{ + XftFont *xft_font; + XGlyphInfo extents; + + _cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font); + + /* XXX: Need to abandon Xft and use Xc instead */ + /* (until I do, this call will croak on IcImage cairo_surface_ts */ + XftTextExtentsUtf8 (gstate->surface->dpy, + xft_font, + utf8, + strlen ((char *) utf8), + &extents); + + /* XXX: What are the semantics of XftTextExtents? Specifically, + what does it do with x/y? I think we actually need to use the + gstate's current point in here somewhere. */ + *x = extents.x; + *y = extents.y; + *width = extents.width; + *height = extents.height; + *dx = extents.xOff; + *dy = extents.yOff; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8) +{ + XftFont *xft_font; + + if (gstate->has_current_pt == 0) + return CAIRO_STATUS_NO_CURRENT_POINT; + + _cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font); + + /* XXX: Need to abandon Xft and use Xc instead */ + /* (until I do, this call will croak on IcImage cairo_surface_ts */ + /* (also, this means text clipping isn't working. Basically text is broken.) */ + XftTextRenderUtf8 (gstate->surface->dpy, + gstate->operator, + _cairo_surface_get_picture (gstate->solid), + xft_font, + _cairo_surface_get_picture (gstate->surface), + 0, 0, + gstate->current_pt.x, + gstate->current_pt.y, + utf8, + strlen ((char *) utf8)); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_show_surface (cairo_gstate_t *gstate, + cairo_surface_t *surface, + int width, + int height) +{ + cairo_surface_t *mask; + cairo_matrix_t user_to_image, image_to_user; + cairo_matrix_t image_to_device, device_to_image; + double device_x, device_y; + double device_width, device_height; + + mask = cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + 1, 1, + 1.0, 1.0, 1.0, + gstate->alpha); + if (mask == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cairo_surface_set_repeat (mask, 1); + + cairo_surface_get_matrix (surface, &user_to_image); + cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); + cairo_surface_set_matrix (surface, &device_to_image); + + image_to_user = user_to_image; + cairo_matrix_invert (&image_to_user); + cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm); + + device_x = 0; + device_y = 0; + device_width = width; + device_height = height; + cairo_matrix_transform_bounding_box (&image_to_device, + &device_x, &device_y, + &device_width, &device_height); + + /* XXX: The rendered size is sometimes 1 or 2 pixels short from + what I expect. Need to fix this. */ + XcComposite (gstate->operator, + surface->xc_surface, + mask->xc_surface, + gstate->surface->xc_surface, + device_x, device_y, + 0, 0, + device_x, device_y, + device_width, + device_height); + + cairo_surface_destroy (mask); + + /* restore the matrix originally in the surface */ + cairo_surface_set_matrix (surface, &user_to_image); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c new file mode 100644 index 000000000..fed5c85b4 --- /dev/null +++ b/src/cairo-matrix.c @@ -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; +} diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c new file mode 100644 index 000000000..6536cf65e --- /dev/null +++ b/src/cairo-path-bounds.c @@ -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; +} diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c new file mode 100644 index 000000000..4aa845949 --- /dev/null +++ b/src/cairo-path-fill.c @@ -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; +} + diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c new file mode 100644 index 000000000..8b1be1fad --- /dev/null +++ b/src/cairo-path-stroke.c @@ -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; +} diff --git a/src/cairo-path.c b/src/cairo-path.c new file mode 100644 index 000000000..99cfea20f --- /dev/null +++ b/src/cairo-path.c @@ -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, ¤t, &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, ¤t, &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, ¤t, &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); +} + + diff --git a/src/cairo-pen.c b/src/cairo-pen.c new file mode 100644 index 000000000..358a1e05a --- /dev/null +++ b/src/cairo-pen.c @@ -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; +} diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c new file mode 100644 index 000000000..70817bd93 --- /dev/null +++ b/src/cairo-polygon.c @@ -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; +} diff --git a/src/cairo-spline.c b/src/cairo-spline.c new file mode 100644 index 000000000..a7e76b294 --- /dev/null +++ b/src/cairo-spline.c @@ -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; +} + diff --git a/src/cairo-surface.c b/src/cairo-surface.c new file mode 100644 index 000000000..1bea568bc --- /dev/null +++ b/src/cairo-surface.c @@ -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); +} + diff --git a/src/xrtraps.c b/src/cairo-traps.c index 439e45d3f..c0afa3d31 100644 --- a/src/xrtraps.c +++ b/src/cairo-traps.c @@ -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; } diff --git a/src/cairo.c b/src/cairo.c new file mode 100644 index 000000000..281234484 --- /dev/null +++ b/src/cairo.c @@ -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; +} diff --git a/src/cairo.h b/src/cairo.h new file mode 100644 index 000000000..0b381ebce --- /dev/null +++ b/src/cairo.h @@ -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 + diff --git a/src/cairo_color.c b/src/cairo_color.c new file mode 100644 index 000000000..dab09ad27 --- /dev/null +++ b/src/cairo_color.c @@ -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); +} diff --git a/src/cairo_font.c b/src/cairo_font.c new file mode 100644 index 000000000..001ea0aca --- /dev/null +++ b/src/cairo_font.c @@ -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; +} diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c new file mode 100644 index 000000000..f83833aea --- /dev/null +++ b/src/cairo_gstate.c @@ -0,0 +1,1123 @@ +/* + * 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 void +_cairo_gstate_set_current_pt (cairo_gstate_t *gstate, double x, double y); + +static cairo_status_t +_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, + cairo_surface_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps); + +cairo_gstate_t * +_cairo_gstate_create () +{ + cairo_gstate_t *gstate; + + gstate = malloc (sizeof (cairo_gstate_t)); + + if (gstate) + _cairo_gstate_init (gstate); + + return gstate; +} + +void +_cairo_gstate_init (cairo_gstate_t *gstate) +{ + gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT; + + gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; + + gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT; + gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT; + gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT; + gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT; + + gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; + + gstate->dash = NULL; + gstate->num_dashes = 0; + gstate->dash_offset = 0.0; + + _cairo_font_init (&gstate->font); + + gstate->surface = NULL; + gstate->solid = NULL; + gstate->pattern = NULL; + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; + + gstate->clip.surface = NULL; + + gstate->alpha = 1.0; + _cairo_color_init (&gstate->color); + + /* 3780 PPM (~96DPI) is a good enough assumption until we get a surface */ + gstate->ppm = 3780; + _cairo_gstate_default_matrix (gstate); + + _cairo_path_init (&gstate->path); + + gstate->has_current_pt = 0; + + _cairo_pen_init_empty (&gstate->pen_regular); + + gstate->next = NULL; +} + +cairo_status_t +_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) +{ + cairo_status_t status; + + *gstate = *other; + if (other->dash) { + gstate->dash = malloc (other->num_dashes * sizeof (double)); + if (gstate->dash == NULL) + return CAIRO_STATUS_NO_MEMORY; + memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double)); + } + + status = _cairo_font_init_copy (&gstate->font, &other->font); + if (status) + goto CLEANUP_DASHES; + + _cairo_surface_reference (gstate->surface); + _cairo_surface_reference (gstate->solid); + _cairo_surface_reference (gstate->pattern); + _cairo_surface_reference (gstate->clip.surface); + + status = _cairo_path_init_copy (&gstate->path, &other->path); + if (status) + goto CLEANUP_FONT; + + status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular); + if (status) + goto CLEANUP_PATH; + + return status; + + CLEANUP_PATH: + _cairo_path_fini (&gstate->path); + CLEANUP_FONT: + _cairo_font_fini (&gstate->font); + CLEANUP_DASHES: + free (gstate->dash); + gstate->dash = NULL; + + return status; +} + +void +_cairo_gstate_fini (cairo_gstate_t *gstate) +{ + _cairo_font_fini (&gstate->font); + + cairo_surface_destroy (gstate->surface); + gstate->surface = NULL; + + cairo_surface_destroy (gstate->solid); + gstate->solid = NULL; + + cairo_surface_destroy (gstate->pattern); + gstate->pattern = NULL; + + cairo_surface_destroy (gstate->clip.surface); + gstate->clip.surface = NULL; + + _cairo_color_fini (&gstate->color); + + _cairo_matrix_fini (&gstate->ctm); + _cairo_matrix_fini (&gstate->ctm_inverse); + + _cairo_path_fini (&gstate->path); + + _cairo_pen_fini (&gstate->pen_regular); + + if (gstate->dash) { + free (gstate->dash); + gstate->dash = NULL; + } +} + +void +_cairo_gstate_destroy (cairo_gstate_t *gstate) +{ + _cairo_gstate_fini (gstate); + free (gstate); +} + +cairo_gstate_t* +_cairo_gstate_clone (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_gstate_t *clone; + + clone = malloc (sizeof (cairo_gstate_t)); + if (clone) { + status = _cairo_gstate_init_copy (clone, gstate); + if (status) { + free (clone); + return NULL; + } + } + + return clone; +} + +/* Push rendering off to an off-screen group. */ +/* XXX: Rethinking this API +cairo_status_t +_cairo_gstate_begin_group (cairo_gstate_t *gstate) +{ + Pixmap pix; + cairo_color_t clear; + unsigned int width, height; + + gstate->parent_surface = gstate->surface; + + width = _cairo_surface_get_width (gstate->surface); + height = _cairo_surface_get_height (gstate->surface); + + pix = XCreatePixmap (gstate->dpy, + _cairo_surface_get_drawable (gstate->surface), + width, height, + _cairo_surface_get_depth (gstate->surface)); + if (pix == 0) + return CAIRO_STATUS_NO_MEMORY; + + gstate->surface = cairo_surface_create (gstate->dpy); + if (gstate->surface == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _cairo_surface_set_drawableWH (gstate->surface, pix, width, height); + + _cairo_color_init (&clear); + _cairo_color_set_alpha (&clear, 0); + + XcFillRectangle (CAIRO_OPERATOR_SRC, + _cairo_surface_get_xc_surface (gstate->surface), + &clear.xc_color, + 0, 0, + _cairo_surface_get_width (gstate->surface), + _cairo_surface_get_height (gstate->surface)); + + return CAIRO_STATUS_SUCCESS; +} +*/ + +/* Complete the current offscreen group, composing its contents onto the parent surface. */ +/* XXX: Rethinking this API +cairo_status_t +_cairo_gstate_end_group (cairo_gstate_t *gstate) +{ + Pixmap pix; + cairo_color_t mask_color; + cairo_surface_t mask; + + if (gstate->parent_surface == NULL) + return CAIRO_STATUS_INVALID_POP_GROUP; + + _cairo_surface_init (&mask, gstate->dpy); + _cairo_color_init (&mask_color); + _cairo_color_set_alpha (&mask_color, gstate->alpha); + + _cairo_surface_set_solid_color (&mask, &mask_color); + + * XXX: This could be made much more efficient by using + _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept + track of such informaton. * + XcComposite (gstate->operator, + _cairo_surface_get_xc_surface (gstate->surface), + _cairo_surface_get_xc_surface (&mask), + _cairo_surface_get_xc_surface (gstate->parent_surface), + 0, 0, + 0, 0, + 0, 0, + _cairo_surface_get_width (gstate->surface), + _cairo_surface_get_height (gstate->surface)); + + _cairo_surface_fini (&mask); + + pix = _cairo_surface_get_drawable (gstate->surface); + XFreePixmap (gstate->dpy, pix); + + cairo_surface_destroy (gstate->surface); + gstate->surface = gstate->parent_surface; + gstate->parent_surface = NULL; + + return CAIRO_STATUS_SUCCESS; +} +*/ + +cairo_status_t +_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface) +{ + double scale; + + cairo_surface_destroy (gstate->surface); + + gstate->surface = surface; + _cairo_surface_reference (gstate->surface); + + scale = surface->ppm / gstate->ppm; + _cairo_gstate_scale (gstate, scale, scale); + gstate->ppm = surface->ppm; + + return CAIRO_STATUS_SUCCESS; +} + +/* XXX: Need to decide the memory mangement semantics of this + function. Should it reference the surface again? */ +cairo_surface_t * +_cairo_gstate_get_target_surface (cairo_gstate_t *gstate) +{ + if (gstate == NULL) + return NULL; + + return gstate->surface; +} + +cairo_status_t +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern) +{ + cairo_surface_destroy (gstate->pattern); + + gstate->pattern = pattern; + _cairo_surface_reference (gstate->pattern); + + gstate->pattern_offset.x = 0; + gstate->pattern_offset.y = 0; + cairo_matrix_transform_point (&gstate->ctm, + &gstate->pattern_offset.x, + &gstate->pattern_offset.y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator) +{ + gstate->operator = operator; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_operator_t +_cairo_gstate_get_operator (cairo_gstate_t *gstate) +{ + return gstate->operator; +} + +cairo_status_t +_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue) +{ + _cairo_color_set_rgb (&gstate->color, red, green, blue); + + cairo_surface_destroy (gstate->pattern); + gstate->pattern = NULL; + + cairo_surface_destroy (gstate->solid); + gstate->solid = cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_ARGB32, + 1, 1, + red, green, blue, + gstate->alpha); + cairo_surface_set_repeat (gstate->solid, 1); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_get_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue) +{ + _cairo_color_get_rgb (&gstate->color, red, green, blue); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance) +{ + gstate->tolerance = tolerance; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_tolerance (cairo_gstate_t *gstate) +{ + return gstate->tolerance; +} + +cairo_status_t +_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha) +{ + gstate->alpha = alpha; + + _cairo_color_set_alpha (&gstate->color, alpha); + + cairo_surface_destroy (gstate->solid); + gstate->solid = cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_ARGB32, + 1, 1, + gstate->color.red, + gstate->color.green, + gstate->color.blue, + gstate->color.alpha); + cairo_surface_set_repeat (gstate->solid, 1); + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_alpha (cairo_gstate_t *gstate) +{ + return gstate->alpha; +} + +cairo_status_t +_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule) +{ + gstate->fill_rule = fill_rule; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width) +{ + gstate->line_width = width; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_line_width (cairo_gstate_t *gstate) +{ + return gstate->line_width; +} + +cairo_status_t +_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap) +{ + gstate->line_cap = line_cap; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_line_cap_t +_cairo_gstate_get_line_cap (cairo_gstate_t *gstate) +{ + return gstate->line_cap; +} + +cairo_status_t +_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join) +{ + gstate->line_join = line_join; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_line_join_t +_cairo_gstate_get_line_join (cairo_gstate_t *gstate) +{ + return gstate->line_join; +} + +cairo_status_t +_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset) +{ + if (gstate->dash) { + free (gstate->dash); + gstate->dash = NULL; + } + + gstate->num_dashes = num_dashes; + if (gstate->num_dashes) { + gstate->dash = malloc (gstate->num_dashes * sizeof (double)); + if (gstate->dash == NULL) { + gstate->num_dashes = 0; + return CAIRO_STATUS_NO_MEMORY; + } + } + + memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); + gstate->dash_offset = offset; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit) +{ + gstate->miter_limit = limit; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate) +{ + return gstate->miter_limit; +} + +cairo_status_t +cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) +{ + cairo_matrix_t tmp; + + _cairo_matrix_set_translate (&tmp, tx, ty); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + _cairo_matrix_set_translate (&tmp, -tx, -ty); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) +{ + cairo_matrix_t tmp; + + if (sx == 0 || sy == 0) + return CAIRO_STATUS_INVALID_MATRIX; + + _cairo_matrix_set_scale (&tmp, sx, sy); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) +{ + cairo_matrix_t tmp; + + _cairo_matrix_set_rotate (&tmp, angle); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + _cairo_matrix_set_rotate (&tmp, -angle); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_concat_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + cairo_matrix_t tmp; + + cairo_matrix_copy (&tmp, matrix); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + + cairo_matrix_invert (&tmp); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + cairo_status_t status; + + cairo_matrix_copy (&gstate->ctm, matrix); + + cairo_matrix_copy (&gstate->ctm_inverse, matrix); + status = cairo_matrix_invert (&gstate->ctm_inverse); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_default_matrix (cairo_gstate_t *gstate) +{ +#define CAIRO_GSTATE_DEFAULT_PPM 3780.0 + + int scale = gstate->ppm / CAIRO_GSTATE_DEFAULT_PPM + 0.5; + if (scale == 0) + scale = 1; + + cairo_matrix_set_identity (&gstate->ctm); + cairo_matrix_scale (&gstate->ctm, scale, scale); + cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm); + cairo_matrix_invert (&gstate->ctm_inverse); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_identity_matrix (cairo_gstate_t *gstate) +{ + cairo_matrix_set_identity (&gstate->ctm); + cairo_matrix_set_identity (&gstate->ctm_inverse); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_gstateransform_point (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm, x, y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_gstateransform_distance (cairo_gstate_t *gstate, double *dx, double *dy) +{ + cairo_matrix_transform_distance (&gstate->ctm, dx, dy); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy) +{ + cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_gstate_set_current_pt (cairo_gstate_t *gstate, double x, double y) +{ + gstate->current_pt.x = x; + gstate->current_pt.y = y; + + gstate->has_current_pt = 1; +} + +cairo_status_t +_cairo_gstate_new_path (cairo_gstate_t *gstate) +{ + _cairo_path_fini (&gstate->path); + gstate->has_current_pt = 0; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y) +{ + cairo_status_t status; + + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + + status = _cairo_path_move_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + gstate->last_move_pt = gstate->current_pt; + + return status; +} + +cairo_status_t +_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y) +{ + cairo_status_t status; + + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + + status = _cairo_path_line_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + return status; +} + +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 status; + + cairo_matrix_transform_point (&gstate->ctm, &x1, &y1); + cairo_matrix_transform_point (&gstate->ctm, &x2, &y2); + cairo_matrix_transform_point (&gstate->ctm, &x3, &y3); + + status = _cairo_path_curve_to (&gstate->path, + x1, y1, + x2, y2, + x3, y3); + + _cairo_gstate_set_current_pt (gstate, x3, y3); + + return status; +} + +cairo_status_t +_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy) +{ + cairo_status_t status; + double x, y; + + cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); + + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; + + status = _cairo_path_move_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + gstate->last_move_pt = gstate->current_pt; + + return status; +} + +cairo_status_t +_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy) +{ + cairo_status_t status; + double x, y; + + cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); + + x = gstate->current_pt.x + dx; + y = gstate->current_pt.y + dy; + + status = _cairo_path_line_to (&gstate->path, x, y); + + _cairo_gstate_set_current_pt (gstate, x, y); + + return status; +} + +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 status; + + cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1); + cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2); + cairo_matrix_transform_distance (&gstate->ctm, &dx3, &dy3); + + status = _cairo_path_curve_to (&gstate->path, + gstate->current_pt.x + dx1, gstate->current_pt.y + dy1, + gstate->current_pt.x + dx2, gstate->current_pt.y + dy2, + gstate->current_pt.x + dx3, gstate->current_pt.y + dy3); + + _cairo_gstate_set_current_pt (gstate, + gstate->current_pt.x + dx3, + gstate->current_pt.y + dy3); + + return status; +} + +cairo_status_t +_cairo_gstate_close_path (cairo_gstate_t *gstate) +{ + cairo_status_t status; + + status = _cairo_path_close_path (&gstate->path); + + _cairo_gstate_set_current_pt (gstate, + gstate->last_move_pt.x, + gstate->last_move_pt.y); + + return status; +} + +cairo_status_t +_cairo_gstate_get_current_point (cairo_gstate_t *gstate, double *x, double *y) +{ + *x = gstate->current_pt.x; + *y = gstate->current_pt.y; + + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_stroke (cairo_gstate_t *gstate) +{ + cairo_status_t status; + + cairo_traps_t traps; + + _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); + + cairo_traps_init (&traps); + + status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps); + if (status) { + cairo_traps_fini (&traps); + return status; + } + + _cairo_gstate_clip_and_composite_trapezoids (gstate, + gstate->pattern ? gstate->pattern : gstate->solid, + gstate->operator, + gstate->surface, + &traps); + + cairo_traps_fini (&traps); + + _cairo_gstate_new_path (gstate); + + return CAIRO_STATUS_SUCCESS; +} + +/* Warning: This call modifies the coordinates of traps */ +static cairo_status_t +_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, + cairo_surface_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps) +{ + if (traps->num_xtraps == 0) + return CAIRO_STATUS_SUCCESS; + + if (gstate->clip.surface) { + XFixed xoff, yoff; + XTrapezoid *t; + int i; + + cairo_surface_t *intermediate, *white; + + white = cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, + 1, 1, + 1.0, 1.0, 1.0, 1.0); + cairo_surface_set_repeat (white, 1); + + intermediate = cairo_surface_create_similar_solid (gstate->clip.surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + 0.0, 0.0, 0.0, 0.0); + + /* Ugh. The Xc/ (Render) interface doesn't allow an offset for + the trapezoids. Need to manually shift all the coordinates + to align with the offset origin of the clip surface. */ + xoff = XDoubleToFixed (gstate->clip.x); + yoff = XDoubleToFixed (gstate->clip.y); + for (i=0, t=traps->xtraps; i < traps->num_xtraps; i++, t++) { + t->top -= yoff; + t->bottom -= yoff; + t->left.p1.x -= xoff; + t->left.p1.y -= yoff; + t->left.p2.x -= xoff; + t->left.p2.y -= yoff; + t->right.p1.x -= xoff; + t->right.p1.y -= yoff; + t->right.p2.x -= xoff; + t->right.p2.y -= yoff; + } + + XcCompositeTrapezoids (CAIRO_OPERATOR_ADD, + white->xc_surface, + intermediate->xc_surface, + 0, 0, + traps->xtraps, + traps->num_xtraps); + XcComposite (CAIRO_OPERATOR_IN, + gstate->clip.surface->xc_surface, + NULL, + intermediate->xc_surface, + 0, 0, 0, 0, 0, 0, + gstate->clip.width, gstate->clip.height); + XcComposite (operator, + src->xc_surface, + intermediate->xc_surface, + dst->xc_surface, + 0, 0, + 0, 0, + gstate->clip.x, + gstate->clip.y, + gstate->clip.width, + gstate->clip.height); + cairo_surface_destroy (intermediate); + cairo_surface_destroy (white); + + } else { + double xoff, yoff; + + if (traps->xtraps[0].left.p1.y < traps->xtraps[0].left.p2.y) { + xoff = traps->xtraps[0].left.p1.x; + yoff = traps->xtraps[0].left.p1.y; + } else { + xoff = traps->xtraps[0].left.p2.x; + yoff = traps->xtraps[0].left.p2.y; + } + + XcCompositeTrapezoids (gstate->operator, + src->xc_surface, + dst->xc_surface, + XFixedToDouble (xoff) - gstate->pattern_offset.x, + XFixedToDouble (yoff) - gstate->pattern_offset.y, + traps->xtraps, + traps->num_xtraps); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_fill (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_traps_t traps; + + cairo_traps_init (&traps); + + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) { + cairo_traps_fini (&traps); + return status; + } + + _cairo_gstate_clip_and_composite_trapezoids (gstate, + gstate->pattern ? gstate->pattern : gstate->solid, + gstate->operator, + gstate->surface, + &traps); + cairo_traps_fini (&traps); + + _cairo_gstate_new_path (gstate); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_surface_t *alpha_one; + cairo_traps_t traps; + + if (gstate->clip.surface == NULL) { + double x1, y1, x2, y2; + _cairo_path_bounds (&gstate->path, + &x1, &y1, &x2, &y2); + gstate->clip.x = floor (x1); + gstate->clip.y = floor (y1); + gstate->clip.width = ceil (x2 - gstate->clip.x); + gstate->clip.height = ceil (y2 - gstate->clip.y); + gstate->clip.surface = cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + 1.0, 1.0, 1.0, 1.0); + } + + alpha_one = cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, + 1, 1, + 0.0, 0.0, 0.0, 1.0); + cairo_surface_set_repeat (alpha_one, 1); + + cairo_traps_init (&traps); + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) { + cairo_traps_fini (&traps); + return status; + } + + _cairo_gstate_clip_and_composite_trapezoids (gstate, + alpha_one, + CAIRO_OPERATOR_IN, + gstate->clip.surface, + &traps); + + cairo_traps_fini (&traps); + + cairo_surface_destroy (alpha_one); + + return status; +} + +cairo_status_t +_cairo_gstate_select_font (cairo_gstate_t *gstate, const char *key) +{ + return _cairo_font_select (&gstate->font, key); +} + +cairo_status_t +_cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale) +{ + return _cairo_font_scale (&gstate->font, scale); +} + +cairo_status_t +cairo_gstateransform_font (cairo_gstate_t *gstate, + double a, double b, + double c, double d) +{ + return cairo_font_transform (&gstate->font, + a, b, c, 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) +{ + XftFont *xft_font; + XGlyphInfo extents; + + _cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font); + + /* XXX: Need to abandon Xft and use Xc instead */ + /* (until I do, this call will croak on IcImage cairo_surface_ts */ + XftTextExtentsUtf8 (gstate->surface->dpy, + xft_font, + utf8, + strlen ((char *) utf8), + &extents); + + /* XXX: What are the semantics of XftTextExtents? Specifically, + what does it do with x/y? I think we actually need to use the + gstate's current point in here somewhere. */ + *x = extents.x; + *y = extents.y; + *width = extents.width; + *height = extents.height; + *dx = extents.xOff; + *dy = extents.yOff; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8) +{ + XftFont *xft_font; + + if (gstate->has_current_pt == 0) + return CAIRO_STATUS_NO_CURRENT_POINT; + + _cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font); + + /* XXX: Need to abandon Xft and use Xc instead */ + /* (until I do, this call will croak on IcImage cairo_surface_ts */ + /* (also, this means text clipping isn't working. Basically text is broken.) */ + XftTextRenderUtf8 (gstate->surface->dpy, + gstate->operator, + _cairo_surface_get_picture (gstate->solid), + xft_font, + _cairo_surface_get_picture (gstate->surface), + 0, 0, + gstate->current_pt.x, + gstate->current_pt.y, + utf8, + strlen ((char *) utf8)); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_show_surface (cairo_gstate_t *gstate, + cairo_surface_t *surface, + int width, + int height) +{ + cairo_surface_t *mask; + cairo_matrix_t user_to_image, image_to_user; + cairo_matrix_t image_to_device, device_to_image; + double device_x, device_y; + double device_width, device_height; + + mask = cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + 1, 1, + 1.0, 1.0, 1.0, + gstate->alpha); + if (mask == NULL) + return CAIRO_STATUS_NO_MEMORY; + + cairo_surface_set_repeat (mask, 1); + + cairo_surface_get_matrix (surface, &user_to_image); + cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); + cairo_surface_set_matrix (surface, &device_to_image); + + image_to_user = user_to_image; + cairo_matrix_invert (&image_to_user); + cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm); + + device_x = 0; + device_y = 0; + device_width = width; + device_height = height; + cairo_matrix_transform_bounding_box (&image_to_device, + &device_x, &device_y, + &device_width, &device_height); + + /* XXX: The rendered size is sometimes 1 or 2 pixels short from + what I expect. Need to fix this. */ + XcComposite (gstate->operator, + surface->xc_surface, + mask->xc_surface, + gstate->surface->xc_surface, + device_x, device_y, + 0, 0, + device_x, device_y, + device_width, + device_height); + + cairo_surface_destroy (mask); + + /* restore the matrix originally in the surface */ + cairo_surface_set_matrix (surface, &user_to_image); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c new file mode 100644 index 000000000..fed5c85b4 --- /dev/null +++ b/src/cairo_matrix.c @@ -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; +} diff --git a/src/cairo_misc.c b/src/cairo_misc.c new file mode 100644 index 000000000..b3f91db59 --- /dev/null +++ b/src/cairo_misc.c @@ -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; +} + diff --git a/src/cairo_path.c b/src/cairo_path.c new file mode 100644 index 000000000..99cfea20f --- /dev/null +++ b/src/cairo_path.c @@ -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, ¤t, &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, ¤t, &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, ¤t, &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); +} + + diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c new file mode 100644 index 000000000..6536cf65e --- /dev/null +++ b/src/cairo_path_bounds.c @@ -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; +} diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c new file mode 100644 index 000000000..4aa845949 --- /dev/null +++ b/src/cairo_path_fill.c @@ -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; +} + diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c new file mode 100644 index 000000000..8b1be1fad --- /dev/null +++ b/src/cairo_path_stroke.c @@ -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; +} diff --git a/src/cairo_pen.c b/src/cairo_pen.c new file mode 100644 index 000000000..358a1e05a --- /dev/null +++ b/src/cairo_pen.c @@ -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; +} diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c new file mode 100644 index 000000000..70817bd93 --- /dev/null +++ b/src/cairo_polygon.c @@ -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; +} diff --git a/src/cairo_spline.c b/src/cairo_spline.c new file mode 100644 index 000000000..a7e76b294 --- /dev/null +++ b/src/cairo_spline.c @@ -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; +} + diff --git a/src/cairo_surface.c b/src/cairo_surface.c new file mode 100644 index 000000000..1bea568bc --- /dev/null +++ b/src/cairo_surface.c @@ -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); +} + diff --git a/src/cairo_traps.c b/src/cairo_traps.c new file mode 100644 index 000000000..c0afa3d31 --- /dev/null +++ b/src/cairo_traps.c @@ -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; +} diff --git a/src/cairoint.h b/src/cairoint.h new file mode 100644 index 000000000..84d5e4303 --- /dev/null +++ b/src/cairoint.h @@ -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 diff --git a/src/xr.c b/src/xr.c deleted file mode 100644 index e6a3dd648..000000000 --- a/src/xr.c +++ /dev/null @@ -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; -} diff --git a/src/xrcolor.c b/src/xrcolor.c deleted file mode 100644 index 005c7aa5a..000000000 --- a/src/xrcolor.c +++ /dev/null @@ -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); -} diff --git a/src/xrfiller.c b/src/xrfiller.c deleted file mode 100644 index 79015e19c..000000000 --- a/src/xrfiller.c +++ /dev/null @@ -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); -} - diff --git a/src/xrfont.c b/src/xrfont.c deleted file mode 100644 index 79dd79e01..000000000 --- a/src/xrfont.c +++ /dev/null @@ -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; -} diff --git a/src/xrgstate.c b/src/xrgstate.c deleted file mode 100644 index bb50dee26..000000000 --- a/src/xrgstate.c +++ /dev/null @@ -1,1120 +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 void -_XrGStateSetCurrentPt(XrGState *gstate, double x, double y); - -static XrStatus -_XrGStateClipAndCompositeTrapezoids(XrGState *gstate, - XrSurface *src, - XrOperator operator, - XrSurface *dst, - XrTraps *traps); - -XrGState * -_XrGStateCreate() -{ - XrGState *gstate; - - gstate = malloc(sizeof(XrGState)); - - if (gstate) - _XrGStateInit(gstate); - - return gstate; -} - -void -_XrGStateInit(XrGState *gstate) -{ - gstate->operator = XR_GSTATE_OPERATOR_DEFAULT; - - gstate->tolerance = XR_GSTATE_TOLERANCE_DEFAULT; - - gstate->line_width = XR_GSTATE_LINE_WIDTH_DEFAULT; - gstate->line_cap = XR_GSTATE_LINE_CAP_DEFAULT; - gstate->line_join = XR_GSTATE_LINE_JOIN_DEFAULT; - gstate->miter_limit = XR_GSTATE_MITER_LIMIT_DEFAULT; - - gstate->fill_rule = XR_GSTATE_FILL_RULE_DEFAULT; - - gstate->dash = NULL; - gstate->num_dashes = 0; - gstate->dash_offset = 0.0; - - _XrFontInit(&gstate->font); - - gstate->surface = NULL; - gstate->solid = NULL; - gstate->pattern = NULL; - gstate->pattern_offset.x = 0.0; - gstate->pattern_offset.y = 0.0; - - gstate->clip.surface = NULL; - - gstate->alpha = 1.0; - _XrColorInit(&gstate->color); - - /* 3780 PPM (~96DPI) is a good enough assumption until we get a surface */ - gstate->ppm = 3780; - _XrGStateDefaultMatrix (gstate); - - _XrPathInit(&gstate->path); - - gstate->has_current_pt = 0; - - _XrPenInitEmpty(&gstate->pen_regular); - - gstate->next = NULL; -} - -XrStatus -_XrGStateInitCopy(XrGState *gstate, XrGState *other) -{ - XrStatus status; - - *gstate = *other; - if (other->dash) { - gstate->dash = malloc (other->num_dashes * sizeof (double)); - if (gstate->dash == NULL) - return XrStatusNoMemory; - memcpy(gstate->dash, other->dash, other->num_dashes * sizeof (double)); - } - - status = _XrFontInitCopy(&gstate->font, &other->font); - if (status) - goto CLEANUP_DASHES; - - _XrSurfaceReference(gstate->surface); - _XrSurfaceReference(gstate->solid); - _XrSurfaceReference(gstate->pattern); - _XrSurfaceReference(gstate->clip.surface); - - status = _XrPathInitCopy(&gstate->path, &other->path); - if (status) - goto CLEANUP_FONT; - - status = _XrPenInitCopy(&gstate->pen_regular, &other->pen_regular); - if (status) - goto CLEANUP_PATH; - - return status; - - CLEANUP_PATH: - _XrPathDeinit(&gstate->path); - CLEANUP_FONT: - _XrFontDeinit(&gstate->font); - CLEANUP_DASHES: - free (gstate->dash); - gstate->dash = NULL; - - return status; -} - -void -_XrGStateDeinit(XrGState *gstate) -{ - _XrFontDeinit(&gstate->font); - - XrSurfaceDestroy(gstate->surface); - gstate->surface = NULL; - - XrSurfaceDestroy(gstate->solid); - gstate->solid = NULL; - - XrSurfaceDestroy(gstate->pattern); - gstate->pattern = NULL; - - XrSurfaceDestroy(gstate->clip.surface); - gstate->clip.surface = NULL; - - _XrColorDeinit(&gstate->color); - - _XrMatrixFini(&gstate->ctm); - _XrMatrixFini(&gstate->ctm_inverse); - - _XrPathDeinit(&gstate->path); - - _XrPenDeinit(&gstate->pen_regular); - - if (gstate->dash) { - free (gstate->dash); - gstate->dash = NULL; - } -} - -void -_XrGStateDestroy(XrGState *gstate) -{ - _XrGStateDeinit(gstate); - free(gstate); -} - -XrGState* -_XrGStateClone(XrGState *gstate) -{ - XrStatus status; - XrGState *clone; - - clone = malloc(sizeof(XrGState)); - if (clone) { - status = _XrGStateInitCopy(clone, gstate); - if (status) { - free(clone); - return NULL; - } - } - - return clone; -} - -/* Push rendering off to an off-screen group. */ -/* XXX: Rethinking this API -XrStatus -_XrGStateBeginGroup(XrGState *gstate) -{ - Pixmap pix; - XrColor clear; - unsigned int width, height; - - gstate->parent_surface = gstate->surface; - - width = _XrSurfaceGetWidth(gstate->surface); - height = _XrSurfaceGetHeight(gstate->surface); - - pix = XCreatePixmap(gstate->dpy, - _XrSurfaceGetDrawable(gstate->surface), - width, height, - _XrSurfaceGetDepth(gstate->surface)); - if (pix == 0) - return XrStatusNoMemory; - - gstate->surface = XrSurfaceCreate(gstate->dpy); - if (gstate->surface == NULL) - return XrStatusNoMemory; - - _XrSurfaceSetDrawableWH(gstate->surface, pix, width, height); - - _XrColorInit(&clear); - _XrColorSetAlpha(&clear, 0); - - XcFillRectangle(XrOperatorSrc, - _XrSurfaceGetXcSurface(gstate->surface), - &clear.xc_color, - 0, 0, - _XrSurfaceGetWidth(gstate->surface), - _XrSurfaceGetHeight(gstate->surface)); - - return XrStatusSuccess; -} -*/ - -/* Complete the current offscreen group, composing its contents onto the parent surface. */ -/* XXX: Rethinking this API -XrStatus -_XrGStateEndGroup(XrGState *gstate) -{ - Pixmap pix; - XrColor mask_color; - XrSurface mask; - - if (gstate->parent_surface == NULL) - return XrStatusInvalidPopGroup; - - _XrSurfaceInit(&mask, gstate->dpy); - _XrColorInit(&mask_color); - _XrColorSetAlpha(&mask_color, gstate->alpha); - - _XrSurfaceSetSolidColor(&mask, &mask_color); - - * XXX: This could be made much more efficient by using - _XrSurfaceGetDamagedWidth/Height if XrSurface actually kept - track of such informaton. * - XcComposite(gstate->operator, - _XrSurfaceGetXcSurface(gstate->surface), - _XrSurfaceGetXcSurface(&mask), - _XrSurfaceGetXcSurface(gstate->parent_surface), - 0, 0, - 0, 0, - 0, 0, - _XrSurfaceGetWidth(gstate->surface), - _XrSurfaceGetHeight(gstate->surface)); - - _XrSurfaceDeinit(&mask); - - pix = _XrSurfaceGetDrawable(gstate->surface); - XFreePixmap(gstate->dpy, pix); - - XrSurfaceDestroy(gstate->surface); - gstate->surface = gstate->parent_surface; - gstate->parent_surface = NULL; - - return XrStatusSuccess; -} -*/ - -XrStatus -_XrGStateSetTargetSurface (XrGState *gstate, XrSurface *surface) -{ - double scale; - - XrSurfaceDestroy (gstate->surface); - - gstate->surface = surface; - _XrSurfaceReference (gstate->surface); - - scale = surface->ppm / gstate->ppm; - _XrGStateScale (gstate, scale, scale); - gstate->ppm = surface->ppm; - - return XrStatusSuccess; -} - -/* XXX: Need to decide the memory mangement semantics of this - function. Should it reference the surface again? */ -XrSurface * -_XrGStateGetTargetSurface (XrGState *gstate) -{ - if (gstate == NULL) - return NULL; - - return gstate->surface; -} - -XrStatus -_XrGStateSetPattern (XrGState *gstate, XrSurface *pattern) -{ - XrSurfaceDestroy (gstate->pattern); - - gstate->pattern = pattern; - _XrSurfaceReference (gstate->pattern); - - gstate->pattern_offset.x = 0; - gstate->pattern_offset.y = 0; - XrMatrixTransformPoint (&gstate->ctm, - &gstate->pattern_offset.x, - &gstate->pattern_offset.y); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateSetOperator(XrGState *gstate, XrOperator operator) -{ - gstate->operator = operator; - - return XrStatusSuccess; -} - -XrOperator -_XrGStateGetOperator(XrGState *gstate) -{ - return gstate->operator; -} - -XrStatus -_XrGStateSetRGBColor(XrGState *gstate, double red, double green, double blue) -{ - _XrColorSetRGB(&gstate->color, red, green, blue); - - XrSurfaceDestroy(gstate->pattern); - gstate->pattern = NULL; - - XrSurfaceDestroy(gstate->solid); - gstate->solid = XrSurfaceCreateNextToSolid (gstate->surface, XrFormatARGB32, - 1, 1, - red, green, blue, - gstate->alpha); - XrSurfaceSetRepeat (gstate->solid, 1); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateGetRGBColor(XrGState *gstate, double *red, double *green, double *blue) -{ - _XrColorGetRGB(&gstate->color, red, green, blue); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateSetTolerance(XrGState *gstate, double tolerance) -{ - gstate->tolerance = tolerance; - - return XrStatusSuccess; -} - -double -_XrGStateGetTolerance(XrGState *gstate) -{ - return gstate->tolerance; -} - -XrStatus -_XrGStateSetAlpha(XrGState *gstate, double alpha) -{ - gstate->alpha = alpha; - - _XrColorSetAlpha(&gstate->color, alpha); - - XrSurfaceDestroy (gstate->solid); - gstate->solid = XrSurfaceCreateNextToSolid (gstate->surface, - XrFormatARGB32, - 1, 1, - gstate->color.red, - gstate->color.green, - gstate->color.blue, - gstate->color.alpha); - XrSurfaceSetRepeat (gstate->solid, 1); - - return XrStatusSuccess; -} - -double -_XrGStateGetAlpha(XrGState *gstate) -{ - return gstate->alpha; -} - -XrStatus -_XrGStateSetFillRule(XrGState *gstate, XrFillRule fill_rule) -{ - gstate->fill_rule = fill_rule; - - return XrStatusSuccess; -} - -XrStatus -_XrGStateSetLineWidth(XrGState *gstate, double width) -{ - gstate->line_width = width; - - return XrStatusSuccess; -} - -double -_XrGStateGetLineWidth(XrGState *gstate) -{ - return gstate->line_width; -} - -XrStatus -_XrGStateSetLineCap(XrGState *gstate, XrLineCap line_cap) -{ - gstate->line_cap = line_cap; - - return XrStatusSuccess; -} - -XrLineCap -_XrGStateGetLineCap(XrGState *gstate) -{ - return gstate->line_cap; -} - -XrStatus -_XrGStateSetLineJoin(XrGState *gstate, XrLineJoin line_join) -{ - gstate->line_join = line_join; - - return XrStatusSuccess; -} - -XrLineJoin -_XrGStateGetLineJoin(XrGState *gstate) -{ - return gstate->line_join; -} - -XrStatus -_XrGStateSetDash(XrGState *gstate, double *dash, int num_dashes, double offset) -{ - if (gstate->dash) { - free (gstate->dash); - gstate->dash = NULL; - } - - gstate->num_dashes = num_dashes; - if (gstate->num_dashes) { - gstate->dash = malloc (gstate->num_dashes * sizeof (double)); - if (gstate->dash == NULL) { - gstate->num_dashes = 0; - return XrStatusNoMemory; - } - } - - memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); - gstate->dash_offset = offset; - - return XrStatusSuccess; -} - -XrStatus -_XrGStateSetMiterLimit(XrGState *gstate, double limit) -{ - gstate->miter_limit = limit; - - return XrStatusSuccess; -} - -double -_XrGStateGetMiterLimit(XrGState *gstate) -{ - return gstate->miter_limit; -} - -XrStatus -_XrGStateTranslate(XrGState *gstate, double tx, double ty) -{ - XrMatrix tmp; - - _XrMatrixSetTranslate(&tmp, tx, ty); - XrMatrixMultiply (&gstate->ctm, &tmp, &gstate->ctm); - - _XrMatrixSetTranslate(&tmp, -tx, -ty); - XrMatrixMultiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateScale(XrGState *gstate, double sx, double sy) -{ - XrMatrix tmp; - - if (sx == 0 || sy == 0) - return XrStatusInvalidMatrix; - - _XrMatrixSetScale(&tmp, sx, sy); - XrMatrixMultiply (&gstate->ctm, &tmp, &gstate->ctm); - - _XrMatrixSetScale(&tmp, 1/sx, 1/sy); - XrMatrixMultiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateRotate(XrGState *gstate, double angle) -{ - XrMatrix tmp; - - _XrMatrixSetRotate(&tmp, angle); - XrMatrixMultiply (&gstate->ctm, &tmp, &gstate->ctm); - - _XrMatrixSetRotate(&tmp, -angle); - XrMatrixMultiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateConcatMatrix(XrGState *gstate, - XrMatrix *matrix) -{ - XrMatrix tmp; - - XrMatrixCopy(&tmp, matrix); - XrMatrixMultiply (&gstate->ctm, &tmp, &gstate->ctm); - - XrMatrixInvert(&tmp); - XrMatrixMultiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateSetMatrix(XrGState *gstate, - XrMatrix *matrix) -{ - XrStatus status; - - XrMatrixCopy(&gstate->ctm, matrix); - - XrMatrixCopy(&gstate->ctm_inverse, matrix); - status = XrMatrixInvert (&gstate->ctm_inverse); - if (status) - return status; - - return XrStatusSuccess; -} - -XrStatus -_XrGStateDefaultMatrix(XrGState *gstate) -{ -#define XR_GSTATE_DEFAULT_PPM 3780.0 - - int scale = gstate->ppm / XR_GSTATE_DEFAULT_PPM + 0.5; - if (scale == 0) - scale = 1; - - XrMatrixSetIdentity (&gstate->ctm); - XrMatrixScale (&gstate->ctm, scale, scale); - XrMatrixCopy (&gstate->ctm_inverse, &gstate->ctm); - XrMatrixInvert (&gstate->ctm_inverse); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateIdentityMatrix(XrGState *gstate) -{ - XrMatrixSetIdentity(&gstate->ctm); - XrMatrixSetIdentity(&gstate->ctm_inverse); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateTransformPoint (XrGState *gstate, double *x, double *y) -{ - XrMatrixTransformPoint (&gstate->ctm, x, y); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateTransformDistance (XrGState *gstate, double *dx, double *dy) -{ - XrMatrixTransformDistance (&gstate->ctm, dx, dy); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateInverseTransformPoint (XrGState *gstate, double *x, double *y) -{ - XrMatrixTransformPoint (&gstate->ctm_inverse, x, y); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateInverseTransformDistance (XrGState *gstate, double *dx, double *dy) -{ - XrMatrixTransformDistance (&gstate->ctm_inverse, dx, dy); - - return XrStatusSuccess; -} - -static void -_XrGStateSetCurrentPt(XrGState *gstate, double x, double y) -{ - gstate->current_pt.x = x; - gstate->current_pt.y = y; - - gstate->has_current_pt = 1; -} - -XrStatus -_XrGStateNewPath(XrGState *gstate) -{ - _XrPathDeinit(&gstate->path); - gstate->has_current_pt = 0; - - return XrStatusSuccess; -} - -XrStatus -_XrGStateMoveTo(XrGState *gstate, double x, double y) -{ - XrStatus status; - - XrMatrixTransformPoint(&gstate->ctm, &x, &y); - - status = _XrPathMoveTo(&gstate->path, x, y); - - _XrGStateSetCurrentPt(gstate, x, y); - - gstate->last_move_pt = gstate->current_pt; - - return status; -} - -XrStatus -_XrGStateLineTo(XrGState *gstate, double x, double y) -{ - XrStatus status; - - XrMatrixTransformPoint(&gstate->ctm, &x, &y); - - status = _XrPathLineTo(&gstate->path, x, y); - - _XrGStateSetCurrentPt(gstate, x, y); - - return status; -} - -XrStatus -_XrGStateCurveTo(XrGState *gstate, - double x1, double y1, - double x2, double y2, - double x3, double y3) -{ - XrStatus status; - - XrMatrixTransformPoint(&gstate->ctm, &x1, &y1); - XrMatrixTransformPoint(&gstate->ctm, &x2, &y2); - XrMatrixTransformPoint(&gstate->ctm, &x3, &y3); - - status = _XrPathCurveTo(&gstate->path, - x1, y1, - x2, y2, - x3, y3); - - _XrGStateSetCurrentPt(gstate, x3, y3); - - return status; -} - -XrStatus -_XrGStateRelMoveTo(XrGState *gstate, double dx, double dy) -{ - XrStatus status; - double x, y; - - XrMatrixTransformDistance(&gstate->ctm, &dx, &dy); - - x = gstate->current_pt.x + dx; - y = gstate->current_pt.y + dy; - - status = _XrPathMoveTo(&gstate->path, x, y); - - _XrGStateSetCurrentPt(gstate, x, y); - - gstate->last_move_pt = gstate->current_pt; - - return status; -} - -XrStatus -_XrGStateRelLineTo(XrGState *gstate, double dx, double dy) -{ - XrStatus status; - double x, y; - - XrMatrixTransformDistance(&gstate->ctm, &dx, &dy); - - x = gstate->current_pt.x + dx; - y = gstate->current_pt.y + dy; - - status = _XrPathLineTo(&gstate->path, x, y); - - _XrGStateSetCurrentPt(gstate, x, y); - - return status; -} - -XrStatus -_XrGStateRelCurveTo(XrGState *gstate, - double dx1, double dy1, - double dx2, double dy2, - double dx3, double dy3) -{ - XrStatus status; - - XrMatrixTransformDistance(&gstate->ctm, &dx1, &dy1); - XrMatrixTransformDistance(&gstate->ctm, &dx2, &dy2); - XrMatrixTransformDistance(&gstate->ctm, &dx3, &dy3); - - status = _XrPathCurveTo(&gstate->path, - gstate->current_pt.x + dx1, gstate->current_pt.y + dy1, - gstate->current_pt.x + dx2, gstate->current_pt.y + dy2, - gstate->current_pt.x + dx3, gstate->current_pt.y + dy3); - - _XrGStateSetCurrentPt(gstate, - gstate->current_pt.x + dx3, - gstate->current_pt.y + dy3); - - return status; -} - -XrStatus -_XrGStateClosePath(XrGState *gstate) -{ - XrStatus status; - - status = _XrPathClosePath(&gstate->path); - - _XrGStateSetCurrentPt(gstate, - gstate->last_move_pt.x, - gstate->last_move_pt.y); - - return status; -} - -XrStatus -_XrGStateGetCurrentPoint(XrGState *gstate, double *x, double *y) -{ - *x = gstate->current_pt.x; - *y = gstate->current_pt.y; - - XrMatrixTransformPoint(&gstate->ctm_inverse, x, y); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateStroke(XrGState *gstate) -{ - XrStatus status; - - XrTraps traps; - - _XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate); - - _XrTrapsInit(&traps); - - status = _XrPathStrokeToTraps(&gstate->path, gstate, &traps); - if (status) { - _XrTrapsDeinit(&traps); - return status; - } - - _XrGStateClipAndCompositeTrapezoids(gstate, - gstate->pattern ? gstate->pattern : gstate->solid, - gstate->operator, - gstate->surface, - &traps); - - _XrTrapsDeinit(&traps); - - _XrGStateNewPath(gstate); - - return XrStatusSuccess; -} - -/* Warning: This call modifies the coordinates of traps */ -static XrStatus -_XrGStateClipAndCompositeTrapezoids(XrGState *gstate, - XrSurface *src, - XrOperator operator, - XrSurface *dst, - XrTraps *traps) -{ - if (traps->num_xtraps == 0) - return XrStatusSuccess; - - if (gstate->clip.surface) { - XFixed xoff, yoff; - XTrapezoid *t; - int i; - - XrSurface *intermediate, *white; - - white = XrSurfaceCreateNextToSolid(gstate->surface, XrFormatA8, - 1, 1, - 1.0, 1.0, 1.0, 1.0); - XrSurfaceSetRepeat(white, 1); - - intermediate = XrSurfaceCreateNextToSolid(gstate->clip.surface, - XrFormatA8, - gstate->clip.width, gstate->clip.height, - 0.0, 0.0, 0.0, 0.0); - - /* Ugh. The Xc/(Render) interface doesn't allow an offset for - the trapezoids. Need to manually shift all the coordinates - to align with the offset origin of the clip surface. */ - xoff = XDoubleToFixed (gstate->clip.x); - yoff = XDoubleToFixed (gstate->clip.y); - for (i=0, t=traps->xtraps; i < traps->num_xtraps; i++, t++) { - t->top -= yoff; - t->bottom -= yoff; - t->left.p1.x -= xoff; - t->left.p1.y -= yoff; - t->left.p2.x -= xoff; - t->left.p2.y -= yoff; - t->right.p1.x -= xoff; - t->right.p1.y -= yoff; - t->right.p2.x -= xoff; - t->right.p2.y -= yoff; - } - - XcCompositeTrapezoids(XrOperatorAdd, - white->xc_surface, - intermediate->xc_surface, - 0, 0, - traps->xtraps, - traps->num_xtraps); - XcComposite(XrOperatorIn, - gstate->clip.surface->xc_surface, - NULL, - intermediate->xc_surface, - 0, 0, 0, 0, 0, 0, - gstate->clip.width, gstate->clip.height); - XcComposite(operator, - src->xc_surface, - intermediate->xc_surface, - dst->xc_surface, - 0, 0, - 0, 0, - gstate->clip.x, - gstate->clip.y, - gstate->clip.width, - gstate->clip.height); - XrSurfaceDestroy(intermediate); - XrSurfaceDestroy (white); - - } else { - double xoff, yoff; - - if (traps->xtraps[0].left.p1.y < traps->xtraps[0].left.p2.y) { - xoff = traps->xtraps[0].left.p1.x; - yoff = traps->xtraps[0].left.p1.y; - } else { - xoff = traps->xtraps[0].left.p2.x; - yoff = traps->xtraps[0].left.p2.y; - } - - XcCompositeTrapezoids(gstate->operator, - src->xc_surface, - dst->xc_surface, - XFixedToDouble(xoff) - gstate->pattern_offset.x, - XFixedToDouble(yoff) - gstate->pattern_offset.y, - traps->xtraps, - traps->num_xtraps); - } - - return XrStatusSuccess; -} - -XrStatus -_XrGStateFill(XrGState *gstate) -{ - XrStatus status; - XrTraps traps; - - _XrTrapsInit(&traps); - - status = _XrPathFillToTraps(&gstate->path, gstate, &traps); - if (status) { - _XrTrapsDeinit(&traps); - return status; - } - - _XrGStateClipAndCompositeTrapezoids(gstate, - gstate->pattern ? gstate->pattern : gstate->solid, - gstate->operator, - gstate->surface, - &traps); - _XrTrapsDeinit(&traps); - - _XrGStateNewPath(gstate); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateClip(XrGState *gstate) -{ - XrStatus status; - XrSurface *alpha_one; - XrTraps traps; - - if (gstate->clip.surface == NULL) { - double x1, y1, x2, y2; - _XrPathBounds(&gstate->path, - &x1, &y1, &x2, &y2); - gstate->clip.x = floor(x1); - gstate->clip.y = floor(y1); - gstate->clip.width = ceil(x2 - gstate->clip.x); - gstate->clip.height = ceil(y2 - gstate->clip.y); - gstate->clip.surface = XrSurfaceCreateNextToSolid(gstate->surface, - XrFormatA8, - gstate->clip.width, - gstate->clip.height, - 1.0, 1.0, 1.0, 1.0); - } - - alpha_one = XrSurfaceCreateNextToSolid(gstate->surface, XrFormatA8, - 1, 1, - 0.0, 0.0, 0.0, 1.0); - XrSurfaceSetRepeat(alpha_one, 1); - - _XrTrapsInit(&traps); - status = _XrPathFillToTraps(&gstate->path, gstate, &traps); - if (status) { - _XrTrapsDeinit(&traps); - return status; - } - - _XrGStateClipAndCompositeTrapezoids(gstate, - alpha_one, - XrOperatorIn, - gstate->clip.surface, - &traps); - - _XrTrapsDeinit(&traps); - - XrSurfaceDestroy (alpha_one); - - return status; -} - -XrStatus -_XrGStateSelectFont(XrGState *gstate, const char *key) -{ - return _XrFontSelect(&gstate->font, key); -} - -XrStatus -_XrGStateScaleFont(XrGState *gstate, double scale) -{ - return _XrFontScale(&gstate->font, scale); -} - -XrStatus -_XrGStateTransformFont(XrGState *gstate, - double a, double b, - double c, double d) -{ - return _XrFontTransform(&gstate->font, - a, b, c, d); -} - -XrStatus -_XrGStateTextExtents(XrGState *gstate, - const unsigned char *utf8, - double *x, double *y, - double *width, double *height, - double *dx, double *dy) -{ - XftFont *xft_font; - XGlyphInfo extents; - - _XrFontResolveXftFont(&gstate->font, gstate, &xft_font); - - /* XXX: Need to abandon Xft and use Xc instead */ - /* (until I do, this call will croak on IcImage XrSurfaces */ - XftTextExtentsUtf8(gstate->surface->dpy, - xft_font, - utf8, - strlen((char *) utf8), - &extents); - - /* XXX: What are the semantics of XftTextExtents? Specifically, - what does it do with x/y? I think we actually need to use the - gstate's current point in here somewhere. */ - *x = extents.x; - *y = extents.y; - *width = extents.width; - *height = extents.height; - *dx = extents.xOff; - *dy = extents.yOff; - - return XrStatusSuccess; -} - -XrStatus -_XrGStateShowText(XrGState *gstate, const unsigned char *utf8) -{ - XftFont *xft_font; - - if (gstate->has_current_pt == 0) - return XrStatusNoCurrentPoint; - - _XrFontResolveXftFont(&gstate->font, gstate, &xft_font); - - /* XXX: Need to abandon Xft and use Xc instead */ - /* (until I do, this call will croak on IcImage XrSurfaces */ - /* (also, this means text clipping isn't working. Basically text is broken.) */ - XftTextRenderUtf8(gstate->surface->dpy, - gstate->operator, - _XrSurfaceGetPicture (gstate->solid), - xft_font, - _XrSurfaceGetPicture (gstate->surface), - 0, 0, - gstate->current_pt.x, - gstate->current_pt.y, - utf8, - strlen((char *) utf8)); - - return XrStatusSuccess; -} - -XrStatus -_XrGStateShowSurface(XrGState *gstate, - XrSurface *surface, - int width, - int height) -{ - XrSurface *mask; - XrMatrix user_to_image, image_to_user; - XrMatrix image_to_device, device_to_image; - double device_x, device_y; - double device_width, device_height; - - mask = XrSurfaceCreateNextToSolid (gstate->surface, - XrFormatA8, - 1, 1, - 1.0, 1.0, 1.0, - gstate->alpha); - if (mask == NULL) - return XrStatusNoMemory; - - XrSurfaceSetRepeat (mask, 1); - - XrSurfaceGetMatrix (surface, &user_to_image); - XrMatrixMultiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); - XrSurfaceSetMatrix (surface, &device_to_image); - - image_to_user = user_to_image; - XrMatrixInvert (&image_to_user); - XrMatrixMultiply (&image_to_device, &image_to_user, &gstate->ctm); - - device_x = 0; - device_y = 0; - device_width = width; - device_height = height; - _XrMatrixTransformBoundingBox(&image_to_device, - &device_x, &device_y, - &device_width, &device_height); - - /* XXX: The rendered size is sometimes 1 or 2 pixels short from - what I expect. Need to fix this. */ - XcComposite(gstate->operator, - surface->xc_surface, - mask->xc_surface, - gstate->surface->xc_surface, - device_x, device_y, - 0, 0, - device_x, device_y, - device_width, - device_height); - - XrSurfaceDestroy (mask); - - /* restore the matrix originally in the surface */ - XrSurfaceSetMatrix (surface, &user_to_image); - - return XrStatusSuccess; -} diff --git a/src/xrint.h b/src/xrint.h deleted file mode 100644 index 9c21bbeb7..000000000 --- a/src/xrint.h +++ /dev/null @@ -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 diff --git a/src/xrmatrix.c b/src/xrmatrix.c deleted file mode 100644 index 856ccf726..000000000 --- a/src/xrmatrix.c +++ /dev/null @@ -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; -} diff --git a/src/xrmisc.c b/src/xrmisc.c deleted file mode 100644 index 74e7585d2..000000000 --- a/src/xrmisc.c +++ /dev/null @@ -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; -} - diff --git a/src/xrpath.c b/src/xrpath.c deleted file mode 100644 index 65fcb54c6..000000000 --- a/src/xrpath.c +++ /dev/null @@ -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, ¤t, &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, ¤t, &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, ¤t, &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); -} - - diff --git a/src/xrpathbounds.c b/src/xrpathbounds.c deleted file mode 100644 index 7009a3c4a..000000000 --- a/src/xrpathbounds.c +++ /dev/null @@ -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; -} diff --git a/src/xrpathfill.c b/src/xrpathfill.c deleted file mode 100644 index 47f1a10d3..000000000 --- a/src/xrpathfill.c +++ /dev/null @@ -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; -} - diff --git a/src/xrpathstroke.c b/src/xrpathstroke.c deleted file mode 100644 index 027ec0652..000000000 --- a/src/xrpathstroke.c +++ /dev/null @@ -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; -} diff --git a/src/xrpen.c b/src/xrpen.c deleted file mode 100644 index bb7c47d92..000000000 --- a/src/xrpen.c +++ /dev/null @@ -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; -} diff --git a/src/xrpolygon.c b/src/xrpolygon.c deleted file mode 100644 index d638ece10..000000000 --- a/src/xrpolygon.c +++ /dev/null @@ -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; -} diff --git a/src/xrspline.c b/src/xrspline.c deleted file mode 100644 index d4e7c269b..000000000 --- a/src/xrspline.c +++ /dev/null @@ -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; -} - diff --git a/src/xrstate.c b/src/xrstate.c deleted file mode 100644 index 92768097b..000000000 --- a/src/xrstate.c +++ /dev/null @@ -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; -} - diff --git a/src/xrstroker.c b/src/xrstroker.c deleted file mode 100644 index 07592dea9..000000000 --- a/src/xrstroker.c +++ /dev/null @@ -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; -} diff --git a/src/xrsurface.c b/src/xrsurface.c deleted file mode 100644 index 7cf6b512c..000000000 --- a/src/xrsurface.c +++ /dev/null @@ -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); -} - |