mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-03 07:48:04 +02:00
Renamed everything from Xr* to cairo_*
This commit is contained in:
parent
4a57fd0881
commit
dc1e96ae35
58 changed files with 11733 additions and 7351 deletions
|
|
@ -2,6 +2,7 @@ Makefile
|
|||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
cairo.pc
|
||||
config.cache
|
||||
config.guess
|
||||
config.h
|
||||
|
|
@ -15,4 +16,4 @@ ltmain.sh
|
|||
stamp-h
|
||||
stamp-h1
|
||||
stamp-h.in
|
||||
xr.pc
|
||||
|
||||
|
|
|
|||
5
BUGS
5
BUGS
|
|
@ -1,2 +1,3 @@
|
|||
SEGV if XrSetRGBColor is called before XrSetTargetDrawable
|
||||
SEGV if XrFill is called before XrSetRGBColor
|
||||
SEGV if cairo_set_rgb_color is called before cairo_set_target_drawable
|
||||
SEGV if cairo_fill is called before cairo_set_rgb_color
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
2003-07-18 Carl Worth <cworth@isi.edu>
|
||||
|
||||
* src/cairo.h: Renamed everything from Xr* to cairo_*.
|
||||
|
||||
* util/xr2cairo: Added utility script xr2cairo to help users fix
|
||||
their source code.
|
||||
|
||||
2003-07-03 Carl Worth <cworth@isi.edu>
|
||||
|
||||
* src/xrmatrix.c (XrMatrixGetAffine): Added XrMatrixGetAffine
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ SUBDIRS = src
|
|||
|
||||
EXTRA_DIST = \
|
||||
COPYING \
|
||||
xr.pc.in
|
||||
cairo.pc.in
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = xr.pc
|
||||
pkgconfig_DATA = cairo.pc
|
||||
|
|
|
|||
30
README
30
README
|
|
@ -1,4 +1,4 @@
|
|||
Xr - Rendering library
|
||||
Cairo - Multi-platform 2D graphics library
|
||||
|
||||
Compiling
|
||||
---------
|
||||
|
|
@ -6,27 +6,27 @@ See the INSTALL document for build instructions.
|
|||
|
||||
Description
|
||||
-----------
|
||||
Xr provides anti-aliased vector-based rendering for X. Paths consist
|
||||
Cairo provides anti-aliased vector-based rendering for X. Paths consist
|
||||
of line segments and cubic splines and can be rendered at any width
|
||||
with various join and cap styles. All colors may be specified with
|
||||
optional translucence (opacity/alpha) and combined using the extended
|
||||
Porter/Duff compositing algebra as found in the X Render Extension.
|
||||
|
||||
Xr exports a stateful rendering API similar in spirit to the path
|
||||
Cairo exports a stateful rendering API similar in spirit to the path
|
||||
construction, text, and painting operators of PostScript, (with the
|
||||
significant addition of translucence in the imaging model). When
|
||||
complete, the API is intended to support the complete imaging model of
|
||||
PDF 1.4.
|
||||
|
||||
Xr relies on the Xc library for backend rendering. Xc provides an
|
||||
Cairo relies on the Xc library for backend rendering. Xc provides an
|
||||
abstract interface for rendering to multiple target types. As of this
|
||||
writing, Xc allows Xr to target X drawables as well as generic image
|
||||
writing, Xc allows Cairo to target X drawables as well as generic image
|
||||
buffers. Future backends such as PostScript, PDF, and perhaps OpenGL
|
||||
are currently being planned.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
Xr currently requires the following supporting libraries:
|
||||
Cairo currently requires the following supporting libraries:
|
||||
|
||||
Xc
|
||||
Xft
|
||||
|
|
@ -36,28 +36,28 @@ Xr currently requires the following supporting libraries:
|
|||
|
||||
Documentation
|
||||
-------------
|
||||
There's not much documentation yet apart from the Xr.h header
|
||||
There's not much documentation yet apart from the cairo.h header
|
||||
file. We'll be correcting that shortly.
|
||||
|
||||
In the meantime, the xrtest module in CVS provides a few example
|
||||
programs using Xr. These may be helpful to a programmer just beginning
|
||||
with Xr. Also, familiarity with the PostScript imaging model will
|
||||
help in understanding Xr.
|
||||
programs using Cairo. These may be helpful to a programmer just beginning
|
||||
with Cairo. Also, familiarity with the PostScript imaging model will
|
||||
help in understanding Cairo.
|
||||
|
||||
History
|
||||
-------
|
||||
Xr was developed by Carl Worth <cworth@isi.edu> and Keith Packard
|
||||
Cairo was developed by Carl Worth <cworth@isi.edu> and Keith Packard
|
||||
<keithp@keithp.com>. Many thanks are due to Lyle Ramshaw without whose
|
||||
patient help our ignorance would be much more apparent.
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
If you have trouble with Xr or you have some ideas for how it could be
|
||||
improved, please feel free to send a message to xr@xwin.org.
|
||||
If you have trouble with Cairo or you have some ideas for how it could be
|
||||
improved, please feel free to send a message to cairo@cairographics.org
|
||||
|
||||
Xr is still under active development and all discussion happens on
|
||||
Cairo is still under active development and all discussion happens on
|
||||
that list. So if you want to lurk or, (even better), take part in the
|
||||
development, take a look. Subscription information and archives are
|
||||
available:
|
||||
|
||||
http://xwin.org/cgi-bin/mailman/listinfo/xr
|
||||
http://cairographics.org/cgi-bin/mailman/listinfo/cairo
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ exec_prefix=@exec_prefix@
|
|||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: Xr
|
||||
Description: X Rendering library
|
||||
Name: cairo
|
||||
Description: Multi-platform 2D graphics library
|
||||
Version: @VERSION@
|
||||
|
||||
Requires: xc xft
|
||||
Libs: -L${libdir} -lXr -lm
|
||||
Libs: -L${libdir} -lcairo -lm
|
||||
Cflags: -I${includedir}
|
||||
|
||||
14
configure.in
14
configure.in
|
|
@ -1,9 +1,9 @@
|
|||
AC_INIT(src/Xr.h)
|
||||
AC_INIT(src/cairo.h)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
# Package version number, (as distinct from shared library version)
|
||||
XR_VERSION=0.1.0
|
||||
CAIRO_VERSION=0.1.0
|
||||
|
||||
# libtool shared library version
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ XFT_REQUIRED=2.1.1
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
AM_INIT_AUTOMAKE(xr, $XR_VERSION)
|
||||
AM_INIT_AUTOMAKE(cairo, $CAIRO_VERSION)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
|
@ -45,14 +45,14 @@ AC_PATH_XTRA
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
PKG_CHECK_MODULES(XR, xc >= $XC_REQUIRED xft >= $XFT_REQUIRED)
|
||||
AC_SUBST(XR_CFLAGS)
|
||||
AC_SUBST(XR_LIBS)
|
||||
PKG_CHECK_MODULES(CAIRO, xc >= $XC_REQUIRED xft >= $XFT_REQUIRED)
|
||||
AC_SUBST(CAIRO_CFLAGS)
|
||||
AC_SUBST(CAIRO_LIBS)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_OUTPUT([
|
||||
xr.pc
|
||||
cairo.pc
|
||||
Makefile
|
||||
src/Makefile
|
||||
])
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
lib_LTLIBRARIES = libXr.la
|
||||
include_HEADERS = Xr.h
|
||||
lib_LTLIBRARIES = libcairo.la
|
||||
include_HEADERS = cairo.h
|
||||
|
||||
libXr_la_SOURCES = \
|
||||
Xr.h \
|
||||
xr.c \
|
||||
xrint.h \
|
||||
xrcolor.c \
|
||||
xrfont.c \
|
||||
xrgstate.c \
|
||||
xrmatrix.c \
|
||||
xrmisc.c \
|
||||
xrpath.c \
|
||||
xrpathbounds.c \
|
||||
xrpathfill.c \
|
||||
xrpathstroke.c \
|
||||
xrpen.c \
|
||||
xrpolygon.c \
|
||||
xrspline.c \
|
||||
xrstate.c \
|
||||
xrsurface.c \
|
||||
xrtraps.c
|
||||
libcairo_la_SOURCES = \
|
||||
cairo.h \
|
||||
cairo.c \
|
||||
cairoint.h \
|
||||
cairo_color.c \
|
||||
cairo_font.c \
|
||||
cairo_gstate.c \
|
||||
cairo_matrix.c \
|
||||
cairo_misc.c \
|
||||
cairo_path.c \
|
||||
cairo_path_bounds.c \
|
||||
cairo_path_fill.c \
|
||||
cairo_path_stroke.c \
|
||||
cairo_pen.c \
|
||||
cairo_polygon.c \
|
||||
cairo_spline.c \
|
||||
cairo_surface.c \
|
||||
cairo_traps.c
|
||||
|
||||
libXr_la_LDFLAGS = -version-info @VERSION_INFO@
|
||||
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@
|
||||
|
||||
INCLUDES = $(XR_CFLAGS) $(X_CFLAGS)
|
||||
INCLUDES = $(CAIRO_CFLAGS) $(X_CFLAGS)
|
||||
|
||||
libXr_la_LIBADD = $(XR_LIBS) -lm
|
||||
libcairo_la_LIBADD = $(CAIRO_LIBS) -lm
|
||||
|
|
|
|||
476
src/Xr.h
476
src/Xr.h
|
|
@ -1,476 +0,0 @@
|
|||
/*
|
||||
* $XFree86: $
|
||||
*
|
||||
* Copyright © 2002 Carl D. Worth
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of Carl
|
||||
* D. Worth not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Carl D. Worth makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _XR_H_
|
||||
#define _XR_H_
|
||||
|
||||
#include <Xc.h>
|
||||
|
||||
typedef struct _XrState XrState;
|
||||
typedef struct _XrSurface XrSurface;
|
||||
typedef struct _XrMatrix XrMatrix;
|
||||
|
||||
_XFUNCPROTOBEGIN
|
||||
|
||||
/* Functions for manipulating state objects */
|
||||
XrState *
|
||||
XrCreate(void);
|
||||
|
||||
void
|
||||
XrDestroy(XrState *xrs);
|
||||
|
||||
void
|
||||
XrSave(XrState *xrs);
|
||||
|
||||
void
|
||||
XrRestore(XrState *xrs);
|
||||
|
||||
/* XXX: I want to rethink this API
|
||||
void
|
||||
XrPushGroup(XrState *xrs);
|
||||
|
||||
void
|
||||
XrPopGroup(XrState *xrs);
|
||||
*/
|
||||
|
||||
/* Modify state */
|
||||
void
|
||||
XrSetTargetSurface (XrState *xrs, XrSurface *surface);
|
||||
|
||||
typedef enum _XrFormat {
|
||||
XrFormatARGB32 = PictStandardARGB32,
|
||||
XrFormatRGB24 = PictStandardRGB24,
|
||||
XrFormatA8 = PictStandardA8,
|
||||
XrFormatA1 = PictStandardA1
|
||||
} XrFormat;
|
||||
|
||||
void
|
||||
XrSetTargetDrawable (XrState *xrs,
|
||||
Display *dpy,
|
||||
Drawable drawable);
|
||||
|
||||
void
|
||||
XrSetTargetImage (XrState *xrs,
|
||||
char *data,
|
||||
XrFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
typedef enum _XrOperator {
|
||||
XrOperatorClear = PictOpClear,
|
||||
XrOperatorSrc = PictOpSrc,
|
||||
XrOperatorDst = PictOpDst,
|
||||
XrOperatorOver = PictOpOver,
|
||||
XrOperatorOverReverse = PictOpOverReverse,
|
||||
XrOperatorIn = PictOpIn,
|
||||
XrOperatorInReverse = PictOpInReverse,
|
||||
XrOperatorOut = PictOpOut,
|
||||
XrOperatorOutReverse = PictOpOutReverse,
|
||||
XrOperatorAtop = PictOpAtop,
|
||||
XrOperatorAtopReverse = PictOpAtopReverse,
|
||||
XrOperatorXor = PictOpXor,
|
||||
XrOperatorAdd = PictOpAdd,
|
||||
XrOperatorSaturate = PictOpSaturate,
|
||||
|
||||
XrOperatorDisjointClear = PictOpDisjointClear,
|
||||
XrOperatorDisjointSrc = PictOpDisjointSrc,
|
||||
XrOperatorDisjointDst = PictOpDisjointDst,
|
||||
XrOperatorDisjointOver = PictOpDisjointOver,
|
||||
XrOperatorDisjointOverReverse = PictOpDisjointOverReverse,
|
||||
XrOperatorDisjointIn = PictOpDisjointIn,
|
||||
XrOperatorDisjointInReverse = PictOpDisjointInReverse,
|
||||
XrOperatorDisjointOut = PictOpDisjointOut,
|
||||
XrOperatorDisjointOutReverse = PictOpDisjointOutReverse,
|
||||
XrOperatorDisjointAtop = PictOpDisjointAtop,
|
||||
XrOperatorDisjointAtopReverse = PictOpDisjointAtopReverse,
|
||||
XrOperatorDisjointXor = PictOpDisjointXor,
|
||||
|
||||
XrOperatorConjointClear = PictOpConjointClear,
|
||||
XrOperatorConjointSrc = PictOpConjointSrc,
|
||||
XrOperatorConjointDst = PictOpConjointDst,
|
||||
XrOperatorConjointOver = PictOpConjointOver,
|
||||
XrOperatorConjointOverReverse = PictOpConjointOverReverse,
|
||||
XrOperatorConjointIn = PictOpConjointIn,
|
||||
XrOperatorConjointInReverse = PictOpConjointInReverse,
|
||||
XrOperatorConjointOut = PictOpConjointOut,
|
||||
XrOperatorConjointOutReverse = PictOpConjointOutReverse,
|
||||
XrOperatorConjointAtop = PictOpConjointAtop,
|
||||
XrOperatorConjointAtopReverse = PictOpConjointAtopReverse,
|
||||
XrOperatorConjointXor = PictOpConjointXor
|
||||
} XrOperator;
|
||||
|
||||
void
|
||||
XrSetOperator(XrState *xrs, XrOperator op);
|
||||
|
||||
/* XXX: Probably want to bite the bullet and expose an XrColor object */
|
||||
|
||||
void
|
||||
XrSetRGBColor(XrState *xrs, double red, double green, double blue);
|
||||
|
||||
void
|
||||
XrGetRGBColor(XrState *xrs, double *red, double *green, double *blue);
|
||||
|
||||
/* XXX: Do we want XrGetPattern as well? */
|
||||
void
|
||||
XrSetPattern(XrState *xrs, XrSurface *pattern);
|
||||
|
||||
void
|
||||
XrSetTolerance(XrState *xrs, double tolerance);
|
||||
|
||||
void
|
||||
XrSetAlpha(XrState *xrs, double alpha);
|
||||
|
||||
double
|
||||
XrGetAlpha(XrState *xrs);
|
||||
|
||||
typedef enum _XrFillRule { XrFillRuleWinding, XrFillRuleEvenOdd } XrFillRule;
|
||||
|
||||
void
|
||||
XrSetFillRule(XrState *xrs, XrFillRule fill_rule);
|
||||
|
||||
void
|
||||
XrSetLineWidth(XrState *xrs, double width);
|
||||
|
||||
typedef enum _XrLineCap { XrLineCapButt, XrLineCapRound, XrLineCapSquare } XrLineCap;
|
||||
|
||||
void
|
||||
XrSetLineCap(XrState *xrs, XrLineCap line_cap);
|
||||
|
||||
typedef enum _XrLineJoin { XrLineJoinMiter, XrLineJoinRound, XrLineJoinBevel } XrLineJoin;
|
||||
|
||||
void
|
||||
XrSetLineJoin(XrState *xrs, XrLineJoin line_join);
|
||||
|
||||
void
|
||||
XrSetDash(XrState *xrs, double *dashes, int ndash, double offset);
|
||||
|
||||
void
|
||||
XrSetMiterLimit(XrState *xrs, double limit);
|
||||
|
||||
void
|
||||
XrTranslate(XrState *xrs, double tx, double ty);
|
||||
|
||||
void
|
||||
XrScale(XrState *xrs, double sx, double sy);
|
||||
|
||||
void
|
||||
XrRotate(XrState *xrs, double angle);
|
||||
|
||||
void
|
||||
XrConcatMatrix(XrState *xrs,
|
||||
XrMatrix *matrix);
|
||||
|
||||
void
|
||||
XrSetMatrix(XrState *xrs,
|
||||
XrMatrix *matrix);
|
||||
|
||||
void
|
||||
XrDefaultMatrix(XrState *xrs);
|
||||
|
||||
/* XXX: There's been a proposal to add XrDefaultMatrixExact */
|
||||
|
||||
void
|
||||
XrIdentityMatrix(XrState *xrs);
|
||||
|
||||
void
|
||||
XrTransformPoint (XrState *xrs, double *x, double *y);
|
||||
|
||||
void
|
||||
XrTransformDistance (XrState *xrs, double *dx, double *dy);
|
||||
|
||||
void
|
||||
XrInverseTransformPoint (XrState *xrs, double *x, double *y);
|
||||
|
||||
void
|
||||
XrInverseTransformDistance (XrState *xrs, double *dx, double *dy);
|
||||
|
||||
/* Path creation functions */
|
||||
void
|
||||
XrNewPath(XrState *xrs);
|
||||
|
||||
void
|
||||
XrMoveTo(XrState *xrs, double x, double y);
|
||||
|
||||
void
|
||||
XrLineTo(XrState *xrs, double x, double y);
|
||||
|
||||
void
|
||||
XrCurveTo(XrState *xrs,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
|
||||
void
|
||||
XrRelMoveTo(XrState *xrs, double dx, double dy);
|
||||
|
||||
void
|
||||
XrRelLineTo(XrState *xrs, double dx, double dy);
|
||||
|
||||
void
|
||||
XrRelCurveTo(XrState *xrs,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
double dx3, double dy3);
|
||||
|
||||
void
|
||||
XrRectangle (XrState *xrs,
|
||||
double x, double y,
|
||||
double width, double height);
|
||||
|
||||
void
|
||||
XrClosePath(XrState *xrs);
|
||||
|
||||
/* Painting functions */
|
||||
void
|
||||
XrStroke(XrState *xrs);
|
||||
|
||||
void
|
||||
XrFill(XrState *xrs);
|
||||
|
||||
/* Clipping */
|
||||
void
|
||||
XrClip(XrState *xrs);
|
||||
|
||||
/* Font/Text functions */
|
||||
|
||||
/* XXX: The font support should probably expose an XrFont object with
|
||||
several functions, (XrFontTransform, etc.) in a parallel manner as
|
||||
XrMatrix and (eventually) XrColor */
|
||||
void
|
||||
XrSelectFont(XrState *xrs, const char *key);
|
||||
|
||||
void
|
||||
XrScaleFont(XrState *xrs, double scale);
|
||||
|
||||
/* XXX: Probably want to use an XrMatrix here, (to fix as part of the
|
||||
big text support rewrite) */
|
||||
void
|
||||
XrTransformFont(XrState *xrs,
|
||||
double a, double b,
|
||||
double c, double d);
|
||||
|
||||
void
|
||||
XrTextExtents(XrState *xrs,
|
||||
const unsigned char *utf8,
|
||||
double *x, double *y,
|
||||
double *width, double *height,
|
||||
double *dx, double *dy);
|
||||
|
||||
void
|
||||
XrShowText(XrState *xrs, const unsigned char *utf8);
|
||||
|
||||
/* Image functions */
|
||||
|
||||
void
|
||||
XrShowSurface (XrState *xrs,
|
||||
XrSurface *surface,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* Query functions */
|
||||
|
||||
XrOperator
|
||||
XrGetOperator(XrState *xrs);
|
||||
|
||||
double
|
||||
XrGetTolerance(XrState *xrs);
|
||||
|
||||
void
|
||||
XrGetCurrentPoint(XrState *, double *x, double *y);
|
||||
|
||||
XrFillRule
|
||||
XrGetFillRule(XrState *xrs);
|
||||
|
||||
double
|
||||
XrGetLineWidth(XrState *xrs);
|
||||
|
||||
XrLineCap
|
||||
XrGetLineCap(XrState *xrs);
|
||||
|
||||
XrLineJoin
|
||||
XrGetLineJoin(XrState *xrs);
|
||||
|
||||
double
|
||||
XrGetMiterLimit(XrState *xrs);
|
||||
|
||||
/* XXX: How to do XrGetDash??? Do we want to switch to an XrDash object? */
|
||||
|
||||
void
|
||||
XrGetMatrix(XrState *xrs,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty);
|
||||
|
||||
XrSurface *
|
||||
XrGetTargetSurface (XrState *xrs);
|
||||
|
||||
/* Error status queries */
|
||||
|
||||
typedef enum _XrStatus {
|
||||
XrStatusSuccess = 0,
|
||||
XrStatusNoMemory,
|
||||
XrStatusInvalidRestore,
|
||||
XrStatusInvalidPopGroup,
|
||||
XrStatusNoCurrentPoint,
|
||||
XrStatusInvalidMatrix
|
||||
} XrStatus;
|
||||
|
||||
XrStatus
|
||||
XrGetStatus(XrState *xrs);
|
||||
|
||||
const char *
|
||||
XrGetStatusString(XrState *xrs);
|
||||
|
||||
/* Surface mainpulation */
|
||||
|
||||
/* XXX: This is a mess from the user's POV. Should the Visual or the
|
||||
XrFormat control what render format is used? Maybe I can have
|
||||
XrSurfaceCreateForWindow with a visual, and
|
||||
XrSurfaceCreateForPixmap with an XrFormat. Would that work?
|
||||
*/
|
||||
XrSurface *
|
||||
XrSurfaceCreateForDrawable (Display *dpy,
|
||||
Drawable drawable,
|
||||
Visual *visual,
|
||||
XrFormat format,
|
||||
Colormap colormap);
|
||||
|
||||
XrSurface *
|
||||
XrSurfaceCreateForImage (char *data,
|
||||
XrFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
XrSurface *
|
||||
XrSurfaceCreateNextTo (XrSurface *neighbor,
|
||||
XrFormat format,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* XXX: One problem with having RGB and A here in one function is that
|
||||
it introduces the question of pre-multiplied vs. non-pre-multiplied
|
||||
alpha. Do I want to export an XrColor structure instead? So far, no
|
||||
other public functions need it. */
|
||||
XrSurface *
|
||||
XrSurfaceCreateNextToSolid (XrSurface *neighbor,
|
||||
XrFormat format,
|
||||
int width,
|
||||
int height,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha);
|
||||
|
||||
void
|
||||
XrSurfaceDestroy(XrSurface *surface);
|
||||
|
||||
/* XXX: Should this take an X/Y offset as well? (Probably) */
|
||||
XrStatus
|
||||
XrSurfacePutImage (XrSurface *surface,
|
||||
char *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
/* XXX: The Xc version of this function isn't quite working yet
|
||||
XrStatus
|
||||
XrSurfaceSetClipRegion (XrSurface *surface, Region region);
|
||||
*/
|
||||
|
||||
/* XXX: Note: The current Render/Ic implementations don't do the right
|
||||
thing with repeat when the surface has a non-identity matrix. */
|
||||
XrStatus
|
||||
XrSurfaceSetRepeat (XrSurface *surface, int repeat);
|
||||
|
||||
XrStatus
|
||||
XrSurfaceSetMatrix(XrSurface *surface, XrMatrix *matrix);
|
||||
|
||||
XrStatus
|
||||
XrSurfaceGetMatrix (XrSurface *surface, XrMatrix *matrix);
|
||||
|
||||
typedef enum {
|
||||
XrFilterFast = XcFilterFast,
|
||||
XrFilterGood = XcFilterGood,
|
||||
XrFilterBest = XcFilterBest,
|
||||
XrFilterNearest = XcFilterNearest,
|
||||
XrFilterBilinear = XcFilterBilinear
|
||||
} XrFilter;
|
||||
|
||||
XrStatus
|
||||
XrSurfaceSetFilter(XrSurface *surface, XrFilter filter);
|
||||
|
||||
/* Matrix functions */
|
||||
|
||||
XrMatrix *
|
||||
XrMatrixCreate (void);
|
||||
|
||||
void
|
||||
XrMatrixDestroy (XrMatrix *matrix);
|
||||
|
||||
XrStatus
|
||||
XrMatrixCopy(XrMatrix *matrix, const XrMatrix *other);
|
||||
|
||||
XrStatus
|
||||
XrMatrixSetIdentity (XrMatrix *matrix);
|
||||
|
||||
XrStatus
|
||||
XrMatrixSetAffine (XrMatrix *xrs,
|
||||
double a, double b,
|
||||
double c, double d,
|
||||
double tx, double ty);
|
||||
|
||||
XrStatus
|
||||
XrMatrixGetAffine (XrMatrix *matrix,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty);
|
||||
|
||||
XrStatus
|
||||
XrMatrixTranslate (XrMatrix *matrix, double tx, double ty);
|
||||
|
||||
XrStatus
|
||||
XrMatrixScale (XrMatrix *matrix, double sx, double sy);
|
||||
|
||||
XrStatus
|
||||
XrMatrixRotate (XrMatrix *matrix, double radians);
|
||||
|
||||
XrStatus
|
||||
XrMatrixInvert(XrMatrix *matrix);
|
||||
|
||||
XrStatus
|
||||
XrMatrixMultiply (XrMatrix *result, const XrMatrix *a, const XrMatrix *b);
|
||||
|
||||
XrStatus
|
||||
XrMatrixTransformDistance (XrMatrix *xr, double *dx, double *dy);
|
||||
|
||||
XrStatus
|
||||
XrMatrixTransformPoint (XrMatrix *xr, double *x, double *y);
|
||||
|
||||
_XFUNCPROTOEND
|
||||
|
||||
#endif
|
||||
|
||||
80
src/cairo-color.c
Normal file
80
src/cairo-color.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_color_t CAIRO_COLOR_DEFAULT = { 1.0, 1.0, 1.0, 1.0, {0xffff, 0xffff, 0xffff, 0xffff}};
|
||||
|
||||
static void
|
||||
_cairo_color_compute_xc_color (cairo_color_t *color);
|
||||
|
||||
void
|
||||
_cairo_color_init (cairo_color_t *color)
|
||||
{
|
||||
*color = CAIRO_COLOR_DEFAULT;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_fini (cairo_color_t *color)
|
||||
{
|
||||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_color_compute_xc_color (cairo_color_t *color)
|
||||
{
|
||||
color->xc_color.red = color->red * color->alpha * 0xffff;
|
||||
color->xc_color.green = color->green * color->alpha * 0xffff;
|
||||
color->xc_color.blue = color->blue * color->alpha * 0xffff;
|
||||
color->xc_color.alpha = color->alpha * 0xffff;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
|
||||
{
|
||||
color->red = red;
|
||||
color->green = green;
|
||||
color->blue = blue;
|
||||
|
||||
_cairo_color_compute_xc_color (color);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
|
||||
{
|
||||
*red = color->red;
|
||||
*green = color->green;
|
||||
*blue = color->blue;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_set_alpha (cairo_color_t *color, double alpha)
|
||||
{
|
||||
color->alpha = alpha;
|
||||
|
||||
_cairo_color_compute_xc_color (color);
|
||||
}
|
||||
171
src/cairo-font.c
Normal file
171
src/cairo-font.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
void
|
||||
_cairo_font_init (cairo_font_t *font)
|
||||
{
|
||||
font->key = (unsigned char *) strdup (CAIRO_FONT_KEY_DEFAULT);
|
||||
|
||||
font->dpy = NULL;
|
||||
font->xft_font = NULL;
|
||||
|
||||
cairo_matrix_set_identity (&font->matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other)
|
||||
{
|
||||
*font = *other;
|
||||
|
||||
if (other->key) {
|
||||
font->key = (unsigned char *) strdup ((char *) other->key);
|
||||
if (font->key == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (other->xft_font) {
|
||||
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
|
||||
if (font->xft_font == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_font_fini (cairo_font_t *font)
|
||||
{
|
||||
if (font->key)
|
||||
free (font->key);
|
||||
font->key = NULL;
|
||||
|
||||
_cairo_matrix_fini (&font->matrix);
|
||||
|
||||
if (font->xft_font)
|
||||
XftFontClose (font->dpy, font->xft_font);
|
||||
font->xft_font = NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_select (cairo_font_t *font, const char *key)
|
||||
{
|
||||
if (font->xft_font)
|
||||
XftFontClose (font->dpy, font->xft_font);
|
||||
font->xft_font = NULL;
|
||||
|
||||
if (font->key)
|
||||
free (font->key);
|
||||
|
||||
font->key = (unsigned char *) strdup ((char *) key);
|
||||
if (font->key == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_scale (cairo_font_t *font, double scale)
|
||||
{
|
||||
cairo_matrix_scale (&font->matrix, scale, scale);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_font_transform (cairo_font_t *font,
|
||||
double a, double b,
|
||||
double c, double d)
|
||||
{
|
||||
cairo_matrix_t m;
|
||||
|
||||
cairo_matrix_set_affine (&m, a, b, c, d, 0, 0);
|
||||
cairo_matrix_multiply (&font->matrix, &m, &font->matrix);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font)
|
||||
{
|
||||
FcPattern *pattern;
|
||||
FcPattern *match;
|
||||
FcResult result;
|
||||
cairo_matrix_t matrix;
|
||||
FcMatrix fc_matrix;
|
||||
double expansion;
|
||||
double font_size;
|
||||
|
||||
if (font->xft_font) {
|
||||
*xft_font = font->xft_font;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
pattern = FcNameParse (font->key);
|
||||
|
||||
matrix = gstate->ctm;
|
||||
|
||||
cairo_matrix_multiply (&matrix, &font->matrix, &matrix);
|
||||
|
||||
/* Pull the scale factor out of the final matrix and use it to set
|
||||
the direct pixelsize of the font. This enables freetype to
|
||||
perform proper hinting at any size. */
|
||||
|
||||
/* XXX: The determinant gives an area expansion factor, so the
|
||||
math below should be correct for the (common) case of uniform
|
||||
X/Y scaling. Is there anything different we would want to do
|
||||
for non-uniform X/Y scaling? */
|
||||
_cairo_matrix_compute_determinant (&matrix, &expansion);
|
||||
font_size = sqrt (expansion);
|
||||
FcPatternAddDouble (pattern, "pixelsize", font_size);
|
||||
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
|
||||
|
||||
fc_matrix.xx = matrix.m[0][0];
|
||||
fc_matrix.xy = matrix.m[0][1];
|
||||
fc_matrix.yx = matrix.m[1][0];
|
||||
fc_matrix.yy = matrix.m[1][1];
|
||||
|
||||
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
|
||||
|
||||
/* XXX: Need to abandon Xft and use Xc instead */
|
||||
/* When I do that I can throw away these Display pointers */
|
||||
font->dpy = gstate->surface->dpy;
|
||||
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
|
||||
if (!match)
|
||||
return 0;
|
||||
|
||||
font->xft_font = XftFontOpenPattern (font->dpy, match);
|
||||
|
||||
*xft_font = font->xft_font;
|
||||
|
||||
FcPatternDestroy (pattern);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
1123
src/cairo-gstate.c
Normal file
1123
src/cairo-gstate.c
Normal file
File diff suppressed because it is too large
Load diff
380
src/cairo-matrix.c
Normal file
380
src/cairo-matrix.c
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_matrix_t CAIRO_MATRIX_IDENTITY = {
|
||||
{
|
||||
{1, 0},
|
||||
{0, 1},
|
||||
{0, 0}
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
|
||||
|
||||
static void
|
||||
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
|
||||
|
||||
cairo_matrix_t *
|
||||
cairo_matrix_create (void)
|
||||
{
|
||||
cairo_matrix_t *matrix;
|
||||
|
||||
matrix = malloc (sizeof (cairo_matrix_t));
|
||||
if (matrix == NULL)
|
||||
return NULL;
|
||||
|
||||
_cairo_matrix_init (matrix);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_matrix_init (cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_set_identity (matrix);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_matrix_fini (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
void
|
||||
cairo_matrix_destroy (cairo_matrix_t *matrix)
|
||||
{
|
||||
_cairo_matrix_fini (matrix);
|
||||
free (matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
|
||||
{
|
||||
*matrix = *other;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_set_identity (cairo_matrix_t *matrix)
|
||||
{
|
||||
*matrix = CAIRO_MATRIX_IDENTITY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_set_affine (cairo_matrix_t *matrix,
|
||||
double a, double b,
|
||||
double c, double d,
|
||||
double tx, double ty)
|
||||
{
|
||||
matrix->m[0][0] = a; matrix->m[0][1] = b;
|
||||
matrix->m[1][0] = c; matrix->m[1][1] = d;
|
||||
matrix->m[2][0] = tx; matrix->m[2][1] = ty;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_get_affine (cairo_matrix_t *matrix,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty)
|
||||
{
|
||||
*a = matrix->m[0][0]; *b = matrix->m[0][1];
|
||||
*c = matrix->m[1][0]; *d = matrix->m[1][1];
|
||||
*tx = matrix->m[2][0]; *ty = matrix->m[2][1];
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
|
||||
double tx, double ty)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
1, 0,
|
||||
0, 1,
|
||||
tx, ty);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_translate (&tmp, tx, ty);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
|
||||
double sx, double sy)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
sx, 0,
|
||||
0, sy,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_scale (&tmp, sx, sy);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
|
||||
double radians)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
cos (radians), sin (radians),
|
||||
-sin (radians), cos (radians),
|
||||
0, 0);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_rotate (&tmp, radians);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
|
||||
{
|
||||
cairo_matrix_t r;
|
||||
int row, col, n;
|
||||
double t;
|
||||
|
||||
for (row = 0; row < 3; row++) {
|
||||
for (col = 0; col < 2; col++) {
|
||||
if (row == 2)
|
||||
t = b->m[2][col];
|
||||
else
|
||||
t = 0;
|
||||
for (n = 0; n < 2; n++) {
|
||||
t += a->m[row][n] * b->m[n][col];
|
||||
}
|
||||
r.m[row][col] = t;
|
||||
}
|
||||
}
|
||||
|
||||
*result = r;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
|
||||
{
|
||||
double new_x, new_y;
|
||||
|
||||
new_x = (matrix->m[0][0] * *dx
|
||||
+ matrix->m[1][0] * *dy);
|
||||
new_y = (matrix->m[0][1] * *dx
|
||||
+ matrix->m[1][1] * *dy);
|
||||
|
||||
*dx = new_x;
|
||||
*dy = new_y;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
|
||||
{
|
||||
cairo_matrix_transform_distance (matrix, x, y);
|
||||
|
||||
*x += matrix->m[2][0];
|
||||
*y += matrix->m[2][1];
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
|
||||
double *x, double *y,
|
||||
double *width, double *height)
|
||||
{
|
||||
int i;
|
||||
double quad_x[4], quad_y[4];
|
||||
double dx1, dy1;
|
||||
double dx2, dy2;
|
||||
double min_x, max_x;
|
||||
double min_y, max_y;
|
||||
|
||||
quad_x[0] = *x;
|
||||
quad_y[0] = *y;
|
||||
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
|
||||
|
||||
dx1 = *width;
|
||||
dy1 = 0;
|
||||
cairo_matrix_transform_distance (matrix, &dx1, &dy1);
|
||||
quad_x[1] = quad_x[0] + dx1;
|
||||
quad_y[1] = quad_y[0] + dy1;
|
||||
|
||||
dx2 = 0;
|
||||
dy2 = *height;
|
||||
cairo_matrix_transform_distance (matrix, &dx2, &dy2);
|
||||
quad_x[2] = quad_x[0] + dx2;
|
||||
quad_y[2] = quad_y[0] + dy2;
|
||||
|
||||
quad_x[3] = quad_x[0] + dx1 + dx2;
|
||||
quad_y[3] = quad_y[0] + dy1 + dy2;
|
||||
|
||||
min_x = max_x = quad_x[0];
|
||||
min_y = max_y = quad_y[0];
|
||||
|
||||
for (i=1; i < 4; i++) {
|
||||
if (quad_x[i] < min_x)
|
||||
min_x = quad_x[i];
|
||||
if (quad_x[i] > max_x)
|
||||
max_x = quad_x[i];
|
||||
|
||||
if (quad_y[i] < min_y)
|
||||
min_y = quad_y[i];
|
||||
if (quad_y[i] > max_y)
|
||||
max_y = quad_y[i];
|
||||
}
|
||||
|
||||
*x = min_x;
|
||||
*y = min_y;
|
||||
*width = max_x - min_x;
|
||||
*height = max_y - min_y;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
|
||||
{
|
||||
int row, col;
|
||||
|
||||
for (row = 0; row < 3; row++)
|
||||
for (col = 0; col < 2; col++)
|
||||
matrix->m[row][col] *= scalar;
|
||||
}
|
||||
|
||||
/* This function isn't a correct adjoint in that the implicit 1 in the
|
||||
homogeneous result should actually be ad-bc instead. But, since this
|
||||
adjoint is only used in the computation of the inverse, which
|
||||
divides by det (A)=ad-bc anyway, everything works out in the end. */
|
||||
static void
|
||||
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* adj (A) = transpose (C:cofactor (A,i,j)) */
|
||||
double a, b, c, d, tx, ty;
|
||||
|
||||
a = matrix->m[0][0]; b = matrix->m[0][1];
|
||||
c = matrix->m[1][0]; d = matrix->m[1][1];
|
||||
tx = matrix->m[2][0]; ty = matrix->m[2][1];
|
||||
|
||||
cairo_matrix_set_affine (matrix,
|
||||
d, -b,
|
||||
-c, a,
|
||||
c*ty - d*tx, b*tx - a*ty);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_invert (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* inv (A) = 1/det (A) * adj (A) */
|
||||
double det;
|
||||
|
||||
_cairo_matrix_compute_determinant (matrix, &det);
|
||||
|
||||
if (det == 0)
|
||||
return CAIRO_STATUS_INVALID_MATRIX;
|
||||
|
||||
_cairo_matrix_compute_adjoint (matrix);
|
||||
_cairo_matrix_scalar_multiply (matrix, 1 / det);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
|
||||
{
|
||||
double a, b, c, d;
|
||||
|
||||
a = matrix->m[0][0]; b = matrix->m[0][1];
|
||||
c = matrix->m[1][0]; d = matrix->m[1][1];
|
||||
|
||||
*det = a*d - b*c;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
|
||||
{
|
||||
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
|
||||
|
||||
det (M - lI) = 0
|
||||
|
||||
The zeros in our homogeneous 3x3 matrix make this equation equal
|
||||
to that formed by the sub-matrix:
|
||||
|
||||
M = a b
|
||||
c d
|
||||
|
||||
by which:
|
||||
|
||||
l^2 - (a+d)l + (ad - bc) = 0
|
||||
|
||||
l = (a+d +/- sqrt (a^2 + 2ad + d^2 - 4 (ad-bc))) / 2;
|
||||
*/
|
||||
|
||||
double a, b, c, d, rad;
|
||||
|
||||
a = matrix->m[0][0];
|
||||
b = matrix->m[0][1];
|
||||
c = matrix->m[1][0];
|
||||
d = matrix->m[1][1];
|
||||
|
||||
rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
|
||||
*lambda1 = (a + d + rad) / 2.0;
|
||||
*lambda2 = (a + d - rad) / 2.0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
168
src/cairo-path-bounds.c
Normal file
168
src/cairo-path-bounds.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright © 2003 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct _cairo_path_bounder {
|
||||
int has_pt;
|
||||
|
||||
XFixed min_x;
|
||||
XFixed min_y;
|
||||
XFixed max_x;
|
||||
XFixed max_y;
|
||||
} cairo_path_bounder;
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_init (cairo_path_bounder *bounder);
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_fini (cairo_path_bounder *bounder);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_spline (void *closure,
|
||||
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done done);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_path (void *closure);
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_init (cairo_path_bounder *bounder)
|
||||
{
|
||||
bounder->has_pt = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_fini (cairo_path_bounder *bounder)
|
||||
{
|
||||
bounder->has_pt = 0;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt)
|
||||
{
|
||||
if (bounder->has_pt) {
|
||||
if (pt->x < bounder->min_x)
|
||||
bounder->min_x = pt->x;
|
||||
|
||||
if (pt->y < bounder->min_y)
|
||||
bounder->min_y = pt->y;
|
||||
|
||||
if (pt->x > bounder->max_x)
|
||||
bounder->max_x = pt->x;
|
||||
|
||||
if (pt->y > bounder->max_y)
|
||||
bounder->max_y = pt->y;
|
||||
} else {
|
||||
bounder->min_x = pt->x;
|
||||
bounder->min_y = pt->y;
|
||||
bounder->max_x = pt->x;
|
||||
bounder->max_y = pt->y;
|
||||
|
||||
bounder->has_pt = 1;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_path_bounder *bounder = closure;
|
||||
|
||||
_cairo_path_bounder_add_point (bounder, p1);
|
||||
_cairo_path_bounder_add_point (bounder, p2);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_spline (void *closure,
|
||||
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
cairo_path_bounder *bounder = closure;
|
||||
|
||||
_cairo_path_bounder_add_point (bounder, a);
|
||||
_cairo_path_bounder_add_point (bounder, b);
|
||||
_cairo_path_bounder_add_point (bounder, c);
|
||||
_cairo_path_bounder_add_point (bounder, d);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done done)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_path (void *closure)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
|
||||
cairo_status_t
|
||||
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
static cairo_path_callbacks_t cb = {
|
||||
_cairo_path_bounder_add_edge,
|
||||
_cairo_path_bounder_add_spline,
|
||||
_cairo_path_bounder_done_sub_path,
|
||||
_cairo_path_bounder_done_path
|
||||
};
|
||||
|
||||
cairo_path_bounder bounder;
|
||||
|
||||
_cairo_path_bounder_init (&bounder);
|
||||
|
||||
status = _cairo_path_interpret (path, cairo_path_direction_forward, &cb, &bounder);
|
||||
if (status) {
|
||||
*x1 = *y1 = *x2 = *y2 = 0.0;
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
return status;
|
||||
}
|
||||
|
||||
*x1 = XFixedToDouble (bounder.min_x);
|
||||
*y1 = XFixedToDouble (bounder.min_y);
|
||||
*x2 = XFixedToDouble (bounder.max_x);
|
||||
*y2 = XFixedToDouble (bounder.max_y);
|
||||
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
158
src/cairo-path-fill.c
Normal file
158
src/cairo-path-fill.c
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct _cairo_filler {
|
||||
cairo_gstate_t *gstate;
|
||||
cairo_traps_t *traps;
|
||||
|
||||
cairo_polygon_t polygon;
|
||||
} cairo_filler;
|
||||
|
||||
static void
|
||||
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
|
||||
|
||||
static void
|
||||
_cairo_filler_fini (cairo_filler *filler);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_path (void *closure);
|
||||
|
||||
static void
|
||||
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
filler->gstate = gstate;
|
||||
filler->traps = traps;
|
||||
|
||||
_cairo_polygon_init (&filler->polygon);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_filler_fini (cairo_filler *filler)
|
||||
{
|
||||
_cairo_polygon_fini (&filler->polygon);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_filler *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
|
||||
return _cairo_polygon_add_edge (polygon, p1, p2);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
int i;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_filler *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
cairo_gstate_t *gstate = filler->gstate;
|
||||
cairo_spline_t spline;
|
||||
|
||||
status = _cairo_spline_init (&spline, a, b, c, d);
|
||||
if (status == cairo_int_status_degenerate)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_cairo_spline_decompose (&spline, gstate->tolerance);
|
||||
if (status)
|
||||
goto CLEANUP_SPLINE;
|
||||
|
||||
for (i = 0; i < spline.num_pts - 1; i++) {
|
||||
status = _cairo_polygon_add_edge (polygon, &spline.pts[i], &spline.pts[i+1]);
|
||||
if (status)
|
||||
goto CLEANUP_SPLINE;
|
||||
}
|
||||
|
||||
CLEANUP_SPLINE:
|
||||
_cairo_spline_fini (&spline);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_filler *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
|
||||
_cairo_polygon_close (polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_path (void *closure)
|
||||
{
|
||||
cairo_filler *filler = closure;
|
||||
|
||||
return cairo_traps_tessellate_polygon (filler->traps,
|
||||
&filler->polygon,
|
||||
filler->gstate->fill_rule);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
static const cairo_path_callbacks_t filler_callbacks = {
|
||||
_cairo_filler_add_edge,
|
||||
_cairo_filler_add_spline,
|
||||
_cairo_filler_done_sub_path,
|
||||
_cairo_filler_done_path
|
||||
};
|
||||
|
||||
cairo_status_t status;
|
||||
cairo_filler filler;
|
||||
|
||||
_cairo_filler_init (&filler, gstate, traps);
|
||||
|
||||
status = _cairo_path_interpret (path,
|
||||
cairo_path_direction_forward,
|
||||
&filler_callbacks, &filler);
|
||||
if (status) {
|
||||
_cairo_filler_fini (&filler);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_filler_fini (&filler);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
715
src/cairo-path-stroke.c
Normal file
715
src/cairo-path-stroke.c
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct _cairo_stroker {
|
||||
cairo_gstate_t *gstate;
|
||||
cairo_traps_t *traps;
|
||||
|
||||
int have_prev;
|
||||
int have_first;
|
||||
int is_first;
|
||||
cairo_stroke_face_t prev;
|
||||
cairo_stroke_face_t first;
|
||||
int dash_index;
|
||||
int dash_on;
|
||||
double dash_remain;
|
||||
} cairo_stroker;
|
||||
|
||||
/* private functions */
|
||||
static void
|
||||
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps);
|
||||
|
||||
static void
|
||||
_cairo_stroker_fini (cairo_stroker *stroker);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_path (void *closure);
|
||||
|
||||
static void
|
||||
_translate_point (XPointFixed *pt, XPointFixed *offset);
|
||||
|
||||
static int
|
||||
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
|
||||
|
||||
static void
|
||||
_cairo_stroker_start_dash (cairo_stroker *stroker)
|
||||
{
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
double offset;
|
||||
int on = 1;
|
||||
int i = 0;
|
||||
|
||||
offset = gstate->dash_offset;
|
||||
while (offset >= gstate->dash[i]) {
|
||||
offset -= gstate->dash[i];
|
||||
on = 1-on;
|
||||
if (++i == gstate->num_dashes)
|
||||
i = 0;
|
||||
}
|
||||
stroker->dash_index = i;
|
||||
stroker->dash_on = on;
|
||||
stroker->dash_remain = gstate->dash[i] - offset;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_stroker_step_dash (cairo_stroker *stroker, double step)
|
||||
{
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
stroker->dash_remain -= step;
|
||||
if (stroker->dash_remain <= 0) {
|
||||
stroker->dash_index++;
|
||||
if (stroker->dash_index == gstate->num_dashes)
|
||||
stroker->dash_index = 0;
|
||||
stroker->dash_on = 1-stroker->dash_on;
|
||||
stroker->dash_remain = gstate->dash[stroker->dash_index];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
stroker->gstate = gstate;
|
||||
stroker->traps = traps;
|
||||
stroker->have_prev = 0;
|
||||
stroker->have_first = 0;
|
||||
stroker->is_first = 1;
|
||||
if (gstate->dash)
|
||||
_cairo_stroker_start_dash (stroker);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_stroker_fini (cairo_stroker *stroker)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
static void
|
||||
_translate_point (XPointFixed *pt, XPointFixed *offset)
|
||||
{
|
||||
pt->x += offset->x;
|
||||
pt->y += offset->y;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
|
||||
{
|
||||
XPointDouble d_in, d_out;
|
||||
|
||||
d_in.x = XFixedToDouble (in->cw.x - in->pt.x);
|
||||
d_in.y = XFixedToDouble (in->cw.y - in->pt.y);
|
||||
d_out.x = XFixedToDouble (out->cw.x - out->pt.x);
|
||||
d_out.y = XFixedToDouble (out->cw.y - out->pt.y);
|
||||
|
||||
return d_out.y * d_in.x > d_in.y * d_out.x;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
int clockwise = _cairo_stroker_face_clockwise (out, in);
|
||||
XPointFixed *inpt, *outpt;
|
||||
|
||||
if (in->cw.x == out->cw.x
|
||||
&& in->cw.y == out->cw.y
|
||||
&& in->ccw.x == out->ccw.x
|
||||
&& in->ccw.y == out->ccw.y) {
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (clockwise) {
|
||||
inpt = &in->ccw;
|
||||
outpt = &out->ccw;
|
||||
} else {
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
}
|
||||
|
||||
switch (gstate->line_join) {
|
||||
case CAIRO_LINE_JOIN_ROUND: {
|
||||
int i;
|
||||
int start, step, stop;
|
||||
XPointFixed tri[3], initial, final;
|
||||
cairo_pen_t *pen = &gstate->pen_regular;
|
||||
|
||||
tri[0] = in->pt;
|
||||
if (clockwise) {
|
||||
initial = in->ccw;
|
||||
_cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
|
||||
step = -1;
|
||||
_cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
|
||||
final = out->ccw;
|
||||
} else {
|
||||
initial = in->cw;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
|
||||
step = +1;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
|
||||
final = out->cw;
|
||||
}
|
||||
|
||||
i = start;
|
||||
tri[1] = initial;
|
||||
while (i != stop) {
|
||||
tri[2] = in->pt;
|
||||
_translate_point (&tri[2], &pen->vertex[i].pt);
|
||||
cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
i += step;
|
||||
if (i < 0)
|
||||
i = pen->num_vertices - 1;
|
||||
if (i >= pen->num_vertices)
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tri[2] = final;
|
||||
|
||||
return cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
}
|
||||
case CAIRO_LINE_JOIN_MITER:
|
||||
default: {
|
||||
cairo_polygon_t polygon;
|
||||
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
|
||||
XDouble ml = gstate->miter_limit;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
if (2 <= ml * ml * (1 - c)) {
|
||||
XDouble x1, y1, x2, y2;
|
||||
XDouble mx, my;
|
||||
XDouble dx1, dx2, dy1, dy2;
|
||||
XPointFixed outer;
|
||||
|
||||
x1 = XFixedToDouble (inpt->x);
|
||||
y1 = XFixedToDouble (inpt->y);
|
||||
dx1 = in->usr_vector.x;
|
||||
dy1 = in->usr_vector.y;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
|
||||
|
||||
x2 = XFixedToDouble (outpt->x);
|
||||
y2 = XFixedToDouble (outpt->y);
|
||||
dx2 = out->usr_vector.x;
|
||||
dy2 = out->usr_vector.y;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
|
||||
|
||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||
(dx1 * dy2 - dx2 * dy1));
|
||||
if (dy1)
|
||||
mx = (my - y1) * dx1 / dy1 + x1;
|
||||
else
|
||||
mx = (my - y2) * dx2 / dy2 + x2;
|
||||
|
||||
outer.x = XDoubleToFixed (mx);
|
||||
outer.y = XDoubleToFixed (my);
|
||||
_cairo_polygon_add_edge (&polygon, &in->pt, inpt);
|
||||
_cairo_polygon_add_edge (&polygon, inpt, &outer);
|
||||
_cairo_polygon_add_edge (&polygon, &outer, outpt);
|
||||
_cairo_polygon_add_edge (&polygon, outpt, &in->pt);
|
||||
status = cairo_traps_tessellate_polygon (stroker->traps,
|
||||
&polygon,
|
||||
CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
/* fall through ... */
|
||||
}
|
||||
case CAIRO_LINE_JOIN_BEVEL: {
|
||||
XPointFixed tri[3];
|
||||
tri[0] = in->pt;
|
||||
tri[1] = *inpt;
|
||||
tri[2] = *outpt;
|
||||
|
||||
return cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_cap (cairo_stroker *stroker, cairo_stroke_face_t *f)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
|
||||
if (gstate->line_cap == CAIRO_LINE_CAP_BUTT)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
switch (gstate->line_cap) {
|
||||
case CAIRO_LINE_CAP_ROUND: {
|
||||
int i;
|
||||
int start, stop;
|
||||
cairo_slope_fixed_t slope;
|
||||
XPointFixed tri[3];
|
||||
cairo_pen_t *pen = &gstate->pen_regular;
|
||||
|
||||
slope = f->dev_vector;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
|
||||
slope.dx = -slope.dx;
|
||||
slope.dy = -slope.dy;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
|
||||
|
||||
tri[0] = f->pt;
|
||||
tri[1] = f->cw;
|
||||
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
|
||||
tri[2] = f->pt;
|
||||
_translate_point (&tri[2], &pen->vertex[i].pt);
|
||||
cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
}
|
||||
tri[2] = f->ccw;
|
||||
|
||||
return cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
}
|
||||
case CAIRO_LINE_CAP_SQUARE: {
|
||||
double dx, dy;
|
||||
cairo_slope_fixed_t fvector;
|
||||
XPointFixed occw, ocw;
|
||||
cairo_polygon_t polygon;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
dx = f->usr_vector.x;
|
||||
dy = f->usr_vector.y;
|
||||
dx *= gstate->line_width / 2.0;
|
||||
dy *= gstate->line_width / 2.0;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
fvector.dx = XDoubleToFixed (dx);
|
||||
fvector.dy = XDoubleToFixed (dy);
|
||||
occw.x = f->ccw.x + fvector.dx;
|
||||
occw.y = f->ccw.y + fvector.dy;
|
||||
ocw.x = f->cw.x + fvector.dx;
|
||||
ocw.y = f->cw.y + fvector.dy;
|
||||
|
||||
_cairo_polygon_add_edge (&polygon, &f->cw, &ocw);
|
||||
_cairo_polygon_add_edge (&polygon, &ocw, &occw);
|
||||
_cairo_polygon_add_edge (&polygon, &occw, &f->ccw);
|
||||
_cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw);
|
||||
|
||||
status = cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
case CAIRO_LINE_CAP_BUTT:
|
||||
default:
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_compute_face (XPointFixed *pt, cairo_slope_fixed_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
|
||||
{
|
||||
double mag, tmp;
|
||||
double dx, dy;
|
||||
XPointDouble usr_vector;
|
||||
XPointFixed offset_ccw, offset_cw;
|
||||
|
||||
dx = XFixedToDouble (slope->dx);
|
||||
dy = XFixedToDouble (slope->dy);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
|
||||
|
||||
mag = sqrt (dx * dx + dy * dy);
|
||||
if (mag == 0) {
|
||||
/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
|
||||
return;
|
||||
}
|
||||
|
||||
dx /= mag;
|
||||
dy /= mag;
|
||||
|
||||
usr_vector.x = dx;
|
||||
usr_vector.y = dy;
|
||||
|
||||
tmp = dx;
|
||||
dx = - dy * (gstate->line_width / 2.0);
|
||||
dy = tmp * (gstate->line_width / 2.0);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
|
||||
offset_ccw.x = XDoubleToFixed (dx);
|
||||
offset_ccw.y = XDoubleToFixed (dy);
|
||||
offset_cw.x = -offset_ccw.x;
|
||||
offset_cw.y = -offset_ccw.y;
|
||||
|
||||
face->ccw = *pt;
|
||||
_translate_point (&face->ccw, &offset_ccw);
|
||||
|
||||
face->pt = *pt;
|
||||
|
||||
face->cw = *pt;
|
||||
_translate_point (&face->cw, &offset_cw);
|
||||
|
||||
face->usr_vector.x = usr_vector.x;
|
||||
face->usr_vector.y = usr_vector.y;
|
||||
|
||||
face->dev_vector = *slope;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_sub_edge (cairo_stroker *stroker, XPointFixed *p1, XPointFixed *p2,
|
||||
cairo_stroke_face_t *start, cairo_stroke_face_t *end)
|
||||
{
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
XPointFixed quad[4];
|
||||
cairo_slope_fixed_t slope;
|
||||
|
||||
if (p1->x == p2->x && p1->y == p2->y) {
|
||||
/* XXX: Need to rethink how this case should be handled, (both
|
||||
here and in _compute_face). The key behavior is that
|
||||
degenerate paths should draw as much as possible. */
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_compute_slope (p1, p2, &slope);
|
||||
_compute_face (p1, &slope, gstate, start);
|
||||
|
||||
/* XXX: This could be optimized slightly by not calling
|
||||
_compute_face again but rather translating the relevant
|
||||
fields from start. */
|
||||
_compute_face (p2, &slope, gstate, end);
|
||||
|
||||
quad[0] = start->cw;
|
||||
quad[1] = start->ccw;
|
||||
quad[2] = end->ccw;
|
||||
quad[3] = end->cw;
|
||||
|
||||
return cairo_traps_tessellate_rectangle (stroker->traps, quad);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_stroker *stroker = closure;
|
||||
cairo_stroke_face_t start, end;
|
||||
|
||||
if (p1->x == p2->x && p1->y == p2->y) {
|
||||
/* XXX: Need to rethink how this case should be handled, (both
|
||||
here and in cairo_stroker_add_sub_edge and in _compute_face). The
|
||||
key behavior is that degenerate paths should draw as much
|
||||
as possible. */
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &start, &end);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
stroker->have_prev = 1;
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = start;
|
||||
}
|
||||
}
|
||||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dashed lines. Cap each dash end, join around turns when on
|
||||
*/
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_stroker *stroker = closure;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
double mag, remain, tmp;
|
||||
double dx, dy;
|
||||
double dx2, dy2;
|
||||
XPointFixed fd1, fd2;
|
||||
int first = 1;
|
||||
cairo_stroke_face_t sub_start, sub_end;
|
||||
|
||||
dx = XFixedToDouble (p2->x - p1->x);
|
||||
dy = XFixedToDouble (p2->y - p1->y);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
|
||||
|
||||
mag = sqrt (dx *dx + dy * dy);
|
||||
remain = mag;
|
||||
fd1 = *p1;
|
||||
while (remain) {
|
||||
tmp = stroker->dash_remain;
|
||||
if (tmp > remain)
|
||||
tmp = remain;
|
||||
remain -= tmp;
|
||||
dx2 = dx * (mag - remain)/mag;
|
||||
dy2 = dy * (mag - remain)/mag;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
|
||||
fd2.x = XDoubleToFixed (dx2);
|
||||
fd2.y = XDoubleToFixed (dy2);
|
||||
fd2.x += p1->x;
|
||||
fd2.y += p1->y;
|
||||
/*
|
||||
* XXX simplify this case analysis
|
||||
*/
|
||||
if (stroker->dash_on) {
|
||||
status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &sub_start, &sub_end);
|
||||
if (status)
|
||||
return status;
|
||||
if (!first) {
|
||||
/*
|
||||
* Not first dash in this segment, cap start
|
||||
*/
|
||||
status = _cairo_stroker_cap (stroker, &sub_start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
/*
|
||||
* First in this segment, join to any prev, else
|
||||
* if at start of sub-path, mark position, else
|
||||
* cap
|
||||
*/
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = sub_start;
|
||||
} else {
|
||||
status = _cairo_stroker_cap (stroker, &sub_start);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remain) {
|
||||
/*
|
||||
* Cap if not at end of segment
|
||||
*/
|
||||
status = _cairo_stroker_cap (stroker, &sub_end);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
/*
|
||||
* Mark previous line face and fix up next time
|
||||
* through
|
||||
*/
|
||||
stroker->prev = sub_end;
|
||||
stroker->have_prev = 1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If starting with off dash, check previous face
|
||||
* and cap if necessary
|
||||
*/
|
||||
if (first) {
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_cap (stroker, &stroker->prev);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (!remain)
|
||||
stroker->have_prev = 0;
|
||||
}
|
||||
_cairo_stroker_step_dash (stroker, tmp);
|
||||
fd1 = fd2;
|
||||
first = 0;
|
||||
}
|
||||
stroker->is_first = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_stroker *stroker = closure;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
cairo_spline_t spline;
|
||||
cairo_pen_t pen;
|
||||
cairo_stroke_face_t start, end;
|
||||
XPointFixed extra_points[4];
|
||||
|
||||
status = _cairo_spline_init (&spline, a, b, c, d);
|
||||
if (status == cairo_int_status_degenerate)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
status = _cairo_pen_init_copy (&pen, &gstate->pen_regular);
|
||||
if (status)
|
||||
goto CLEANUP_SPLINE;
|
||||
|
||||
_compute_face (a, &spline.initial_slope, gstate, &start);
|
||||
_compute_face (d, &spline.final_slope, gstate, &end);
|
||||
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
stroker->have_prev = 1;
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = start;
|
||||
}
|
||||
}
|
||||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
extra_points[0] = start.cw;
|
||||
extra_points[0].x -= start.pt.x;
|
||||
extra_points[0].y -= start.pt.y;
|
||||
extra_points[1] = start.ccw;
|
||||
extra_points[1].x -= start.pt.x;
|
||||
extra_points[1].y -= start.pt.y;
|
||||
extra_points[2] = end.cw;
|
||||
extra_points[2].x -= end.pt.x;
|
||||
extra_points[2].y -= end.pt.y;
|
||||
extra_points[3] = end.ccw;
|
||||
extra_points[3].x -= end.pt.x;
|
||||
extra_points[3].y -= end.pt.y;
|
||||
|
||||
status = _cairo_pen_add_points (&pen, extra_points, 4);
|
||||
if (status)
|
||||
goto CLEANUP_PEN;
|
||||
|
||||
status = _cairo_pen_stroke_spline (&pen, &spline, gstate->tolerance, stroker->traps);
|
||||
if (status)
|
||||
goto CLEANUP_PEN;
|
||||
|
||||
CLEANUP_PEN:
|
||||
_cairo_pen_fini (&pen);
|
||||
CLEANUP_SPLINE:
|
||||
_cairo_spline_fini (&spline);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_stroker *stroker = closure;
|
||||
|
||||
switch (done) {
|
||||
case cairo_sub_path_done_join:
|
||||
if (stroker->have_first && stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first);
|
||||
if (status)
|
||||
return status;
|
||||
break;
|
||||
}
|
||||
/* fall through... */
|
||||
case cairo_sub_path_done_cap:
|
||||
if (stroker->have_first) {
|
||||
XPointFixed t;
|
||||
/* The initial cap needs an outward facing vector. Reverse everything */
|
||||
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
|
||||
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
|
||||
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
|
||||
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
|
||||
t = stroker->first.cw;
|
||||
stroker->first.cw = stroker->first.ccw;
|
||||
stroker->first.ccw = t;
|
||||
status = _cairo_stroker_cap (stroker, &stroker->first);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_cap (stroker, &stroker->prev);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stroker->have_prev = 0;
|
||||
stroker->have_first = 0;
|
||||
stroker->is_first = 1;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_path (void *closure)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
static const cairo_path_callbacks_t stroker_solid_cb = {
|
||||
_cairo_stroker_add_edge,
|
||||
_cairo_stroker_add_spline,
|
||||
_cairo_stroker_done_sub_path,
|
||||
_cairo_stroker_done_path
|
||||
};
|
||||
static const cairo_path_callbacks_t stroker_dashed_cb = {
|
||||
_cairo_stroker_add_edge_dashed,
|
||||
_cairo_stroker_add_spline,
|
||||
_cairo_stroker_done_sub_path,
|
||||
_cairo_stroker_done_path
|
||||
};
|
||||
const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
|
||||
|
||||
cairo_status_t status;
|
||||
cairo_stroker stroker;
|
||||
|
||||
_cairo_stroker_init (&stroker, gstate, traps);
|
||||
|
||||
status = _cairo_path_interpret (path,
|
||||
cairo_path_direction_forward,
|
||||
callbacks, &stroker);
|
||||
if (status) {
|
||||
_cairo_stroker_fini (&stroker);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_stroker_fini (&stroker);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
436
src/cairo-path.c
Normal file
436
src/cairo-path.c
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "cairoint.h"
|
||||
|
||||
/* private functions */
|
||||
static cairo_status_t
|
||||
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts);
|
||||
|
||||
static void
|
||||
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_op_buf (cairo_path_t *path);
|
||||
|
||||
static void
|
||||
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_arg_buf (cairo_path_t *path);
|
||||
|
||||
static cairo_path_op_buf_t *
|
||||
_cairo_path_op_buf_create (void);
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *buf);
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op);
|
||||
|
||||
static cairo_path_arg_buf_t *
|
||||
_cairo_path_arg_buf_create (void);
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *buf);
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts);
|
||||
|
||||
void
|
||||
_cairo_path_init (cairo_path_t *path)
|
||||
{
|
||||
path->op_head = NULL;
|
||||
path->op_tail = NULL;
|
||||
|
||||
path->arg_head = NULL;
|
||||
path->arg_tail = NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
|
||||
{
|
||||
cairo_path_op_buf_t *op, *other_op;
|
||||
cairo_path_arg_buf_t *arg, *other_arg;
|
||||
|
||||
_cairo_path_init (path);
|
||||
|
||||
for (other_op = other->op_head; other_op; other_op = other_op->next) {
|
||||
op = _cairo_path_op_buf_create ();
|
||||
if (op == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
*op = *other_op;
|
||||
_cairo_path_add_op_buf (path, op);
|
||||
}
|
||||
|
||||
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
|
||||
arg = _cairo_path_arg_buf_create ();
|
||||
if (arg == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
*arg = *other_arg;
|
||||
_cairo_path_add_arg_buf (path, arg);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_path_fini (cairo_path_t *path)
|
||||
{
|
||||
cairo_path_op_buf_t *op;
|
||||
cairo_path_arg_buf_t *arg;
|
||||
|
||||
while (path->op_head) {
|
||||
op = path->op_head;
|
||||
path->op_head = op->next;
|
||||
_cairo_path_op_buf_destroy (op);
|
||||
}
|
||||
path->op_tail = NULL;
|
||||
|
||||
while (path->arg_head) {
|
||||
arg = path->arg_head;
|
||||
path->arg_head = arg->next;
|
||||
_cairo_path_arg_buf_destroy (arg);
|
||||
}
|
||||
path->arg_tail = NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_move_to (cairo_path_t *path, double x, double y)
|
||||
{
|
||||
XPointFixed pt;
|
||||
|
||||
pt.x = XDoubleToFixed (x);
|
||||
pt.y = XDoubleToFixed (y);
|
||||
|
||||
return _cairo_path_add (path, cairo_path_op_move_to, &pt, 1);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_line_to (cairo_path_t *path, double x, double y)
|
||||
{
|
||||
XPointFixed pt;
|
||||
|
||||
pt.x = XDoubleToFixed (x);
|
||||
pt.y = XDoubleToFixed (y);
|
||||
|
||||
return _cairo_path_add (path, cairo_path_op_line_to, &pt, 1);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_curve_to (cairo_path_t *path,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
XPointFixed pt[3];
|
||||
|
||||
pt[0].x = XDoubleToFixed (x1);
|
||||
pt[0].y = XDoubleToFixed (y1);
|
||||
|
||||
pt[1].x = XDoubleToFixed (x2);
|
||||
pt[1].y = XDoubleToFixed (y2);
|
||||
|
||||
pt[2].x = XDoubleToFixed (x3);
|
||||
pt[2].y = XDoubleToFixed (y3);
|
||||
|
||||
return _cairo_path_add (path, cairo_path_op_curve_to, pt, 3);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_close_path (cairo_path_t *path)
|
||||
{
|
||||
return _cairo_path_add (path, cairo_path_op_close_path, NULL, 0);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (path->op_tail == NULL || path->op_tail->num_ops + 1 > CAIRO_PATH_BUF_SZ) {
|
||||
status = _cairo_path_new_op_buf (path);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
_cairo_path_op_buf_add (path->op_tail, op);
|
||||
|
||||
if (path->arg_tail == NULL || path->arg_tail->num_pts + num_pts > CAIRO_PATH_BUF_SZ) {
|
||||
status = _cairo_path_new_arg_buf (path);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
_cairo_path_arg_buf_add (path->arg_tail, pts, num_pts);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op)
|
||||
{
|
||||
op->next = NULL;
|
||||
op->prev = path->op_tail;
|
||||
|
||||
if (path->op_tail) {
|
||||
path->op_tail->next = op;
|
||||
} else {
|
||||
path->op_head = op;
|
||||
}
|
||||
|
||||
path->op_tail = op;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_op_buf (cairo_path_t *path)
|
||||
{
|
||||
cairo_path_op_buf_t *op;
|
||||
|
||||
op = _cairo_path_op_buf_create ();
|
||||
if (op == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
_cairo_path_add_op_buf (path, op);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
|
||||
{
|
||||
arg->next = NULL;
|
||||
arg->prev = path->arg_tail;
|
||||
|
||||
if (path->arg_tail) {
|
||||
path->arg_tail->next = arg;
|
||||
} else {
|
||||
path->arg_head = arg;
|
||||
}
|
||||
|
||||
path->arg_tail = arg;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_arg_buf (cairo_path_t *path)
|
||||
{
|
||||
cairo_path_arg_buf_t *arg;
|
||||
|
||||
arg = _cairo_path_arg_buf_create ();
|
||||
|
||||
if (arg == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
_cairo_path_add_arg_buf (path, arg);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_path_op_buf_t *
|
||||
_cairo_path_op_buf_create (void)
|
||||
{
|
||||
cairo_path_op_buf_t *op;
|
||||
|
||||
op = malloc (sizeof (cairo_path_op_buf_t));
|
||||
|
||||
if (op) {
|
||||
op->num_ops = 0;
|
||||
op->next = NULL;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
|
||||
{
|
||||
free (op);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op)
|
||||
{
|
||||
op_buf->op[op_buf->num_ops++] = op;
|
||||
}
|
||||
|
||||
static cairo_path_arg_buf_t *
|
||||
_cairo_path_arg_buf_create (void)
|
||||
{
|
||||
cairo_path_arg_buf_t *arg;
|
||||
|
||||
arg = malloc (sizeof (cairo_path_arg_buf_t));
|
||||
|
||||
if (arg) {
|
||||
arg->num_pts = 0;
|
||||
arg->next = NULL;
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
|
||||
{
|
||||
free (arg);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_pts; i++) {
|
||||
arg->pt[arg->num_pts++] = pts[i];
|
||||
}
|
||||
}
|
||||
|
||||
#define CAIRO_PATH_OP_MAX_ARGS 3
|
||||
|
||||
static int num_args[] =
|
||||
{
|
||||
1, /* cairo_path_move_to */
|
||||
1, /* cairo_path_op_line_to */
|
||||
3, /* cairo_path_op_curve_to */
|
||||
0, /* cairo_path_op_close_path */
|
||||
};
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_interpret (cairo_path_t *path, cairo_path_direction dir, const cairo_path_callbacks_t *cb, void *closure)
|
||||
{
|
||||
cairo_status_t status;
|
||||
int i, arg;
|
||||
cairo_path_op_buf_t *op_buf;
|
||||
cairo_path_op op;
|
||||
cairo_path_arg_buf_t *arg_buf = path->arg_head;
|
||||
int buf_i = 0;
|
||||
XPointFixed pt[CAIRO_PATH_OP_MAX_ARGS];
|
||||
XPointFixed current = {0, 0};
|
||||
XPointFixed first = {0, 0};
|
||||
int has_current = 0;
|
||||
int has_edge = 0;
|
||||
int step = (dir == cairo_path_direction_forward) ? 1 : -1;
|
||||
|
||||
for (op_buf = (dir == cairo_path_direction_forward) ? path->op_head : path->op_tail;
|
||||
op_buf;
|
||||
op_buf = (dir == cairo_path_direction_forward) ? op_buf->next : op_buf->prev)
|
||||
{
|
||||
int start, stop;
|
||||
if (dir == cairo_path_direction_forward) {
|
||||
start = 0;
|
||||
stop = op_buf->num_ops;
|
||||
} else {
|
||||
start = op_buf->num_ops - 1;
|
||||
stop = -1;
|
||||
}
|
||||
|
||||
for (i=start; i != stop; i += step) {
|
||||
op = op_buf->op[i];
|
||||
|
||||
if (dir == cairo_path_direction_reverse) {
|
||||
if (buf_i == 0) {
|
||||
arg_buf = arg_buf->prev;
|
||||
buf_i = arg_buf->num_pts;
|
||||
}
|
||||
buf_i -= num_args[op];
|
||||
}
|
||||
|
||||
for (arg = 0; arg < num_args[op]; arg++) {
|
||||
pt[arg] = arg_buf->pt[buf_i];
|
||||
buf_i++;
|
||||
if (buf_i >= arg_buf->num_pts) {
|
||||
arg_buf = arg_buf->next;
|
||||
buf_i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == cairo_path_direction_reverse) {
|
||||
buf_i -= num_args[op];
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case cairo_path_op_move_to:
|
||||
if (has_edge) {
|
||||
status = (*cb->DoneSubPath) (closure, cairo_sub_path_done_cap);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
first = pt[0];
|
||||
current = pt[0];
|
||||
has_current = 1;
|
||||
has_edge = 0;
|
||||
break;
|
||||
case cairo_path_op_line_to:
|
||||
if (has_current) {
|
||||
status = (*cb->AddEdge) (closure, ¤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);
|
||||
}
|
||||
|
||||
|
||||
398
src/cairo-pen.c
Normal file
398
src/cairo-pen.c
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix);
|
||||
|
||||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen);
|
||||
|
||||
static int
|
||||
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
|
||||
|
||||
static int
|
||||
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
|
||||
|
||||
static int
|
||||
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_pen_stroke_direction_t dir, cairo_polygon_t *polygon);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_empty (cairo_pen_t *pen)
|
||||
{
|
||||
pen->radius = 0;
|
||||
pen->tolerance = 0;
|
||||
pen->vertex = NULL;
|
||||
pen->num_vertices = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
||||
{
|
||||
int i;
|
||||
cairo_pen_vertex *v;
|
||||
double dx, dy;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
/* XXX: It would be nice to notice that the pen is already properly constructed.
|
||||
However, this test would also have to account for possible changes in the transformation
|
||||
matrix.
|
||||
if (pen->radius == radius && pen->tolerance == tolerance)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
*/
|
||||
_cairo_pen_fini (pen);
|
||||
}
|
||||
|
||||
pen->radius = radius;
|
||||
pen->tolerance = gstate->tolerance;
|
||||
|
||||
pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, &gstate->ctm);
|
||||
/* number of vertices must be even */
|
||||
if (pen->num_vertices % 2)
|
||||
pen->num_vertices++;
|
||||
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
if (pen->vertex == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
v = &pen->vertex[i];
|
||||
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
|
||||
dx = radius * cos (v->theta);
|
||||
dy = radius * sin (v->theta);
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
v->pt.x = XDoubleToFixed (dx);
|
||||
v->pt.y = XDoubleToFixed (dy);
|
||||
/* Recompute theta in device space */
|
||||
v->theta = atan2 (v->pt.y, v->pt.x);
|
||||
if (v->theta < 0)
|
||||
v->theta += 2 * M_PI;
|
||||
}
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_pen_fini (cairo_pen_t *pen)
|
||||
{
|
||||
free (pen->vertex);
|
||||
_cairo_pen_init_empty (pen);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
||||
{
|
||||
*pen = *other;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
if (pen->vertex == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy (pen->vertex, other->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b)
|
||||
{
|
||||
double diff;
|
||||
const cairo_pen_vertex *va = a;
|
||||
const cairo_pen_vertex *vb = b;
|
||||
|
||||
diff = va->theta - vb->theta;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
else if (diff > 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_add_points (cairo_pen_t *pen, XPointFixed *pt, int num_pts)
|
||||
{
|
||||
int i, j;
|
||||
cairo_pen_vertex *v, *v_next, *new_vertex;
|
||||
|
||||
pen->num_vertices += num_pts;
|
||||
new_vertex = realloc (pen->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
if (new_vertex == NULL) {
|
||||
pen->num_vertices -= num_pts;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
pen->vertex = new_vertex;
|
||||
|
||||
/* initialize new vertices */
|
||||
for (i=0; i < num_pts; i++) {
|
||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||
v->pt = pt[i];
|
||||
v->theta = atan2 (v->pt.y, v->pt.x);
|
||||
if (v->theta < 0)
|
||||
v->theta += 2 * M_PI;
|
||||
}
|
||||
|
||||
qsort (pen->vertex, pen->num_vertices, sizeof (cairo_pen_vertex), _cairo_pen_vertex_compare_by_theta);
|
||||
|
||||
/* eliminate any duplicate vertices */
|
||||
for (i=0; i < pen->num_vertices - 1; i++ ) {
|
||||
v = &pen->vertex[i];
|
||||
v_next = &pen->vertex[i+1];
|
||||
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
|
||||
for (j=i+1; j < pen->num_vertices - 1; j++)
|
||||
pen->vertex[j] = pen->vertex[j+1];
|
||||
pen->num_vertices--;
|
||||
/* There may be more of the same duplicate, check again */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix)
|
||||
{
|
||||
double expansion, theta;
|
||||
|
||||
/* The determinant represents the area expansion factor of the
|
||||
transform. In the worst case, this is entirely in one
|
||||
dimension, which is what we assume here. */
|
||||
|
||||
_cairo_matrix_compute_determinant (matrix, &expansion);
|
||||
|
||||
if (tolerance > expansion*radius) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
theta = acos (1 - tolerance/(expansion * radius));
|
||||
return ceil (M_PI / theta);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen)
|
||||
{
|
||||
int i, i_prev;
|
||||
cairo_pen_vertex *prev, *v, *next;
|
||||
|
||||
for (i=0, i_prev = pen->num_vertices - 1;
|
||||
i < pen->num_vertices;
|
||||
i_prev = i++) {
|
||||
prev = &pen->vertex[i_prev];
|
||||
v = &pen->vertex[i];
|
||||
next = &pen->vertex[(i + 1) % pen->num_vertices];
|
||||
|
||||
_compute_slope (&prev->pt, &v->pt, &v->slope_cw);
|
||||
_compute_slope (&v->pt, &next->pt, &v->slope_ccw);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is a clockwise of b?
|
||||
*
|
||||
* NOTE: The strict equality here is not significant in and of itself,
|
||||
* but there are functions up above that are sensitive to it,
|
||||
* (cf. _cairo_pen_find_active_cw_vertex_index).
|
||||
*/
|
||||
static int
|
||||
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
|
||||
{
|
||||
double a_dx = XFixedToDouble (a->dx);
|
||||
double a_dy = XFixedToDouble (a->dy);
|
||||
double b_dx = XFixedToDouble (b->dx);
|
||||
double b_dy = XFixedToDouble (b->dy);
|
||||
|
||||
return b_dy * a_dx > a_dy * b_dx;
|
||||
}
|
||||
|
||||
static int
|
||||
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
|
||||
{
|
||||
return ! _slope_clockwise (a, b);
|
||||
}
|
||||
|
||||
/* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
* the inequality within _slope_clockwise/_slope_counter_clockwise.
|
||||
*
|
||||
* The issue is that the slope_ccw member of one pen vertex will be
|
||||
* equivalent to the slope_cw member of the next pen vertex in a
|
||||
* counterclockwise order. However, for this function, we care
|
||||
* strongly about which vertex is returned.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_fixed_t *slope,
|
||||
int *active)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (_slope_clockwise (slope, &pen->vertex[i].slope_ccw)
|
||||
&& _slope_counter_clockwise (slope, &pen->vertex[i].slope_cw))
|
||||
break;
|
||||
}
|
||||
|
||||
*active = i;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
* the inequality within _slope_clockwise/_slope_counter_clockwise.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_fixed_t *slope,
|
||||
int *active)
|
||||
{
|
||||
int i;
|
||||
cairo_slope_fixed_t slope_reverse;
|
||||
|
||||
slope_reverse = *slope;
|
||||
slope_reverse.dx = -slope_reverse.dx;
|
||||
slope_reverse.dy = -slope_reverse.dy;
|
||||
|
||||
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||
if (_slope_counter_clockwise (&pen->vertex[i].slope_ccw, &slope_reverse)
|
||||
&& _slope_clockwise (&pen->vertex[i].slope_cw, &slope_reverse))
|
||||
break;
|
||||
}
|
||||
|
||||
*active = i;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
cairo_pen_stroke_direction_t dir,
|
||||
cairo_polygon_t *polygon)
|
||||
{
|
||||
int i;
|
||||
cairo_status_t status;
|
||||
int start, stop, step;
|
||||
int active = 0;
|
||||
XPointFixed hull_pt;
|
||||
cairo_slope_fixed_t slope, initial_slope, final_slope;
|
||||
XPointFixed *pt = spline->pts;
|
||||
int num_pts = spline->num_pts;
|
||||
|
||||
if (dir == cairo_pen_stroke_direction_forward) {
|
||||
start = 0;
|
||||
stop = num_pts;
|
||||
step = 1;
|
||||
initial_slope = spline->initial_slope;
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_pts - 1;
|
||||
stop = -1;
|
||||
step = -1;
|
||||
initial_slope = spline->final_slope;
|
||||
initial_slope.dx = -initial_slope.dx;
|
||||
initial_slope.dy = -initial_slope.dy;
|
||||
final_slope = spline->initial_slope;
|
||||
final_slope.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);
|
||||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
||||
hull_pt.y = pt[i].y + pen->vertex[active].pt.y;
|
||||
status = _cairo_polygon_add_point (polygon, &hull_pt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (i + step == stop)
|
||||
slope = final_slope;
|
||||
else
|
||||
_compute_slope (&pt[i], &pt[i+step], &slope);
|
||||
if (_slope_counter_clockwise (&slope, &pen->vertex[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
} else if (_slope_clockwise (&slope, &pen->vertex[active].slope_cw)) {
|
||||
if (--active == -1)
|
||||
active = pen->num_vertices - 1;
|
||||
} else {
|
||||
i += step;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Compute outline of a given spline using the pen.
|
||||
The trapezoids needed to fill that outline will be added to traps
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_stroke_spline (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_polygon_t polygon;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
status = _cairo_spline_decompose (spline, tolerance);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_forward, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_reverse, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_polygon_close (&polygon);
|
||||
cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
175
src/cairo-polygon.c
Normal file
175
src/cairo-polygon.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "cairoint.h"
|
||||
|
||||
#define CAIRO_POLYGON_GROWTH_INC 10
|
||||
|
||||
/* private functions */
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
|
||||
|
||||
static void
|
||||
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt);
|
||||
|
||||
|
||||
void
|
||||
_cairo_polygon_init (cairo_polygon_t *polygon)
|
||||
{
|
||||
polygon->num_edges = 0;
|
||||
|
||||
polygon->edges_size = 0;
|
||||
polygon->edges = NULL;
|
||||
|
||||
polygon->first_pt_defined = 0;
|
||||
polygon->last_pt_defined = 0;
|
||||
|
||||
polygon->closed = 0;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_polygon_fini (cairo_polygon_t *polygon)
|
||||
{
|
||||
if (polygon->edges_size) {
|
||||
free (polygon->edges);
|
||||
polygon->edges = NULL;
|
||||
polygon->edges_size = 0;
|
||||
polygon->num_edges = 0;
|
||||
}
|
||||
|
||||
polygon->first_pt_defined = 0;
|
||||
polygon->last_pt_defined = 0;
|
||||
|
||||
polygon->closed = 0;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
|
||||
{
|
||||
cairo_edge_t *new_edges;
|
||||
int old_size = polygon->edges_size;
|
||||
int new_size = polygon->num_edges + additional;
|
||||
|
||||
if (new_size <= polygon->edges_size) {
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
polygon->edges_size = new_size;
|
||||
new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t));
|
||||
|
||||
if (new_edges == NULL) {
|
||||
polygon->edges_size = old_size;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
polygon->edges = new_edges;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt)
|
||||
{
|
||||
polygon->last_pt = *pt;
|
||||
polygon->last_pt_defined = 1;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_edge (cairo_polygon_t *polygon, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_edge_t *edge;
|
||||
|
||||
if (! polygon->first_pt_defined) {
|
||||
polygon->first_pt = *p1;
|
||||
polygon->first_pt_defined = 1;
|
||||
polygon->closed = 0;
|
||||
}
|
||||
|
||||
/* drop horizontal edges */
|
||||
if (p1->y == p2->y) {
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (polygon->num_edges >= polygon->edges_size) {
|
||||
status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
edge = &polygon->edges[polygon->num_edges];
|
||||
if (p1->y < p2->y) {
|
||||
edge->edge.p1 = *p1;
|
||||
edge->edge.p2 = *p2;
|
||||
edge->clockWise = True;
|
||||
} else {
|
||||
edge->edge.p1 = *p2;
|
||||
edge->edge.p2 = *p1;
|
||||
edge->clockWise = False;
|
||||
}
|
||||
|
||||
polygon->num_edges++;
|
||||
|
||||
DONE:
|
||||
_cairo_polygon_set_last_point (polygon, p2);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_point (cairo_polygon_t *polygon, XPointFixed *pt)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (polygon->last_pt_defined) {
|
||||
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, pt);
|
||||
} else {
|
||||
_cairo_polygon_set_last_point (polygon, pt);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_close (cairo_polygon_t *polygon)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (polygon->closed == 0 && polygon->last_pt_defined) {
|
||||
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, &polygon->first_pt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
polygon->closed = 1;
|
||||
polygon->first_pt_defined = 0;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
271
src/cairo-spline.c
Normal file
271
src/cairo-spline.c
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_grow_by (cairo_spline_t *spline, int additional);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt);
|
||||
|
||||
static void
|
||||
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result);
|
||||
|
||||
static void
|
||||
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2);
|
||||
|
||||
static double
|
||||
_cairo_spline_error_squared (cairo_spline_t *spline);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
|
||||
|
||||
#define CAIRO_SPLINE_GROWTH_INC 100
|
||||
|
||||
cairo_int_status
|
||||
_cairo_spline_init (cairo_spline_t *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
spline->a = *a;
|
||||
spline->b = *b;
|
||||
spline->c = *c;
|
||||
spline->d = *d;
|
||||
|
||||
if (a->x != b->x || a->y != b->y) {
|
||||
_compute_slope (&spline->a, &spline->b, &spline->initial_slope);
|
||||
} else if (a->x != c->x || a->y != c->y) {
|
||||
_compute_slope (&spline->a, &spline->c, &spline->initial_slope);
|
||||
} else if (a->x != d->x || a->y != d->y) {
|
||||
_compute_slope (&spline->a, &spline->d, &spline->initial_slope);
|
||||
} else {
|
||||
return cairo_int_status_degenerate;
|
||||
}
|
||||
|
||||
if (c->x != d->x || c->y != d->y) {
|
||||
_compute_slope (&spline->c, &spline->d, &spline->final_slope);
|
||||
} else if (b->x != d->x || b->y != d->y) {
|
||||
_compute_slope (&spline->b, &spline->d, &spline->final_slope);
|
||||
} else {
|
||||
_compute_slope (&spline->a, &spline->d, &spline->final_slope);
|
||||
}
|
||||
|
||||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
spline->pts = NULL;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_spline_fini (cairo_spline_t *spline)
|
||||
{
|
||||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
free (spline->pts);
|
||||
spline->pts = NULL;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
|
||||
{
|
||||
XPointFixed *new_pts;
|
||||
int old_size = spline->pts_size;
|
||||
int new_size = spline->num_pts + additional;
|
||||
|
||||
if (new_size <= spline->pts_size)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
spline->pts_size = new_size;
|
||||
new_pts = realloc (spline->pts, spline->pts_size * sizeof (XPointFixed));
|
||||
|
||||
if (new_pts == NULL) {
|
||||
spline->pts_size = old_size;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
spline->pts = new_pts;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (spline->num_pts >= spline->pts_size) {
|
||||
status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
spline->pts[spline->num_pts] = *pt;
|
||||
spline->num_pts++;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result)
|
||||
{
|
||||
result->x = a->x + ((b->x - a->x) >> 1);
|
||||
result->y = a->y + ((b->y - a->y) >> 1);
|
||||
}
|
||||
|
||||
static void
|
||||
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2)
|
||||
{
|
||||
XPointFixed ab, bc, cd;
|
||||
XPointFixed abbc, bccd;
|
||||
XPointFixed final;
|
||||
|
||||
_lerp_half (&spline->a, &spline->b, &ab);
|
||||
_lerp_half (&spline->b, &spline->c, &bc);
|
||||
_lerp_half (&spline->c, &spline->d, &cd);
|
||||
_lerp_half (&ab, &bc, &abbc);
|
||||
_lerp_half (&bc, &cd, &bccd);
|
||||
_lerp_half (&abbc, &bccd, &final);
|
||||
|
||||
s1->a = spline->a;
|
||||
s1->b = ab;
|
||||
s1->c = abbc;
|
||||
s1->d = final;
|
||||
|
||||
s2->a = final;
|
||||
s2->b = bccd;
|
||||
s2->c = cd;
|
||||
s2->d = spline->d;
|
||||
}
|
||||
|
||||
static double
|
||||
_PointDistanceSquaredToPoint (XPointFixed *a, XPointFixed *b)
|
||||
{
|
||||
double dx = XFixedToDouble (b->x - a->x);
|
||||
double dy = XFixedToDouble (b->y - a->y);
|
||||
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
static double
|
||||
_PointDistanceSquaredToSegment (XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
double u;
|
||||
double dx, dy;
|
||||
double pdx, pdy;
|
||||
XPointFixed px;
|
||||
|
||||
/* intersection point (px):
|
||||
|
||||
px = p1 + u(p2 - p1)
|
||||
(p - px) . (p2 - p1) = 0
|
||||
|
||||
Thus:
|
||||
|
||||
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
|
||||
*/
|
||||
|
||||
dx = XFixedToDouble (p2->x - p1->x);
|
||||
dy = XFixedToDouble (p2->y - p1->y);
|
||||
|
||||
if (dx == 0 && dy == 0)
|
||||
return _PointDistanceSquaredToPoint (p, p1);
|
||||
|
||||
pdx = XFixedToDouble (p->x - p1->x);
|
||||
pdy = XFixedToDouble (p->y - p1->y);
|
||||
|
||||
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
|
||||
|
||||
if (u <= 0)
|
||||
return _PointDistanceSquaredToPoint (p, p1);
|
||||
else if (u >= 1)
|
||||
return _PointDistanceSquaredToPoint (p, p2);
|
||||
|
||||
px.x = p1->x + u * (p2->x - p1->x);
|
||||
px.y = p1->y + u * (p2->y - p1->y);
|
||||
|
||||
return _PointDistanceSquaredToPoint (p, &px);
|
||||
}
|
||||
|
||||
/* Return an upper bound on the error (squared) that could result from approximating
|
||||
a spline as a line segment connecting the two endpoints */
|
||||
static double
|
||||
_cairo_spline_error_squared (cairo_spline_t *spline)
|
||||
{
|
||||
double berr, cerr;
|
||||
|
||||
berr = _PointDistanceSquaredToSegment (&spline->b, &spline->a, &spline->d);
|
||||
cerr = _PointDistanceSquaredToSegment (&spline->c, &spline->a, &spline->d);
|
||||
|
||||
if (berr > cerr)
|
||||
return berr;
|
||||
else
|
||||
return cerr;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_spline_t s1, s2;
|
||||
|
||||
if (_cairo_spline_error_squared (spline) < tolerance_squared) {
|
||||
return _cairo_spline_add_point (result, &spline->a);
|
||||
}
|
||||
|
||||
_de_casteljau (spline, &s1, &s2);
|
||||
|
||||
status = _cairo_spline_decompose_into (&s1, tolerance_squared, result);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_spline_decompose_into (&s2, tolerance_squared, result);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (spline->pts_size) {
|
||||
_cairo_spline_fini (spline);
|
||||
}
|
||||
|
||||
status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_spline_add_point (spline, &spline->d);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
391
src/cairo-surface.c
Normal file
391
src/cairo-surface.c
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_for_drawable (Display *dpy,
|
||||
Drawable drawable,
|
||||
Visual *visual,
|
||||
cairo_format_t format,
|
||||
Colormap colormap)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
surface = malloc (sizeof (cairo_surface_t));
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
surface->dpy = dpy;
|
||||
surface->image_data = NULL;
|
||||
|
||||
surface->xc_surface = XcSurfaceCreateForDrawable (dpy, drawable, visual, format, colormap);
|
||||
if (surface->xc_surface == NULL) {
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* XXX: We should really get this value from somewhere like Xft.dpy */
|
||||
surface->ppm = 3780;
|
||||
|
||||
surface->ref_count = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/* XXX: These definitions are 100% bogus. The problem that needs to be
|
||||
fixed is that Ic needs to export a real API for passing in
|
||||
formats. */
|
||||
#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
|
||||
((type) << 16) | \
|
||||
((a) << 12) | \
|
||||
((r) << 8) | \
|
||||
((g) << 4) | \
|
||||
((b)))
|
||||
|
||||
/*
|
||||
* gray/color formats use a visual index instead of argb
|
||||
*/
|
||||
#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \
|
||||
((type) << 16) | \
|
||||
((vi)))
|
||||
|
||||
#define PICT_TYPE_A 1
|
||||
#define PICT_TYPE_ARGB 2
|
||||
|
||||
#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2)
|
||||
|
||||
/* 32bpp formats */
|
||||
|
||||
#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8)
|
||||
#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8)
|
||||
#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0)
|
||||
#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0)
|
||||
|
||||
static int
|
||||
cairo_format_bpp (cairo_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_A1:
|
||||
return 1;
|
||||
break;
|
||||
case CAIRO_FORMAT_A8:
|
||||
return 8;
|
||||
break;
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
default:
|
||||
return 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_for_image (char *data,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
IcFormat icformat;
|
||||
IcImage *image;
|
||||
int bpp;
|
||||
|
||||
/* XXX: This all needs to change, (but IcFormatInit interface needs to change first) */
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
IcFormatInit (&icformat, PICT_a8r8g8b8);
|
||||
bpp = 32;
|
||||
break;
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
IcFormatInit (&icformat, PICT_x8r8g8b8);
|
||||
bpp = 32;
|
||||
break;
|
||||
case CAIRO_FORMAT_A8:
|
||||
IcFormatInit (&icformat, PICT_a8);
|
||||
bpp = 8;
|
||||
break;
|
||||
case CAIRO_FORMAT_A1:
|
||||
IcFormatInit (&icformat, PICT_a1);
|
||||
bpp = 1;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface = malloc (sizeof (cairo_surface_t));
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
surface->dpy = NULL;
|
||||
surface->image_data = NULL;
|
||||
image = IcImageCreateForData ((IcBits *) data, &icformat, width, height, cairo_format_bpp (format), stride);
|
||||
if (image == NULL) {
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface->xc_surface = XcSurfaceCreateForIcImage (image);
|
||||
if (surface->xc_surface == NULL) {
|
||||
IcImageDestroy (image);
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assume a default until the user lets us know otherwise */
|
||||
surface->ppm = 3780;
|
||||
|
||||
surface->ref_count = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_similar (cairo_surface_t *other,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_A1:
|
||||
return 1;
|
||||
case CAIRO_FORMAT_A8:
|
||||
return 8;
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
return 24;
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
default:
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_similar_solid (cairo_surface_t *other,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha)
|
||||
{
|
||||
cairo_surface_t *surface = NULL;
|
||||
cairo_color_t color;
|
||||
|
||||
/* XXX: create_similar should perhaps move down to Xc, (then we
|
||||
could drop xrsurface->dpy as well) */
|
||||
if (other->dpy) {
|
||||
Display *dpy = other->dpy;
|
||||
int scr = DefaultScreen (dpy);
|
||||
|
||||
Pixmap pix = XCreatePixmap (dpy,
|
||||
DefaultRootWindow (dpy),
|
||||
width, height,
|
||||
_CAIRO_FORMAT_DEPTH (format));
|
||||
|
||||
surface = cairo_surface_create_for_drawable (dpy, pix,
|
||||
NULL,
|
||||
format,
|
||||
DefaultColormap (dpy, scr));
|
||||
/* XXX: huh? This should be fine since we already created a picture
|
||||
from the pixmap, right?? (Somehow, it seems to be causing some
|
||||
breakage).
|
||||
XFreePixmap (surface->dpy, pix);
|
||||
*/
|
||||
} else {
|
||||
char *data;
|
||||
int stride;
|
||||
|
||||
stride = ((width * cairo_format_bpp (format)) + 7) >> 3;
|
||||
data = malloc (stride * height);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
surface = cairo_surface_create_for_image (data, format,
|
||||
width, height, stride);
|
||||
|
||||
/* lodge data in the surface structure to be freed with the surface */
|
||||
surface->image_data = data;
|
||||
}
|
||||
|
||||
/* XXX: Initializing the color in this way assumes
|
||||
non-pre-multiplied alpha. I'm not sure that that's what I want
|
||||
to do or not. */
|
||||
_cairo_color_init (&color);
|
||||
_cairo_color_set_rgb (&color, red, green, blue);
|
||||
_cairo_color_set_alpha (&color, alpha);
|
||||
_cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SRC, &color, 0, 0, width, height);
|
||||
return surface;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_surface_reference (cairo_surface_t *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
surface->ref_count++;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_surface_destroy (cairo_surface_t *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
surface->ref_count--;
|
||||
if (surface->ref_count)
|
||||
return;
|
||||
|
||||
surface->dpy = 0;
|
||||
|
||||
XcSurfaceDestroy (surface->xc_surface);
|
||||
surface->xc_surface = NULL;
|
||||
|
||||
if (surface->image_data)
|
||||
free (surface->image_data);
|
||||
surface->image_data = NULL;
|
||||
|
||||
free (surface);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_put_image (cairo_surface_t *surface,
|
||||
char *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
XcSurfacePutImage (surface->xc_surface, data,
|
||||
width, height, stride);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: Symmetry demands an cairo_surface_get_image as well */
|
||||
|
||||
/* XXX: We may want to move to projective matrices at some point. If
|
||||
nothing else, that would eliminate the two different transform data
|
||||
structures we have here. */
|
||||
cairo_status_t
|
||||
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
|
||||
{
|
||||
XTransform xtransform;
|
||||
|
||||
xtransform.matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
|
||||
xtransform.matrix[0][1] = XDoubleToFixed (matrix->m[1][0]);
|
||||
xtransform.matrix[0][2] = XDoubleToFixed (matrix->m[2][0]);
|
||||
|
||||
xtransform.matrix[1][0] = XDoubleToFixed (matrix->m[0][1]);
|
||||
xtransform.matrix[1][1] = XDoubleToFixed (matrix->m[1][1]);
|
||||
xtransform.matrix[1][2] = XDoubleToFixed (matrix->m[2][1]);
|
||||
|
||||
xtransform.matrix[2][0] = 0;
|
||||
xtransform.matrix[2][1] = 0;
|
||||
xtransform.matrix[2][2] = XDoubleToFixed (1);
|
||||
|
||||
XcSurfaceSetTransform (surface->xc_surface,
|
||||
&xtransform);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
|
||||
{
|
||||
XTransform xtransform;
|
||||
|
||||
XcSurfaceGetTransform (surface->xc_surface, &xtransform);
|
||||
|
||||
matrix->m[0][0] = XFixedToDouble (xtransform.matrix[0][0]);
|
||||
matrix->m[1][0] = XFixedToDouble (xtransform.matrix[0][1]);
|
||||
matrix->m[2][0] = XFixedToDouble (xtransform.matrix[0][2]);
|
||||
|
||||
matrix->m[0][1] = XFixedToDouble (xtransform.matrix[1][0]);
|
||||
matrix->m[1][1] = XFixedToDouble (xtransform.matrix[1][1]);
|
||||
matrix->m[2][1] = XFixedToDouble (xtransform.matrix[1][2]);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
|
||||
{
|
||||
XcSurfaceSetFilter (surface->xc_surface, filter);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: The Xc version of this function isn't quite working yet
|
||||
cairo_status_t
|
||||
cairo_surface_set_clip_region (cairo_surface_t *surface, Region region)
|
||||
{
|
||||
XcSurfaceSetClipRegion (surface->xc_surface, region);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
|
||||
{
|
||||
XcSurfaceSetRepeat (surface->xc_surface, repeat);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: This function is going away, right? */
|
||||
Picture
|
||||
_cairo_surface_get_picture (cairo_surface_t *surface)
|
||||
{
|
||||
return XcSurfaceGetPicture (surface->xc_surface);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
|
||||
cairo_operator_t operator,
|
||||
cairo_color_t *color,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
XcFillRectangle (operator,
|
||||
surface->xc_surface,
|
||||
&color->xc_color,
|
||||
x, y,
|
||||
width, height);
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* $XFree86: $
|
||||
*
|
||||
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
|
|
@ -21,47 +19,47 @@
|
|||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* 2002-07-15: Converted from XRenderCompositeDoublePoly to XrTrap. Carl D. Worth
|
||||
* 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
|
||||
*/
|
||||
|
||||
#include "xrint.h"
|
||||
#include "cairoint.h"
|
||||
|
||||
#define XR_TRAPS_GROWTH_INC 10
|
||||
#define CAIRO_TRAPS_GROWTH_INC 10
|
||||
|
||||
/* private functions */
|
||||
|
||||
static XrStatus
|
||||
_XrTrapsGrowBy(XrTraps *traps, int additional);
|
||||
static cairo_status_t
|
||||
cairo_traps_grow_by (cairo_traps_t *traps, int additional);
|
||||
|
||||
XrStatus
|
||||
_XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
|
||||
XLineFixed left, XLineFixed right);
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XLineFixed left, XLineFixed right);
|
||||
|
||||
XrStatus
|
||||
_XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
|
||||
XPointFixed left_p1, XPointFixed left_p2,
|
||||
XPointFixed right_p1, XPointFixed right_p2);
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XPointFixed left_p1, XPointFixed left_p2,
|
||||
XPointFixed right_p1, XPointFixed right_p2);
|
||||
|
||||
static int
|
||||
_ComparePointFixedByY (const void *av, const void *bv);
|
||||
_compare_point_fixed_by_y (const void *av, const void *bv);
|
||||
|
||||
static int
|
||||
_CompareXrEdgeByTop (const void *av, const void *bv);
|
||||
_compare_cairo_edge_by_top (const void *av, const void *bv);
|
||||
|
||||
static XFixed
|
||||
_ComputeX (XLineFixed *line, XFixed y);
|
||||
_compute_x (XLineFixed *line, XFixed y);
|
||||
|
||||
static double
|
||||
_ComputeInverseSlope (XLineFixed *l);
|
||||
_compute_inverse_slope (XLineFixed *l);
|
||||
|
||||
static double
|
||||
_ComputeXIntercept (XLineFixed *l, double inverse_slope);
|
||||
_compute_x_intercept (XLineFixed *l, double inverse_slope);
|
||||
|
||||
static XFixed
|
||||
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
|
||||
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
|
||||
|
||||
void
|
||||
_XrTrapsInit(XrTraps *traps)
|
||||
cairo_traps_init (cairo_traps_t *traps)
|
||||
{
|
||||
traps->num_xtraps = 0;
|
||||
|
||||
|
|
@ -70,29 +68,29 @@ _XrTrapsInit(XrTraps *traps)
|
|||
}
|
||||
|
||||
void
|
||||
_XrTrapsDeinit(XrTraps *traps)
|
||||
cairo_traps_fini (cairo_traps_t *traps)
|
||||
{
|
||||
if (traps->xtraps_size) {
|
||||
free(traps->xtraps);
|
||||
free (traps->xtraps);
|
||||
traps->xtraps = NULL;
|
||||
traps->xtraps_size = 0;
|
||||
traps->num_xtraps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
XrStatus
|
||||
_XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
|
||||
XLineFixed left, XLineFixed right)
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XLineFixed left, XLineFixed right)
|
||||
{
|
||||
XrStatus status;
|
||||
cairo_status_t status;
|
||||
XTrapezoid *trap;
|
||||
|
||||
if (top == bottom) {
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (traps->num_xtraps >= traps->xtraps_size) {
|
||||
status = _XrTrapsGrowBy(traps, XR_TRAPS_GROWTH_INC);
|
||||
status = cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
|
@ -105,13 +103,13 @@ _XrTrapsAddTrap(XrTraps *traps, XFixed top, XFixed bottom,
|
|||
|
||||
traps->num_xtraps++;
|
||||
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
XrStatus
|
||||
_XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
|
||||
XPointFixed left_p1, XPointFixed left_p2,
|
||||
XPointFixed right_p1, XPointFixed right_p2)
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XPointFixed left_p1, XPointFixed left_p2,
|
||||
XPointFixed right_p1, XPointFixed right_p2)
|
||||
{
|
||||
XLineFixed left;
|
||||
XLineFixed right;
|
||||
|
|
@ -122,35 +120,35 @@ _XrTrapsAddTrapFromPoints(XrTraps *traps, XFixed top, XFixed bottom,
|
|||
right.p1 = right_p1;
|
||||
right.p2 = right_p2;
|
||||
|
||||
return _XrTrapsAddTrap(traps, top, bottom, left, right);
|
||||
return cairo_traps_add_trap (traps, top, bottom, left, right);
|
||||
}
|
||||
|
||||
static XrStatus
|
||||
_XrTrapsGrowBy(XrTraps *traps, int additional)
|
||||
static cairo_status_t
|
||||
cairo_traps_grow_by (cairo_traps_t *traps, int additional)
|
||||
{
|
||||
XTrapezoid *new_xtraps;
|
||||
int old_size = traps->xtraps_size;
|
||||
int new_size = traps->num_xtraps + additional;
|
||||
|
||||
if (new_size <= traps->xtraps_size) {
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
traps->xtraps_size = new_size;
|
||||
new_xtraps = realloc(traps->xtraps, traps->xtraps_size * sizeof(XTrapezoid));
|
||||
new_xtraps = realloc (traps->xtraps, traps->xtraps_size * sizeof (XTrapezoid));
|
||||
|
||||
if (new_xtraps == NULL) {
|
||||
traps->xtraps_size = old_size;
|
||||
return XrStatusNoMemory;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
traps->xtraps = new_xtraps;
|
||||
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_ComparePointFixedByY (const void *av, const void *bv)
|
||||
_compare_point_fixed_by_y (const void *av, const void *bv)
|
||||
{
|
||||
const XPointFixed *a = av, *b = bv;
|
||||
|
||||
|
|
@ -161,105 +159,111 @@ _ComparePointFixedByY (const void *av, const void *bv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
XrStatus
|
||||
_XrTrapsTessellateTriangle (XrTraps *traps, XPointFixed t[3])
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_triangle (cairo_traps_t *traps, XPointFixed t[3])
|
||||
{
|
||||
XrStatus status;
|
||||
cairo_status_t status;
|
||||
XLineFixed line;
|
||||
double intersect;
|
||||
XPointFixed tsort[3];
|
||||
|
||||
memcpy(tsort, t, 3 * sizeof(XPointFixed));
|
||||
qsort(tsort, 3, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||
memcpy (tsort, t, 3 * sizeof (XPointFixed));
|
||||
qsort (tsort, 3, sizeof (XPointFixed), _compare_point_fixed_by_y);
|
||||
|
||||
/* horizontal top edge requires special handling */
|
||||
if (tsort[0].y == tsort[1].y) {
|
||||
if (tsort[0].x < tsort[1].x)
|
||||
status = _XrTrapsAddTrapFromPoints (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
else
|
||||
status = _XrTrapsAddTrapFromPoints (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
return status;
|
||||
}
|
||||
|
||||
line.p1 = tsort[0];
|
||||
line.p2 = tsort[1];
|
||||
|
||||
intersect = _ComputeX (&line, tsort[2].y);
|
||||
intersect = _compute_x (&line, tsort[2].y);
|
||||
|
||||
if (intersect < tsort[2].x) {
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
tsort[0].y, tsort[1].y,
|
||||
tsort[0], tsort[1],
|
||||
tsort[0], tsort[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[0].y, tsort[1].y,
|
||||
tsort[0], tsort[1],
|
||||
tsort[0], tsort[2]);
|
||||
if (status)
|
||||
return status;
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
tsort[0].y, tsort[1].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[0], tsort[1]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[0].y, tsort[1].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[0], tsort[1]);
|
||||
if (status)
|
||||
return status;
|
||||
status = _XrTrapsAddTrapFromPoints(traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Warning: This function reorders the elements of the array provided. */
|
||||
XrStatus
|
||||
_XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4])
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_rectangle (cairo_traps_t *traps, XPointFixed q[4])
|
||||
{
|
||||
XrStatus status;
|
||||
cairo_status_t status;
|
||||
|
||||
qsort(q, 4, sizeof(XPointFixed), _ComparePointFixedByY);
|
||||
qsort (q, 4, sizeof (XPointFixed), _compare_point_fixed_by_y);
|
||||
|
||||
if (q[1].x > q[2].x) {
|
||||
status = _XrTrapsAddTrapFromPoints(traps, q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
|
||||
if (status)
|
||||
return status;
|
||||
status = _XrTrapsAddTrapFromPoints(traps, q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
|
||||
if (status)
|
||||
return status;
|
||||
status = _XrTrapsAddTrapFromPoints(traps, q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
status = _XrTrapsAddTrapFromPoints(traps, q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
|
||||
if (status)
|
||||
return status;
|
||||
status = _XrTrapsAddTrapFromPoints(traps, q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
|
||||
if (status)
|
||||
return status;
|
||||
status = _XrTrapsAddTrapFromPoints(traps, q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_CompareXrEdgeByTop (const void *av, const void *bv)
|
||||
_compare_cairo_edge_by_top (const void *av, const void *bv)
|
||||
{
|
||||
const XrEdge *a = av, *b = bv;
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
int ret;
|
||||
|
||||
ret = a->edge.p1.y - b->edge.p1.y;
|
||||
|
|
@ -270,35 +274,35 @@ _CompareXrEdgeByTop (const void *av, const void *bv)
|
|||
|
||||
/* Return value is:
|
||||
> 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
|
||||
== 0 if slope(a) == slope(b)
|
||||
== 0 if slope (a) == slope (b)
|
||||
< 0 if a is "counter-clockwise" from b
|
||||
*/
|
||||
static int
|
||||
_CompareXrEdgeBySlope (const void *av, const void *bv)
|
||||
_compare_cairo_edge_by_slope (const void *av, const void *bv)
|
||||
{
|
||||
const XrEdge *a = av, *b = bv;
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
|
||||
double a_dx = XFixedToDouble(a->edge.p2.x - a->edge.p1.x);
|
||||
double a_dy = XFixedToDouble(a->edge.p2.y - a->edge.p1.y);
|
||||
double b_dx = XFixedToDouble(b->edge.p2.x - b->edge.p1.x);
|
||||
double b_dy = XFixedToDouble(b->edge.p2.y - b->edge.p1.y);
|
||||
double a_dx = XFixedToDouble (a->edge.p2.x - a->edge.p1.x);
|
||||
double a_dy = XFixedToDouble (a->edge.p2.y - a->edge.p1.y);
|
||||
double b_dx = XFixedToDouble (b->edge.p2.x - b->edge.p1.x);
|
||||
double b_dy = XFixedToDouble (b->edge.p2.y - b->edge.p1.y);
|
||||
|
||||
return b_dy * a_dx - a_dy * b_dx;
|
||||
}
|
||||
|
||||
static int
|
||||
_CompareXrEdgeByCurrentXThenSlope (const void *av, const void *bv)
|
||||
_compare_cairo_edge_by_current_xthen_slope (const void *av, const void *bv)
|
||||
{
|
||||
const XrEdge *a = av, *b = bv;
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
int ret;
|
||||
|
||||
ret = a->current_x - b->current_x;
|
||||
if (ret == 0)
|
||||
ret = _CompareXrEdgeBySlope(a, b);
|
||||
ret = _compare_cairo_edge_by_slope (a, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* XXX: Both _ComputeX and _ComputeInverseSlope will divide by zero
|
||||
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
|
||||
for horizontal lines. Now, we "know" that when we are tessellating
|
||||
polygons that the polygon data structure discards all horizontal
|
||||
edges, but there's nothing here to guarantee that. I suggest the
|
||||
|
|
@ -324,34 +328,34 @@ _det (double a, double b, double c, double d)
|
|||
}
|
||||
|
||||
static int
|
||||
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
||||
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
||||
{
|
||||
double dx1 = XFixedToDouble(l1->p1.x - l1->p2.x);
|
||||
double dy1 = XFixedToDouble(l1->p1.y - l1->p2.y);
|
||||
double dx1 = XFixedToDouble (l1->p1.x - l1->p2.x);
|
||||
double dy1 = XFixedToDouble (l1->p1.y - l1->p2.y);
|
||||
|
||||
double dx2 = XFixedToDouble(l2->p1.x - l2->p2.x);
|
||||
double dy2 = XFixedToDouble(l2->p1.y - l2->p2.y);
|
||||
double dx2 = XFixedToDouble (l2->p1.x - l2->p2.x);
|
||||
double dy2 = XFixedToDouble (l2->p1.y - l2->p2.y);
|
||||
|
||||
double l1_det, l2_det;
|
||||
|
||||
double den_det = _det(dx1, dy1, dx2, dy2);
|
||||
double den_det = _det (dx1, dy1, dx2, dy2);
|
||||
|
||||
if (den_det == 0)
|
||||
return 0;
|
||||
|
||||
l1_det = _det(l1->p1.x, l1->p1.y,
|
||||
l1_det = _det (l1->p1.x, l1->p1.y,
|
||||
l1->p2.x, l1->p2.y);
|
||||
l2_det = _det(l2->p1.x, l2->p1.y,
|
||||
l2_det = _det (l2->p1.x, l2->p1.y,
|
||||
l2->p2.x, l2->p2.y);
|
||||
|
||||
*y_intersection = _det(l1_det, dy1,
|
||||
*y_intersection = _det (l1_det, dy1,
|
||||
l2_det, dy2) / den_det;
|
||||
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
static XFixed
|
||||
_ComputeX (XLineFixed *line, XFixed y)
|
||||
_compute_x (XLineFixed *line, XFixed y)
|
||||
{
|
||||
XFixed dx = line->p2.x - line->p1.x;
|
||||
double ex = (double) (y - line->p1.y) * (double) dx;
|
||||
|
|
@ -361,20 +365,20 @@ _ComputeX (XLineFixed *line, XFixed y)
|
|||
}
|
||||
|
||||
static double
|
||||
_ComputeInverseSlope (XLineFixed *l)
|
||||
_compute_inverse_slope (XLineFixed *l)
|
||||
{
|
||||
return (XFixedToDouble (l->p2.x - l->p1.x) /
|
||||
XFixedToDouble (l->p2.y - l->p1.y));
|
||||
}
|
||||
|
||||
static double
|
||||
_ComputeXIntercept (XLineFixed *l, double inverse_slope)
|
||||
_compute_x_intercept (XLineFixed *l, double inverse_slope)
|
||||
{
|
||||
return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y);
|
||||
}
|
||||
|
||||
static int
|
||||
_LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
||||
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
||||
{
|
||||
/*
|
||||
* x = m1y + b1
|
||||
|
|
@ -383,10 +387,10 @@ _LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
|||
* y * (m1 - m2) = b2 - b1
|
||||
* y = (b2 - b1) / (m1 - m2)
|
||||
*/
|
||||
double m1 = _ComputeInverseSlope (l1);
|
||||
double b1 = _ComputeXIntercept (l1, m1);
|
||||
double m2 = _ComputeInverseSlope (l2);
|
||||
double b2 = _ComputeXIntercept (l2, m2);
|
||||
double m1 = _compute_inverse_slope (l1);
|
||||
double b1 = _compute_x_intercept (l1, m1);
|
||||
double m2 = _compute_inverse_slope (l2);
|
||||
double b2 = _compute_x_intercept (l2, m2);
|
||||
|
||||
if (m1 == m2)
|
||||
return 0;
|
||||
|
|
@ -396,9 +400,9 @@ _LinesIntersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
|||
}
|
||||
|
||||
static void
|
||||
_SortEdgeList(XrEdge **active)
|
||||
_SortEdgeList (cairo_edge_t **active)
|
||||
{
|
||||
XrEdge *e, *en, *next;
|
||||
cairo_edge_t *e, *en, *next;
|
||||
|
||||
/* sort active list */
|
||||
for (e = *active; e; e = next)
|
||||
|
|
@ -410,7 +414,7 @@ _SortEdgeList(XrEdge **active)
|
|||
*/
|
||||
for (en = next; en; en = en->next)
|
||||
{
|
||||
if (_CompareXrEdgeByCurrentXThenSlope(e, en) > 0)
|
||||
if (_compare_cairo_edge_by_current_xthen_slope (e, en) > 0)
|
||||
{
|
||||
/*
|
||||
* insert en before e
|
||||
|
|
@ -443,14 +447,14 @@ _SortEdgeList(XrEdge **active)
|
|||
/* The algorithm here is pretty simple:
|
||||
|
||||
inactive = [edges]
|
||||
y = min_p1_y(inactive)
|
||||
y = min_p1_y (inactive)
|
||||
|
||||
while (num_active || num_inactive) {
|
||||
active = all edges containing y
|
||||
|
||||
next_y = min( min_p2_y(active), min_p1_y(inactive), min_intersection(active) )
|
||||
next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )
|
||||
|
||||
fill_traps(active, y, next_y, fill_rule)
|
||||
fill_traps (active, y, next_y, fill_rule)
|
||||
|
||||
y = next_y
|
||||
}
|
||||
|
|
@ -467,23 +471,23 @@ _SortEdgeList(XrEdge **active)
|
|||
|
||||
Warning: This function reorders the edges of the polygon provided.
|
||||
*/
|
||||
XrStatus
|
||||
_XrTrapsTessellatePolygon (XrTraps *traps,
|
||||
XrPolygon *poly,
|
||||
XrFillRule fill_rule)
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_polygon (cairo_traps_t *traps,
|
||||
cairo_polygon_t *poly,
|
||||
cairo_fill_rule_t fill_rule)
|
||||
{
|
||||
XrStatus status;
|
||||
cairo_status_t status;
|
||||
int inactive;
|
||||
XrEdge *active;
|
||||
XrEdge *e, *en, *next;
|
||||
cairo_edge_t *active;
|
||||
cairo_edge_t *e, *en, *next;
|
||||
XFixed y, next_y, intersect;
|
||||
int in_out, num_edges = poly->num_edges;
|
||||
XrEdge *edges = poly->edges;
|
||||
cairo_edge_t *edges = poly->edges;
|
||||
|
||||
if (num_edges == 0)
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
qsort (edges, num_edges, sizeof (XrEdge), _CompareXrEdgeByTop);
|
||||
qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
|
||||
|
||||
y = edges[0].edge.p1.y;
|
||||
active = 0;
|
||||
|
|
@ -491,7 +495,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
while (active || inactive < num_edges)
|
||||
{
|
||||
for (e = active; e; e = e->next) {
|
||||
e->current_x = _ComputeX (&e->edge, y);
|
||||
e->current_x = _compute_x (&e->edge, y);
|
||||
}
|
||||
|
||||
/* insert new active edges into list */
|
||||
|
|
@ -502,7 +506,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
break;
|
||||
/* move this edge into the active list */
|
||||
inactive++;
|
||||
e->current_x = _ComputeX (&e->edge, y);
|
||||
e->current_x = _compute_x (&e->edge, y);
|
||||
|
||||
/* insert e at head of list */
|
||||
e->next = active;
|
||||
|
|
@ -512,7 +516,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
active = e;
|
||||
}
|
||||
|
||||
_SortEdgeList(&active);
|
||||
_SortEdgeList (&active);
|
||||
|
||||
/* find next inflection point */
|
||||
if (active)
|
||||
|
|
@ -528,12 +532,12 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
/* check intersect */
|
||||
if (en && e->current_x != en->current_x)
|
||||
{
|
||||
if (_LinesIntersect (&e->edge, &en->edge, &intersect))
|
||||
if (_lines_intersect (&e->edge, &en->edge, &intersect))
|
||||
if (intersect > y) {
|
||||
/* Need to guarantee that we get all the way past
|
||||
the intersection point so that the edges sort
|
||||
properly next time through the loop. */
|
||||
if (_ComputeX(&e->edge, intersect) < _ComputeX(&en->edge, intersect))
|
||||
if (_compute_x (&e->edge, intersect) < _compute_x (&en->edge, intersect))
|
||||
intersect++;
|
||||
if (intersect < next_y)
|
||||
next_y = intersect;
|
||||
|
|
@ -548,7 +552,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
in_out = 0;
|
||||
for (e = active; e && (en = e->next); e = e->next)
|
||||
{
|
||||
if (fill_rule == XrFillRuleWinding) {
|
||||
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
|
||||
if (e->clockWise) {
|
||||
in_out++;
|
||||
} else {
|
||||
|
|
@ -563,7 +567,7 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
status = _XrTrapsAddTrap(traps, y, next_y, e->edge, en->edge);
|
||||
status = cairo_traps_add_trap (traps, y, next_y, e->edge, en->edge);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
|
@ -585,5 +589,5 @@ _XrTrapsTessellatePolygon (XrTraps *traps,
|
|||
|
||||
y = next_y;
|
||||
}
|
||||
return XrStatusSuccess;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
715
src/cairo.c
Normal file
715
src/cairo.c
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
|
||||
|
||||
static void
|
||||
_cairo_restrict_value (double *value, double min, double max);
|
||||
|
||||
static void
|
||||
_cairo_init (cairo_t *cr);
|
||||
|
||||
static void
|
||||
_cairo_fini (cairo_t *cr);
|
||||
|
||||
cairo_t *
|
||||
cairo_create (void)
|
||||
{
|
||||
cairo_t *cr;
|
||||
|
||||
cr = malloc (sizeof (cairo_t));
|
||||
|
||||
if (cr) {
|
||||
_cairo_init (cr);
|
||||
if (cr->status) {
|
||||
free (cr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_init (cairo_t *cr)
|
||||
{
|
||||
cr->gstate = NULL;
|
||||
|
||||
cr->status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
cairo_save (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_fini (cairo_t *cr)
|
||||
{
|
||||
while (cr->gstate) {
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cairo_destroy (cairo_t *cr)
|
||||
{
|
||||
_cairo_fini (cr);
|
||||
free (cr);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_save (cairo_t *cr)
|
||||
{
|
||||
cairo_gstate_t *top;
|
||||
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
if (cr->gstate) {
|
||||
top = _cairo_gstate_clone (cr->gstate);
|
||||
} else {
|
||||
top = _cairo_gstate_create ();
|
||||
}
|
||||
|
||||
if (top == NULL) {
|
||||
cr->status = CAIRO_STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
top->next = cr->gstate;
|
||||
cr->gstate = top;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_restore (cairo_t *cr)
|
||||
{
|
||||
cairo_gstate_t *top;
|
||||
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
if (cr->gstate == NULL) {
|
||||
cr->status = CAIRO_STATUS_INVALID_RESTORE;
|
||||
return;
|
||||
}
|
||||
|
||||
top = cr->gstate;
|
||||
cr->gstate = top->next;
|
||||
|
||||
_cairo_gstate_destroy (top);
|
||||
}
|
||||
|
||||
/* XXX: I want to rethink this API
|
||||
void
|
||||
cairo_push_group (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairoPush (cr);
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_begin_group (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_pop_group (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_end_group (cr->gstate);
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairoPop (cr);
|
||||
}
|
||||
*/
|
||||
|
||||
void
|
||||
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_target_surface (cr->gstate, surface);
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_get_target_surface (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_target_surface (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_target_drawable (cairo_t *cr,
|
||||
Display *dpy,
|
||||
Drawable drawable)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
surface = cairo_surface_create_for_drawable (dpy, drawable,
|
||||
DefaultVisual (dpy, DefaultScreen (dpy)),
|
||||
0,
|
||||
DefaultColormap (dpy, DefaultScreen (dpy)));
|
||||
if (surface == NULL) {
|
||||
cr->status = CAIRO_STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_set_target_surface (cr, surface);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_target_image (cairo_t *cr,
|
||||
char *data,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
surface = cairo_surface_create_for_image (data,
|
||||
format,
|
||||
width, height, stride);
|
||||
if (surface == NULL) {
|
||||
cr->status = CAIRO_STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_set_target_surface (cr, surface);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_operator (cairo_t *cr, cairo_operator_t op)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_operator (cr->gstate, op);
|
||||
}
|
||||
|
||||
cairo_operator_t
|
||||
cairo_get_operator (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_operator (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
_cairo_restrict_value (&red, 0.0, 1.0);
|
||||
_cairo_restrict_value (&green, 0.0, 1.0);
|
||||
_cairo_restrict_value (&blue, 0.0, 1.0);
|
||||
|
||||
cr->status = _cairo_gstate_set_rgb_color (cr->gstate, red, green, blue);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_get_rgb_color (cairo_t *cr, double *red, double *green, double *blue)
|
||||
{
|
||||
/* XXX: Should we do anything with the return values in the error case? */
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_get_rgb_color (cr->gstate, red, green, blue);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_tolerance (cairo_t *cr, double tolerance)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
_cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance);
|
||||
|
||||
cr->status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
|
||||
}
|
||||
|
||||
double
|
||||
cairo_get_tolerance (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_tolerance (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_alpha (cairo_t *cr, double alpha)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
_cairo_restrict_value (&alpha, 0.0, 1.0);
|
||||
|
||||
cr->status = _cairo_gstate_set_alpha (cr->gstate, alpha);
|
||||
}
|
||||
|
||||
double
|
||||
cairo_get_alpha (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_alpha (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_line_width (cairo_t *cr, double width)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_line_width (cr->gstate, width);
|
||||
}
|
||||
|
||||
double
|
||||
cairo_get_line_width (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_line_width (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
|
||||
}
|
||||
|
||||
cairo_line_cap_t
|
||||
cairo_get_line_cap (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_line_cap (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join);
|
||||
}
|
||||
|
||||
cairo_line_join_t
|
||||
cairo_get_line_join (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_line_join (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_miter_limit (cairo_t *cr, double limit)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
|
||||
}
|
||||
|
||||
double
|
||||
cairo_get_miter_limit (cairo_t *cr)
|
||||
{
|
||||
return _cairo_gstate_get_miter_limit (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_translate (cairo_t *cr, double tx, double ty)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairo_gstate_translate (cr->gstate, tx, ty);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_scale (cairo_t *cr, double sx, double sy)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_scale (cr->gstate, sx, sy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_rotate (cairo_t *cr, double angle)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_rotate (cr->gstate, angle);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_concat_matrix (cairo_t *cr,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_concat_matrix (cr->gstate, matrix);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_set_matrix (cairo_t *cr,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_default_matrix (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_default_matrix (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_identity_matrix (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_identity_matrix (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_transform_point (cairo_t *cr, double *x, double *y)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairo_gstateransform_point (cr->gstate, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_transform_distance (cairo_t *cr, double *dx, double *dy)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairo_gstateransform_distance (cr->gstate, dx, dy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_inverse_transform_point (cr->gstate, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_inverse_transform_distance (cr->gstate, dx, dy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_new_path (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_new_path (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_move_to (cairo_t *cr, double x, double y)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_move_to (cr->gstate, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_line_to (cairo_t *cr, double x, double y)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_line_to (cr->gstate, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_curve_to (cairo_t *cr,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_curve_to (cr->gstate,
|
||||
x1, y1,
|
||||
x2, y2,
|
||||
x3, y3);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_rel_move_to (cr->gstate, dx, dy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_rel_line_to (cr->gstate, dx, dy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_rel_curve_to (cairo_t *cr,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
double dx3, double dy3)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_rel_curve_to (cr->gstate,
|
||||
dx1, dy1,
|
||||
dx2, dy2,
|
||||
dx3, dy3);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_rectangle (cairo_t *cr,
|
||||
double x, double y,
|
||||
double width, double height)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_rel_line_to (cr, width, 0);
|
||||
cairo_rel_line_to (cr, 0, height);
|
||||
cairo_rel_line_to (cr, -width, 0);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_close_path (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_close_path (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_get_current_point (cairo_t *cr, double *x, double *y)
|
||||
{
|
||||
/* XXX: Should we do anything with the return values in the error case? */
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_get_current_point (cr->gstate, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_stroke (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_stroke (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_fill (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_fill (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_clip (cairo_t *cr)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_clip (cr->gstate);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_select_font (cairo_t *cr, const char *key)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_select_font (cr->gstate, key);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_scale_font (cairo_t *cr, double scale)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_scale_font (cr->gstate, scale);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_transform_font (cairo_t *cr,
|
||||
double a, double b,
|
||||
double c, double d)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairo_gstateransform_font (cr->gstate,
|
||||
a, b, c, d);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_text_extents (cairo_t *cr,
|
||||
const unsigned char *utf8,
|
||||
double *x, double *y,
|
||||
double *width, double *height,
|
||||
double *dx, double *dy)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = cairo_gstateext_extents (cr->gstate, utf8,
|
||||
x, y, width, height, dx, dy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_show_text (cairo_t *cr, const unsigned char *utf8)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_show_text (cr->gstate, utf8);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_show_surface (cairo_t *cr,
|
||||
cairo_surface_t *surface,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_show_surface (cr->gstate,
|
||||
surface, width, height);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_get_status (cairo_t *cr)
|
||||
{
|
||||
return cr->status;
|
||||
}
|
||||
|
||||
const char *
|
||||
cairo_get_status_string (cairo_t *cr)
|
||||
{
|
||||
switch (cr->status) {
|
||||
case CAIRO_STATUS_SUCCESS:
|
||||
return "success";
|
||||
case CAIRO_STATUS_NO_MEMORY:
|
||||
return "out of memory";
|
||||
case CAIRO_STATUS_INVALID_RESTORE:
|
||||
return "cairo_restore without matching cairo_save";
|
||||
case CAIRO_STATUS_INVALID_POP_GROUP:
|
||||
return "cairo_pop_group without matching cairo_push_group";
|
||||
case CAIRO_STATUS_NO_CURRENT_POINT:
|
||||
return "no current point defined";
|
||||
case CAIRO_STATUS_INVALID_MATRIX:
|
||||
return "invalid matrix (not invertible)";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_restrict_value (double *value, double min, double max)
|
||||
{
|
||||
if (*value < min)
|
||||
*value = min;
|
||||
else if (*value > max)
|
||||
*value = max;
|
||||
}
|
||||
494
src/cairo.h
Normal file
494
src/cairo.h
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#ifndef _CAIRO_H_
|
||||
#define _CAIRO_H_
|
||||
|
||||
#include <Xc.h>
|
||||
|
||||
typedef struct cairo cairo_t;
|
||||
typedef struct cairo_surface_t cairo_surface_t;
|
||||
typedef struct cairo_matrix_t cairo_matrix_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Functions for manipulating state objects */
|
||||
cairo_t *
|
||||
cairo_create (void);
|
||||
|
||||
void
|
||||
cairo_destroy (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_save (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_restore (cairo_t *cr);
|
||||
|
||||
/* XXX: I want to rethink this API
|
||||
void
|
||||
cairo_push_group (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_pop_group (cairo_t *cr);
|
||||
*/
|
||||
|
||||
/* Modify state */
|
||||
void
|
||||
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface);
|
||||
|
||||
typedef enum cairo_format_t {
|
||||
CAIRO_FORMAT_ARGB32 = PictStandardARGB32,
|
||||
CAIRO_FORMAT_RGB24 = PictStandardRGB24,
|
||||
CAIRO_FORMAT_A8 = PictStandardA8,
|
||||
CAIRO_FORMAT_A1 = PictStandardA1
|
||||
} cairo_format_t;
|
||||
|
||||
void
|
||||
cairo_set_target_drawable (cairo_t *cr,
|
||||
Display *dpy,
|
||||
Drawable drawable);
|
||||
|
||||
void
|
||||
cairo_set_target_image (cairo_t *cr,
|
||||
char *data,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
typedef enum cairo_operator_t {
|
||||
CAIRO_OPERATOR_CLEAR = PictOpClear,
|
||||
CAIRO_OPERATOR_SRC = PictOpSrc,
|
||||
CAIRO_OPERATOR_DST = PictOpDst,
|
||||
CAIRO_OPERATOR_OVER = PictOpOver,
|
||||
CAIRO_OPERATOR_OVER_REVERSE = PictOpOverReverse,
|
||||
CAIRO_OPERATOR_IN = PictOpIn,
|
||||
CAIRO_OPERATOR_IN_REVERSE = PictOpInReverse,
|
||||
CAIRO_OPERATOR_OUT = PictOpOut,
|
||||
CAIRO_OPERATOR_OUT_REVERSE = PictOpOutReverse,
|
||||
CAIRO_OPERATOR_ATOP = PictOpAtop,
|
||||
CAIRO_OPERATOR_ATOP_REVERSE = PictOpAtopReverse,
|
||||
CAIRO_OPERATOR_XOR = PictOpXor,
|
||||
CAIRO_OPERATOR_ADD = PictOpAdd,
|
||||
CAIRO_OPERATOR_SATURATE = PictOpSaturate,
|
||||
|
||||
CAIRO_OPERATOR_DISJOINT_CLEAR = PictOpDisjointClear,
|
||||
CAIRO_OPERATOR_DISJOINT_SRC = PictOpDisjointSrc,
|
||||
CAIRO_OPERATOR_DISJOINT_DST = PictOpDisjointDst,
|
||||
CAIRO_OPERATOR_DISJOINT_OVER = PictOpDisjointOver,
|
||||
CAIRO_OPERATOR_DISJOINT_OVER_REVERSE = PictOpDisjointOverReverse,
|
||||
CAIRO_OPERATOR_DISJOINT_IN = PictOpDisjointIn,
|
||||
CAIRO_OPERATOR_DISJOINT_IN_REVERSE = PictOpDisjointInReverse,
|
||||
CAIRO_OPERATOR_DISJOINT_OUT = PictOpDisjointOut,
|
||||
CAIRO_OPERATOR_DISJOINT_OUT_REVERSE = PictOpDisjointOutReverse,
|
||||
CAIRO_OPERATOR_DISJOINT_ATOP = PictOpDisjointAtop,
|
||||
CAIRO_OPERATOR_DISJOINT_ATOP_REVERSE = PictOpDisjointAtopReverse,
|
||||
CAIRO_OPERATOR_DISJOINT_XOR = PictOpDisjointXor,
|
||||
|
||||
CAIRO_OPERATOR_CONJOINT_CLEAR = PictOpConjointClear,
|
||||
CAIRO_OPERATOR_CONJOINT_SRC = PictOpConjointSrc,
|
||||
CAIRO_OPERATOR_CONJOINT_DST = PictOpConjointDst,
|
||||
CAIRO_OPERATOR_CONJOINT_OVER = PictOpConjointOver,
|
||||
CAIRO_OPERATOR_CONJOINT_OVER_REVERSE = PictOpConjointOverReverse,
|
||||
CAIRO_OPERATOR_CONJOINT_IN = PictOpConjointIn,
|
||||
CAIRO_OPERATOR_CONJOINT_IN_REVERSE = PictOpConjointInReverse,
|
||||
CAIRO_OPERATOR_CONJOINT_OUT = PictOpConjointOut,
|
||||
CAIRO_OPERATOR_CONJOINT_OUT_REVERSE = PictOpConjointOutReverse,
|
||||
CAIRO_OPERATOR_CONJOINT_ATOP = PictOpConjointAtop,
|
||||
CAIRO_OPERATOR_CONJOINT_ATOP_REVERSE = PictOpConjointAtopReverse,
|
||||
CAIRO_OPERATOR_CONJOINT_XOR = PictOpConjointXor
|
||||
} cairo_operator_t;
|
||||
|
||||
void
|
||||
cairo_set_operator (cairo_t *cr, cairo_operator_t op);
|
||||
|
||||
/* XXX: Probably want to bite the bullet and expose a cairo_color_t object */
|
||||
|
||||
void
|
||||
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue);
|
||||
|
||||
void
|
||||
cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern);
|
||||
|
||||
void
|
||||
cairo_set_tolerance (cairo_t *cr, double tolerance);
|
||||
|
||||
void
|
||||
cairo_set_alpha (cairo_t *cr, double alpha);
|
||||
|
||||
typedef enum cairo_fill_rule_t {
|
||||
CAIRO_FILL_RULE_WINDING,
|
||||
CAIRO_FILL_RULE_EVEN_ODD
|
||||
} cairo_fill_rule_t;
|
||||
|
||||
void
|
||||
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule);
|
||||
|
||||
void
|
||||
cairo_set_line_width (cairo_t *cr, double width);
|
||||
|
||||
typedef enum cairo_line_cap_t {
|
||||
CAIRO_LINE_CAP_BUTT,
|
||||
CAIRO_LINE_CAP_ROUND,
|
||||
CAIRO_LINE_CAP_SQUARE
|
||||
} cairo_line_cap_t;
|
||||
|
||||
void
|
||||
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap);
|
||||
|
||||
typedef enum cairo_line_join_t {
|
||||
CAIRO_LINE_JOIN_MITER,
|
||||
CAIRO_LINE_JOIN_ROUND,
|
||||
CAIRO_LINE_JOIN_BEVEL
|
||||
} cairo_line_join_t;
|
||||
|
||||
void
|
||||
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join);
|
||||
|
||||
void
|
||||
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset);
|
||||
|
||||
void
|
||||
cairo_set_miter_limit (cairo_t *cr, double limit);
|
||||
|
||||
void
|
||||
cairo_translate (cairo_t *cr, double tx, double ty);
|
||||
|
||||
void
|
||||
cairo_scale (cairo_t *cr, double sx, double sy);
|
||||
|
||||
void
|
||||
cairo_rotate (cairo_t *cr, double angle);
|
||||
|
||||
void
|
||||
cairo_concat_matrix (cairo_t *cr,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
void
|
||||
cairo_set_matrix (cairo_t *cr,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
void
|
||||
cairo_default_matrix (cairo_t *cr);
|
||||
|
||||
/* XXX: There's been a proposal to add cairo_default_matrix_exact */
|
||||
|
||||
void
|
||||
cairo_identity_matrix (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_transform_point (cairo_t *cr, double *x, double *y);
|
||||
|
||||
void
|
||||
cairo_transform_distance (cairo_t *cr, double *dx, double *dy);
|
||||
|
||||
void
|
||||
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y);
|
||||
|
||||
void
|
||||
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy);
|
||||
|
||||
/* Path creation functions */
|
||||
void
|
||||
cairo_new_path (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_move_to (cairo_t *cr, double x, double y);
|
||||
|
||||
void
|
||||
cairo_line_to (cairo_t *cr, double x, double y);
|
||||
|
||||
void
|
||||
cairo_curve_to (cairo_t *cr,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
|
||||
void
|
||||
cairo_rel_move_to (cairo_t *cr, double dx, double dy);
|
||||
|
||||
void
|
||||
cairo_rel_line_to (cairo_t *cr, double dx, double dy);
|
||||
|
||||
void
|
||||
cairo_rel_curve_to (cairo_t *cr,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
double dx3, double dy3);
|
||||
|
||||
void
|
||||
cairo_rectangle (cairo_t *cr,
|
||||
double x, double y,
|
||||
double width, double height);
|
||||
|
||||
void
|
||||
cairo_close_path (cairo_t *cr);
|
||||
|
||||
/* Painting functions */
|
||||
void
|
||||
cairo_stroke (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_fill (cairo_t *cr);
|
||||
|
||||
/* Clipping */
|
||||
void
|
||||
cairo_clip (cairo_t *cr);
|
||||
|
||||
/* Font/Text functions */
|
||||
|
||||
/* XXX: The font support should probably expose a cairo_font_t object with
|
||||
several functions, (cairo_font_transform, etc.) in a parallel manner as
|
||||
cairo_matrix_t and (eventually) cairo_color_t */
|
||||
void
|
||||
cairo_select_font (cairo_t *cr, const char *key);
|
||||
|
||||
void
|
||||
cairo_scale_font (cairo_t *cr, double scale);
|
||||
|
||||
/* XXX: Probably want to use a cairo_matrix_t here, (to fix as part of the
|
||||
big text support rewrite) */
|
||||
void
|
||||
cairo_transform_font (cairo_t *cr,
|
||||
double a, double b,
|
||||
double c, double d);
|
||||
|
||||
void
|
||||
cairo_text_extents (cairo_t *cr,
|
||||
const unsigned char *utf8,
|
||||
double *x, double *y,
|
||||
double *width, double *height,
|
||||
double *dx, double *dy);
|
||||
|
||||
void
|
||||
cairo_show_text (cairo_t *cr, const unsigned char *utf8);
|
||||
|
||||
/* Image functions */
|
||||
|
||||
void
|
||||
cairo_show_surface (cairo_t *cr,
|
||||
cairo_surface_t *surface,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* Query functions */
|
||||
|
||||
cairo_operator_t
|
||||
cairo_get_operator (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_get_rgb_color (cairo_t *cr, double *red, double *green, double *blue);
|
||||
|
||||
/* XXX: Do we want cairo_get_pattern as well? */
|
||||
|
||||
double
|
||||
cairo_get_tolerance (cairo_t *cr);
|
||||
|
||||
double
|
||||
cairo_get_alpha (cairo_t *cr);
|
||||
|
||||
void
|
||||
cairo_get_current_point (cairo_t *cr, double *x, double *y);
|
||||
|
||||
cairo_fill_rule_t
|
||||
cairo_get_fill_rule (cairo_t *cr);
|
||||
|
||||
double
|
||||
cairo_get_line_width (cairo_t *cr);
|
||||
|
||||
cairo_line_cap_t
|
||||
cairo_get_line_cap (cairo_t *cr);
|
||||
|
||||
cairo_line_join_t
|
||||
cairo_get_line_join (cairo_t *cr);
|
||||
|
||||
double
|
||||
cairo_get_miter_limit (cairo_t *cr);
|
||||
|
||||
/* XXX: How to do cairo_get_dash??? Do we want to switch to a cairo_dash object? */
|
||||
|
||||
void
|
||||
cairo_get_matrix (cairo_t *cr,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty);
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_get_target_surface (cairo_t *cr);
|
||||
|
||||
/* Error status queries */
|
||||
|
||||
typedef enum cairo_status_t {
|
||||
CAIRO_STATUS_SUCCESS = 0,
|
||||
CAIRO_STATUS_NO_MEMORY,
|
||||
CAIRO_STATUS_INVALID_RESTORE,
|
||||
CAIRO_STATUS_INVALID_POP_GROUP,
|
||||
CAIRO_STATUS_NO_CURRENT_POINT,
|
||||
CAIRO_STATUS_INVALID_MATRIX
|
||||
} cairo_status_t;
|
||||
|
||||
cairo_status_t
|
||||
cairo_get_status (cairo_t *cr);
|
||||
|
||||
const char *
|
||||
cairo_get_status_string (cairo_t *cr);
|
||||
|
||||
/* Surface mainpulation */
|
||||
|
||||
/* XXX: This is a mess from the user's POV. Should the Visual or the
|
||||
cairo_format_t control what render format is used? Maybe I can have
|
||||
cairo_surface_create_for_window with a visual, and
|
||||
cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
|
||||
*/
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_for_drawable (Display *dpy,
|
||||
Drawable drawable,
|
||||
Visual *visual,
|
||||
cairo_format_t format,
|
||||
Colormap colormap);
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_for_image (char *data,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_similar (cairo_surface_t *other,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* XXX: One problem with having RGB and A here in one function is that
|
||||
it introduces the question of pre-multiplied vs. non-pre-multiplied
|
||||
alpha. Do I want to export a cairo_color_t structure instead? So far, no
|
||||
other public functions need it. */
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_similar_solid (cairo_surface_t *other,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha);
|
||||
|
||||
void
|
||||
cairo_surface_destroy (cairo_surface_t *surface);
|
||||
|
||||
/* XXX: Should this take an X/Y offset as well? (Probably) */
|
||||
cairo_status_t
|
||||
cairo_surface_put_image (cairo_surface_t *surface,
|
||||
char *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
/* XXX: The Xc version of this function isn't quite working yet
|
||||
cairo_status_t
|
||||
cairo_surface_set_clip_region (cairo_surface_t *surface, Region region);
|
||||
*/
|
||||
|
||||
/* XXX: Note: The current Render/Ic implementations don't do the right
|
||||
thing with repeat when the surface has a non-identity matrix. */
|
||||
cairo_status_t
|
||||
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat);
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
|
||||
|
||||
typedef enum cairo_filter_t {
|
||||
CAIRO_FILTER_FAST = XcFilterFast,
|
||||
CAIRO_FILTER_GOOD = XcFilterGood,
|
||||
CAIRO_FILTER_BEST = XcFilterBest,
|
||||
CAIRO_FILTER_NEAREST = XcFilterNearest,
|
||||
CAIRO_FILTER_BILINEAR = XcFilterBilinear
|
||||
} cairo_filter_t;
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter);
|
||||
|
||||
/* Matrix functions */
|
||||
|
||||
cairo_matrix_t *
|
||||
cairo_matrix_create (void);
|
||||
|
||||
void
|
||||
cairo_matrix_destroy (cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_set_identity (cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_set_affine (cairo_matrix_t *cr,
|
||||
double a, double b,
|
||||
double c, double d,
|
||||
double tx, double ty);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_get_affine (cairo_matrix_t *matrix,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_invert (cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
80
src/cairo_color.c
Normal file
80
src/cairo_color.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_color_t CAIRO_COLOR_DEFAULT = { 1.0, 1.0, 1.0, 1.0, {0xffff, 0xffff, 0xffff, 0xffff}};
|
||||
|
||||
static void
|
||||
_cairo_color_compute_xc_color (cairo_color_t *color);
|
||||
|
||||
void
|
||||
_cairo_color_init (cairo_color_t *color)
|
||||
{
|
||||
*color = CAIRO_COLOR_DEFAULT;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_fini (cairo_color_t *color)
|
||||
{
|
||||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_color_compute_xc_color (cairo_color_t *color)
|
||||
{
|
||||
color->xc_color.red = color->red * color->alpha * 0xffff;
|
||||
color->xc_color.green = color->green * color->alpha * 0xffff;
|
||||
color->xc_color.blue = color->blue * color->alpha * 0xffff;
|
||||
color->xc_color.alpha = color->alpha * 0xffff;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
|
||||
{
|
||||
color->red = red;
|
||||
color->green = green;
|
||||
color->blue = blue;
|
||||
|
||||
_cairo_color_compute_xc_color (color);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
|
||||
{
|
||||
*red = color->red;
|
||||
*green = color->green;
|
||||
*blue = color->blue;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_color_set_alpha (cairo_color_t *color, double alpha)
|
||||
{
|
||||
color->alpha = alpha;
|
||||
|
||||
_cairo_color_compute_xc_color (color);
|
||||
}
|
||||
171
src/cairo_font.c
Normal file
171
src/cairo_font.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
void
|
||||
_cairo_font_init (cairo_font_t *font)
|
||||
{
|
||||
font->key = (unsigned char *) strdup (CAIRO_FONT_KEY_DEFAULT);
|
||||
|
||||
font->dpy = NULL;
|
||||
font->xft_font = NULL;
|
||||
|
||||
cairo_matrix_set_identity (&font->matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other)
|
||||
{
|
||||
*font = *other;
|
||||
|
||||
if (other->key) {
|
||||
font->key = (unsigned char *) strdup ((char *) other->key);
|
||||
if (font->key == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (other->xft_font) {
|
||||
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
|
||||
if (font->xft_font == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_font_fini (cairo_font_t *font)
|
||||
{
|
||||
if (font->key)
|
||||
free (font->key);
|
||||
font->key = NULL;
|
||||
|
||||
_cairo_matrix_fini (&font->matrix);
|
||||
|
||||
if (font->xft_font)
|
||||
XftFontClose (font->dpy, font->xft_font);
|
||||
font->xft_font = NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_select (cairo_font_t *font, const char *key)
|
||||
{
|
||||
if (font->xft_font)
|
||||
XftFontClose (font->dpy, font->xft_font);
|
||||
font->xft_font = NULL;
|
||||
|
||||
if (font->key)
|
||||
free (font->key);
|
||||
|
||||
font->key = (unsigned char *) strdup ((char *) key);
|
||||
if (font->key == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_scale (cairo_font_t *font, double scale)
|
||||
{
|
||||
cairo_matrix_scale (&font->matrix, scale, scale);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_font_transform (cairo_font_t *font,
|
||||
double a, double b,
|
||||
double c, double d)
|
||||
{
|
||||
cairo_matrix_t m;
|
||||
|
||||
cairo_matrix_set_affine (&m, a, b, c, d, 0, 0);
|
||||
cairo_matrix_multiply (&font->matrix, &m, &font->matrix);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font)
|
||||
{
|
||||
FcPattern *pattern;
|
||||
FcPattern *match;
|
||||
FcResult result;
|
||||
cairo_matrix_t matrix;
|
||||
FcMatrix fc_matrix;
|
||||
double expansion;
|
||||
double font_size;
|
||||
|
||||
if (font->xft_font) {
|
||||
*xft_font = font->xft_font;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
pattern = FcNameParse (font->key);
|
||||
|
||||
matrix = gstate->ctm;
|
||||
|
||||
cairo_matrix_multiply (&matrix, &font->matrix, &matrix);
|
||||
|
||||
/* Pull the scale factor out of the final matrix and use it to set
|
||||
the direct pixelsize of the font. This enables freetype to
|
||||
perform proper hinting at any size. */
|
||||
|
||||
/* XXX: The determinant gives an area expansion factor, so the
|
||||
math below should be correct for the (common) case of uniform
|
||||
X/Y scaling. Is there anything different we would want to do
|
||||
for non-uniform X/Y scaling? */
|
||||
_cairo_matrix_compute_determinant (&matrix, &expansion);
|
||||
font_size = sqrt (expansion);
|
||||
FcPatternAddDouble (pattern, "pixelsize", font_size);
|
||||
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
|
||||
|
||||
fc_matrix.xx = matrix.m[0][0];
|
||||
fc_matrix.xy = matrix.m[0][1];
|
||||
fc_matrix.yx = matrix.m[1][0];
|
||||
fc_matrix.yy = matrix.m[1][1];
|
||||
|
||||
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
|
||||
|
||||
/* XXX: Need to abandon Xft and use Xc instead */
|
||||
/* When I do that I can throw away these Display pointers */
|
||||
font->dpy = gstate->surface->dpy;
|
||||
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
|
||||
if (!match)
|
||||
return 0;
|
||||
|
||||
font->xft_font = XftFontOpenPattern (font->dpy, match);
|
||||
|
||||
*xft_font = font->xft_font;
|
||||
|
||||
FcPatternDestroy (pattern);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
1123
src/cairo_gstate.c
Normal file
1123
src/cairo_gstate.c
Normal file
File diff suppressed because it is too large
Load diff
380
src/cairo_matrix.c
Normal file
380
src/cairo_matrix.c
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_matrix_t CAIRO_MATRIX_IDENTITY = {
|
||||
{
|
||||
{1, 0},
|
||||
{0, 1},
|
||||
{0, 0}
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
|
||||
|
||||
static void
|
||||
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
|
||||
|
||||
cairo_matrix_t *
|
||||
cairo_matrix_create (void)
|
||||
{
|
||||
cairo_matrix_t *matrix;
|
||||
|
||||
matrix = malloc (sizeof (cairo_matrix_t));
|
||||
if (matrix == NULL)
|
||||
return NULL;
|
||||
|
||||
_cairo_matrix_init (matrix);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_matrix_init (cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_set_identity (matrix);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_matrix_fini (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
void
|
||||
cairo_matrix_destroy (cairo_matrix_t *matrix)
|
||||
{
|
||||
_cairo_matrix_fini (matrix);
|
||||
free (matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
|
||||
{
|
||||
*matrix = *other;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_set_identity (cairo_matrix_t *matrix)
|
||||
{
|
||||
*matrix = CAIRO_MATRIX_IDENTITY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_set_affine (cairo_matrix_t *matrix,
|
||||
double a, double b,
|
||||
double c, double d,
|
||||
double tx, double ty)
|
||||
{
|
||||
matrix->m[0][0] = a; matrix->m[0][1] = b;
|
||||
matrix->m[1][0] = c; matrix->m[1][1] = d;
|
||||
matrix->m[2][0] = tx; matrix->m[2][1] = ty;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_get_affine (cairo_matrix_t *matrix,
|
||||
double *a, double *b,
|
||||
double *c, double *d,
|
||||
double *tx, double *ty)
|
||||
{
|
||||
*a = matrix->m[0][0]; *b = matrix->m[0][1];
|
||||
*c = matrix->m[1][0]; *d = matrix->m[1][1];
|
||||
*tx = matrix->m[2][0]; *ty = matrix->m[2][1];
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
|
||||
double tx, double ty)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
1, 0,
|
||||
0, 1,
|
||||
tx, ty);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_translate (&tmp, tx, ty);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
|
||||
double sx, double sy)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
sx, 0,
|
||||
0, sy,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_scale (&tmp, sx, sy);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
|
||||
double radians)
|
||||
{
|
||||
return cairo_matrix_set_affine (matrix,
|
||||
cos (radians), sin (radians),
|
||||
-sin (radians), cos (radians),
|
||||
0, 0);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
|
||||
_cairo_matrix_set_rotate (&tmp, radians);
|
||||
|
||||
return cairo_matrix_multiply (matrix, &tmp, matrix);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
|
||||
{
|
||||
cairo_matrix_t r;
|
||||
int row, col, n;
|
||||
double t;
|
||||
|
||||
for (row = 0; row < 3; row++) {
|
||||
for (col = 0; col < 2; col++) {
|
||||
if (row == 2)
|
||||
t = b->m[2][col];
|
||||
else
|
||||
t = 0;
|
||||
for (n = 0; n < 2; n++) {
|
||||
t += a->m[row][n] * b->m[n][col];
|
||||
}
|
||||
r.m[row][col] = t;
|
||||
}
|
||||
}
|
||||
|
||||
*result = r;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
|
||||
{
|
||||
double new_x, new_y;
|
||||
|
||||
new_x = (matrix->m[0][0] * *dx
|
||||
+ matrix->m[1][0] * *dy);
|
||||
new_y = (matrix->m[0][1] * *dx
|
||||
+ matrix->m[1][1] * *dy);
|
||||
|
||||
*dx = new_x;
|
||||
*dy = new_y;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
|
||||
{
|
||||
cairo_matrix_transform_distance (matrix, x, y);
|
||||
|
||||
*x += matrix->m[2][0];
|
||||
*y += matrix->m[2][1];
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
|
||||
double *x, double *y,
|
||||
double *width, double *height)
|
||||
{
|
||||
int i;
|
||||
double quad_x[4], quad_y[4];
|
||||
double dx1, dy1;
|
||||
double dx2, dy2;
|
||||
double min_x, max_x;
|
||||
double min_y, max_y;
|
||||
|
||||
quad_x[0] = *x;
|
||||
quad_y[0] = *y;
|
||||
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
|
||||
|
||||
dx1 = *width;
|
||||
dy1 = 0;
|
||||
cairo_matrix_transform_distance (matrix, &dx1, &dy1);
|
||||
quad_x[1] = quad_x[0] + dx1;
|
||||
quad_y[1] = quad_y[0] + dy1;
|
||||
|
||||
dx2 = 0;
|
||||
dy2 = *height;
|
||||
cairo_matrix_transform_distance (matrix, &dx2, &dy2);
|
||||
quad_x[2] = quad_x[0] + dx2;
|
||||
quad_y[2] = quad_y[0] + dy2;
|
||||
|
||||
quad_x[3] = quad_x[0] + dx1 + dx2;
|
||||
quad_y[3] = quad_y[0] + dy1 + dy2;
|
||||
|
||||
min_x = max_x = quad_x[0];
|
||||
min_y = max_y = quad_y[0];
|
||||
|
||||
for (i=1; i < 4; i++) {
|
||||
if (quad_x[i] < min_x)
|
||||
min_x = quad_x[i];
|
||||
if (quad_x[i] > max_x)
|
||||
max_x = quad_x[i];
|
||||
|
||||
if (quad_y[i] < min_y)
|
||||
min_y = quad_y[i];
|
||||
if (quad_y[i] > max_y)
|
||||
max_y = quad_y[i];
|
||||
}
|
||||
|
||||
*x = min_x;
|
||||
*y = min_y;
|
||||
*width = max_x - min_x;
|
||||
*height = max_y - min_y;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
|
||||
{
|
||||
int row, col;
|
||||
|
||||
for (row = 0; row < 3; row++)
|
||||
for (col = 0; col < 2; col++)
|
||||
matrix->m[row][col] *= scalar;
|
||||
}
|
||||
|
||||
/* This function isn't a correct adjoint in that the implicit 1 in the
|
||||
homogeneous result should actually be ad-bc instead. But, since this
|
||||
adjoint is only used in the computation of the inverse, which
|
||||
divides by det (A)=ad-bc anyway, everything works out in the end. */
|
||||
static void
|
||||
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* adj (A) = transpose (C:cofactor (A,i,j)) */
|
||||
double a, b, c, d, tx, ty;
|
||||
|
||||
a = matrix->m[0][0]; b = matrix->m[0][1];
|
||||
c = matrix->m[1][0]; d = matrix->m[1][1];
|
||||
tx = matrix->m[2][0]; ty = matrix->m[2][1];
|
||||
|
||||
cairo_matrix_set_affine (matrix,
|
||||
d, -b,
|
||||
-c, a,
|
||||
c*ty - d*tx, b*tx - a*ty);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_invert (cairo_matrix_t *matrix)
|
||||
{
|
||||
/* inv (A) = 1/det (A) * adj (A) */
|
||||
double det;
|
||||
|
||||
_cairo_matrix_compute_determinant (matrix, &det);
|
||||
|
||||
if (det == 0)
|
||||
return CAIRO_STATUS_INVALID_MATRIX;
|
||||
|
||||
_cairo_matrix_compute_adjoint (matrix);
|
||||
_cairo_matrix_scalar_multiply (matrix, 1 / det);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
|
||||
{
|
||||
double a, b, c, d;
|
||||
|
||||
a = matrix->m[0][0]; b = matrix->m[0][1];
|
||||
c = matrix->m[1][0]; d = matrix->m[1][1];
|
||||
|
||||
*det = a*d - b*c;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
|
||||
{
|
||||
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
|
||||
|
||||
det (M - lI) = 0
|
||||
|
||||
The zeros in our homogeneous 3x3 matrix make this equation equal
|
||||
to that formed by the sub-matrix:
|
||||
|
||||
M = a b
|
||||
c d
|
||||
|
||||
by which:
|
||||
|
||||
l^2 - (a+d)l + (ad - bc) = 0
|
||||
|
||||
l = (a+d +/- sqrt (a^2 + 2ad + d^2 - 4 (ad-bc))) / 2;
|
||||
*/
|
||||
|
||||
double a, b, c, d, rad;
|
||||
|
||||
a = matrix->m[0][0];
|
||||
b = matrix->m[0][1];
|
||||
c = matrix->m[1][0];
|
||||
d = matrix->m[1][1];
|
||||
|
||||
rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
|
||||
*lambda1 = (a + d + rad) / 2.0;
|
||||
*lambda2 = (a + d - rad) / 2.0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
36
src/cairo_misc.c
Normal file
36
src/cairo_misc.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
void
|
||||
_compute_slope (XPointFixed *a, XPointFixed *b, cairo_slope_fixed_t *slope)
|
||||
{
|
||||
slope->dx = b->x - a->x;
|
||||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
436
src/cairo_path.c
Normal file
436
src/cairo_path.c
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "cairoint.h"
|
||||
|
||||
/* private functions */
|
||||
static cairo_status_t
|
||||
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts);
|
||||
|
||||
static void
|
||||
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_op_buf (cairo_path_t *path);
|
||||
|
||||
static void
|
||||
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_arg_buf (cairo_path_t *path);
|
||||
|
||||
static cairo_path_op_buf_t *
|
||||
_cairo_path_op_buf_create (void);
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *buf);
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op);
|
||||
|
||||
static cairo_path_arg_buf_t *
|
||||
_cairo_path_arg_buf_create (void);
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *buf);
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts);
|
||||
|
||||
void
|
||||
_cairo_path_init (cairo_path_t *path)
|
||||
{
|
||||
path->op_head = NULL;
|
||||
path->op_tail = NULL;
|
||||
|
||||
path->arg_head = NULL;
|
||||
path->arg_tail = NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
|
||||
{
|
||||
cairo_path_op_buf_t *op, *other_op;
|
||||
cairo_path_arg_buf_t *arg, *other_arg;
|
||||
|
||||
_cairo_path_init (path);
|
||||
|
||||
for (other_op = other->op_head; other_op; other_op = other_op->next) {
|
||||
op = _cairo_path_op_buf_create ();
|
||||
if (op == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
*op = *other_op;
|
||||
_cairo_path_add_op_buf (path, op);
|
||||
}
|
||||
|
||||
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
|
||||
arg = _cairo_path_arg_buf_create ();
|
||||
if (arg == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
*arg = *other_arg;
|
||||
_cairo_path_add_arg_buf (path, arg);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_path_fini (cairo_path_t *path)
|
||||
{
|
||||
cairo_path_op_buf_t *op;
|
||||
cairo_path_arg_buf_t *arg;
|
||||
|
||||
while (path->op_head) {
|
||||
op = path->op_head;
|
||||
path->op_head = op->next;
|
||||
_cairo_path_op_buf_destroy (op);
|
||||
}
|
||||
path->op_tail = NULL;
|
||||
|
||||
while (path->arg_head) {
|
||||
arg = path->arg_head;
|
||||
path->arg_head = arg->next;
|
||||
_cairo_path_arg_buf_destroy (arg);
|
||||
}
|
||||
path->arg_tail = NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_move_to (cairo_path_t *path, double x, double y)
|
||||
{
|
||||
XPointFixed pt;
|
||||
|
||||
pt.x = XDoubleToFixed (x);
|
||||
pt.y = XDoubleToFixed (y);
|
||||
|
||||
return _cairo_path_add (path, cairo_path_op_move_to, &pt, 1);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_line_to (cairo_path_t *path, double x, double y)
|
||||
{
|
||||
XPointFixed pt;
|
||||
|
||||
pt.x = XDoubleToFixed (x);
|
||||
pt.y = XDoubleToFixed (y);
|
||||
|
||||
return _cairo_path_add (path, cairo_path_op_line_to, &pt, 1);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_curve_to (cairo_path_t *path,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
XPointFixed pt[3];
|
||||
|
||||
pt[0].x = XDoubleToFixed (x1);
|
||||
pt[0].y = XDoubleToFixed (y1);
|
||||
|
||||
pt[1].x = XDoubleToFixed (x2);
|
||||
pt[1].y = XDoubleToFixed (y2);
|
||||
|
||||
pt[2].x = XDoubleToFixed (x3);
|
||||
pt[2].y = XDoubleToFixed (y3);
|
||||
|
||||
return _cairo_path_add (path, cairo_path_op_curve_to, pt, 3);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_close_path (cairo_path_t *path)
|
||||
{
|
||||
return _cairo_path_add (path, cairo_path_op_close_path, NULL, 0);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_add (cairo_path_t *path, cairo_path_op op, XPointFixed *pts, int num_pts)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (path->op_tail == NULL || path->op_tail->num_ops + 1 > CAIRO_PATH_BUF_SZ) {
|
||||
status = _cairo_path_new_op_buf (path);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
_cairo_path_op_buf_add (path->op_tail, op);
|
||||
|
||||
if (path->arg_tail == NULL || path->arg_tail->num_pts + num_pts > CAIRO_PATH_BUF_SZ) {
|
||||
status = _cairo_path_new_arg_buf (path);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
_cairo_path_arg_buf_add (path->arg_tail, pts, num_pts);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op)
|
||||
{
|
||||
op->next = NULL;
|
||||
op->prev = path->op_tail;
|
||||
|
||||
if (path->op_tail) {
|
||||
path->op_tail->next = op;
|
||||
} else {
|
||||
path->op_head = op;
|
||||
}
|
||||
|
||||
path->op_tail = op;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_op_buf (cairo_path_t *path)
|
||||
{
|
||||
cairo_path_op_buf_t *op;
|
||||
|
||||
op = _cairo_path_op_buf_create ();
|
||||
if (op == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
_cairo_path_add_op_buf (path, op);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
|
||||
{
|
||||
arg->next = NULL;
|
||||
arg->prev = path->arg_tail;
|
||||
|
||||
if (path->arg_tail) {
|
||||
path->arg_tail->next = arg;
|
||||
} else {
|
||||
path->arg_head = arg;
|
||||
}
|
||||
|
||||
path->arg_tail = arg;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_new_arg_buf (cairo_path_t *path)
|
||||
{
|
||||
cairo_path_arg_buf_t *arg;
|
||||
|
||||
arg = _cairo_path_arg_buf_create ();
|
||||
|
||||
if (arg == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
_cairo_path_add_arg_buf (path, arg);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_path_op_buf_t *
|
||||
_cairo_path_op_buf_create (void)
|
||||
{
|
||||
cairo_path_op_buf_t *op;
|
||||
|
||||
op = malloc (sizeof (cairo_path_op_buf_t));
|
||||
|
||||
if (op) {
|
||||
op->num_ops = 0;
|
||||
op->next = NULL;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
|
||||
{
|
||||
free (op);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op op)
|
||||
{
|
||||
op_buf->op[op_buf->num_ops++] = op;
|
||||
}
|
||||
|
||||
static cairo_path_arg_buf_t *
|
||||
_cairo_path_arg_buf_create (void)
|
||||
{
|
||||
cairo_path_arg_buf_t *arg;
|
||||
|
||||
arg = malloc (sizeof (cairo_path_arg_buf_t));
|
||||
|
||||
if (arg) {
|
||||
arg->num_pts = 0;
|
||||
arg->next = NULL;
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
|
||||
{
|
||||
free (arg);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, XPointFixed *pts, int num_pts)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_pts; i++) {
|
||||
arg->pt[arg->num_pts++] = pts[i];
|
||||
}
|
||||
}
|
||||
|
||||
#define CAIRO_PATH_OP_MAX_ARGS 3
|
||||
|
||||
static int num_args[] =
|
||||
{
|
||||
1, /* cairo_path_move_to */
|
||||
1, /* cairo_path_op_line_to */
|
||||
3, /* cairo_path_op_curve_to */
|
||||
0, /* cairo_path_op_close_path */
|
||||
};
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_interpret (cairo_path_t *path, cairo_path_direction dir, const cairo_path_callbacks_t *cb, void *closure)
|
||||
{
|
||||
cairo_status_t status;
|
||||
int i, arg;
|
||||
cairo_path_op_buf_t *op_buf;
|
||||
cairo_path_op op;
|
||||
cairo_path_arg_buf_t *arg_buf = path->arg_head;
|
||||
int buf_i = 0;
|
||||
XPointFixed pt[CAIRO_PATH_OP_MAX_ARGS];
|
||||
XPointFixed current = {0, 0};
|
||||
XPointFixed first = {0, 0};
|
||||
int has_current = 0;
|
||||
int has_edge = 0;
|
||||
int step = (dir == cairo_path_direction_forward) ? 1 : -1;
|
||||
|
||||
for (op_buf = (dir == cairo_path_direction_forward) ? path->op_head : path->op_tail;
|
||||
op_buf;
|
||||
op_buf = (dir == cairo_path_direction_forward) ? op_buf->next : op_buf->prev)
|
||||
{
|
||||
int start, stop;
|
||||
if (dir == cairo_path_direction_forward) {
|
||||
start = 0;
|
||||
stop = op_buf->num_ops;
|
||||
} else {
|
||||
start = op_buf->num_ops - 1;
|
||||
stop = -1;
|
||||
}
|
||||
|
||||
for (i=start; i != stop; i += step) {
|
||||
op = op_buf->op[i];
|
||||
|
||||
if (dir == cairo_path_direction_reverse) {
|
||||
if (buf_i == 0) {
|
||||
arg_buf = arg_buf->prev;
|
||||
buf_i = arg_buf->num_pts;
|
||||
}
|
||||
buf_i -= num_args[op];
|
||||
}
|
||||
|
||||
for (arg = 0; arg < num_args[op]; arg++) {
|
||||
pt[arg] = arg_buf->pt[buf_i];
|
||||
buf_i++;
|
||||
if (buf_i >= arg_buf->num_pts) {
|
||||
arg_buf = arg_buf->next;
|
||||
buf_i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == cairo_path_direction_reverse) {
|
||||
buf_i -= num_args[op];
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case cairo_path_op_move_to:
|
||||
if (has_edge) {
|
||||
status = (*cb->DoneSubPath) (closure, cairo_sub_path_done_cap);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
first = pt[0];
|
||||
current = pt[0];
|
||||
has_current = 1;
|
||||
has_edge = 0;
|
||||
break;
|
||||
case cairo_path_op_line_to:
|
||||
if (has_current) {
|
||||
status = (*cb->AddEdge) (closure, ¤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);
|
||||
}
|
||||
|
||||
|
||||
168
src/cairo_path_bounds.c
Normal file
168
src/cairo_path_bounds.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright © 2003 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct _cairo_path_bounder {
|
||||
int has_pt;
|
||||
|
||||
XFixed min_x;
|
||||
XFixed min_y;
|
||||
XFixed max_x;
|
||||
XFixed max_y;
|
||||
} cairo_path_bounder;
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_init (cairo_path_bounder *bounder);
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_fini (cairo_path_bounder *bounder);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_spline (void *closure,
|
||||
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done done);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_path (void *closure);
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_init (cairo_path_bounder *bounder)
|
||||
{
|
||||
bounder->has_pt = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_path_bounder_fini (cairo_path_bounder *bounder)
|
||||
{
|
||||
bounder->has_pt = 0;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_point (cairo_path_bounder *bounder, XPointFixed *pt)
|
||||
{
|
||||
if (bounder->has_pt) {
|
||||
if (pt->x < bounder->min_x)
|
||||
bounder->min_x = pt->x;
|
||||
|
||||
if (pt->y < bounder->min_y)
|
||||
bounder->min_y = pt->y;
|
||||
|
||||
if (pt->x > bounder->max_x)
|
||||
bounder->max_x = pt->x;
|
||||
|
||||
if (pt->y > bounder->max_y)
|
||||
bounder->max_y = pt->y;
|
||||
} else {
|
||||
bounder->min_x = pt->x;
|
||||
bounder->min_y = pt->y;
|
||||
bounder->max_x = pt->x;
|
||||
bounder->max_y = pt->y;
|
||||
|
||||
bounder->has_pt = 1;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_path_bounder *bounder = closure;
|
||||
|
||||
_cairo_path_bounder_add_point (bounder, p1);
|
||||
_cairo_path_bounder_add_point (bounder, p2);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_add_spline (void *closure,
|
||||
XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
cairo_path_bounder *bounder = closure;
|
||||
|
||||
_cairo_path_bounder_add_point (bounder, a);
|
||||
_cairo_path_bounder_add_point (bounder, b);
|
||||
_cairo_path_bounder_add_point (bounder, c);
|
||||
_cairo_path_bounder_add_point (bounder, d);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done done)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_done_path (void *closure)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
|
||||
cairo_status_t
|
||||
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
static cairo_path_callbacks_t cb = {
|
||||
_cairo_path_bounder_add_edge,
|
||||
_cairo_path_bounder_add_spline,
|
||||
_cairo_path_bounder_done_sub_path,
|
||||
_cairo_path_bounder_done_path
|
||||
};
|
||||
|
||||
cairo_path_bounder bounder;
|
||||
|
||||
_cairo_path_bounder_init (&bounder);
|
||||
|
||||
status = _cairo_path_interpret (path, cairo_path_direction_forward, &cb, &bounder);
|
||||
if (status) {
|
||||
*x1 = *y1 = *x2 = *y2 = 0.0;
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
return status;
|
||||
}
|
||||
|
||||
*x1 = XFixedToDouble (bounder.min_x);
|
||||
*y1 = XFixedToDouble (bounder.min_y);
|
||||
*x2 = XFixedToDouble (bounder.max_x);
|
||||
*y2 = XFixedToDouble (bounder.max_y);
|
||||
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
158
src/cairo_path_fill.c
Normal file
158
src/cairo_path_fill.c
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct _cairo_filler {
|
||||
cairo_gstate_t *gstate;
|
||||
cairo_traps_t *traps;
|
||||
|
||||
cairo_polygon_t polygon;
|
||||
} cairo_filler;
|
||||
|
||||
static void
|
||||
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
|
||||
|
||||
static void
|
||||
_cairo_filler_fini (cairo_filler *filler);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_path (void *closure);
|
||||
|
||||
static void
|
||||
_cairo_filler_init (cairo_filler *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
filler->gstate = gstate;
|
||||
filler->traps = traps;
|
||||
|
||||
_cairo_polygon_init (&filler->polygon);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_filler_fini (cairo_filler *filler)
|
||||
{
|
||||
_cairo_polygon_fini (&filler->polygon);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_filler *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
|
||||
return _cairo_polygon_add_edge (polygon, p1, p2);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
int i;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_filler *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
cairo_gstate_t *gstate = filler->gstate;
|
||||
cairo_spline_t spline;
|
||||
|
||||
status = _cairo_spline_init (&spline, a, b, c, d);
|
||||
if (status == cairo_int_status_degenerate)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_cairo_spline_decompose (&spline, gstate->tolerance);
|
||||
if (status)
|
||||
goto CLEANUP_SPLINE;
|
||||
|
||||
for (i = 0; i < spline.num_pts - 1; i++) {
|
||||
status = _cairo_polygon_add_edge (polygon, &spline.pts[i], &spline.pts[i+1]);
|
||||
if (status)
|
||||
goto CLEANUP_SPLINE;
|
||||
}
|
||||
|
||||
CLEANUP_SPLINE:
|
||||
_cairo_spline_fini (&spline);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done done)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_filler *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
|
||||
_cairo_polygon_close (polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_filler_done_path (void *closure)
|
||||
{
|
||||
cairo_filler *filler = closure;
|
||||
|
||||
return cairo_traps_tessellate_polygon (filler->traps,
|
||||
&filler->polygon,
|
||||
filler->gstate->fill_rule);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
static const cairo_path_callbacks_t filler_callbacks = {
|
||||
_cairo_filler_add_edge,
|
||||
_cairo_filler_add_spline,
|
||||
_cairo_filler_done_sub_path,
|
||||
_cairo_filler_done_path
|
||||
};
|
||||
|
||||
cairo_status_t status;
|
||||
cairo_filler filler;
|
||||
|
||||
_cairo_filler_init (&filler, gstate, traps);
|
||||
|
||||
status = _cairo_path_interpret (path,
|
||||
cairo_path_direction_forward,
|
||||
&filler_callbacks, &filler);
|
||||
if (status) {
|
||||
_cairo_filler_fini (&filler);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_filler_fini (&filler);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
715
src/cairo_path_stroke.c
Normal file
715
src/cairo_path_stroke.c
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct _cairo_stroker {
|
||||
cairo_gstate_t *gstate;
|
||||
cairo_traps_t *traps;
|
||||
|
||||
int have_prev;
|
||||
int have_first;
|
||||
int is_first;
|
||||
cairo_stroke_face_t prev;
|
||||
cairo_stroke_face_t first;
|
||||
int dash_index;
|
||||
int dash_on;
|
||||
double dash_remain;
|
||||
} cairo_stroker;
|
||||
|
||||
/* private functions */
|
||||
static void
|
||||
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps);
|
||||
|
||||
static void
|
||||
_cairo_stroker_fini (cairo_stroker *stroker);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_path (void *closure);
|
||||
|
||||
static void
|
||||
_translate_point (XPointFixed *pt, XPointFixed *offset);
|
||||
|
||||
static int
|
||||
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
|
||||
|
||||
static void
|
||||
_cairo_stroker_start_dash (cairo_stroker *stroker)
|
||||
{
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
double offset;
|
||||
int on = 1;
|
||||
int i = 0;
|
||||
|
||||
offset = gstate->dash_offset;
|
||||
while (offset >= gstate->dash[i]) {
|
||||
offset -= gstate->dash[i];
|
||||
on = 1-on;
|
||||
if (++i == gstate->num_dashes)
|
||||
i = 0;
|
||||
}
|
||||
stroker->dash_index = i;
|
||||
stroker->dash_on = on;
|
||||
stroker->dash_remain = gstate->dash[i] - offset;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_stroker_step_dash (cairo_stroker *stroker, double step)
|
||||
{
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
stroker->dash_remain -= step;
|
||||
if (stroker->dash_remain <= 0) {
|
||||
stroker->dash_index++;
|
||||
if (stroker->dash_index == gstate->num_dashes)
|
||||
stroker->dash_index = 0;
|
||||
stroker->dash_on = 1-stroker->dash_on;
|
||||
stroker->dash_remain = gstate->dash[stroker->dash_index];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_stroker_init (cairo_stroker *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
stroker->gstate = gstate;
|
||||
stroker->traps = traps;
|
||||
stroker->have_prev = 0;
|
||||
stroker->have_first = 0;
|
||||
stroker->is_first = 1;
|
||||
if (gstate->dash)
|
||||
_cairo_stroker_start_dash (stroker);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_stroker_fini (cairo_stroker *stroker)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
static void
|
||||
_translate_point (XPointFixed *pt, XPointFixed *offset)
|
||||
{
|
||||
pt->x += offset->x;
|
||||
pt->y += offset->y;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
|
||||
{
|
||||
XPointDouble d_in, d_out;
|
||||
|
||||
d_in.x = XFixedToDouble (in->cw.x - in->pt.x);
|
||||
d_in.y = XFixedToDouble (in->cw.y - in->pt.y);
|
||||
d_out.x = XFixedToDouble (out->cw.x - out->pt.x);
|
||||
d_out.y = XFixedToDouble (out->cw.y - out->pt.y);
|
||||
|
||||
return d_out.y * d_in.x > d_in.y * d_out.x;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_join (cairo_stroker *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
int clockwise = _cairo_stroker_face_clockwise (out, in);
|
||||
XPointFixed *inpt, *outpt;
|
||||
|
||||
if (in->cw.x == out->cw.x
|
||||
&& in->cw.y == out->cw.y
|
||||
&& in->ccw.x == out->ccw.x
|
||||
&& in->ccw.y == out->ccw.y) {
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (clockwise) {
|
||||
inpt = &in->ccw;
|
||||
outpt = &out->ccw;
|
||||
} else {
|
||||
inpt = &in->cw;
|
||||
outpt = &out->cw;
|
||||
}
|
||||
|
||||
switch (gstate->line_join) {
|
||||
case CAIRO_LINE_JOIN_ROUND: {
|
||||
int i;
|
||||
int start, step, stop;
|
||||
XPointFixed tri[3], initial, final;
|
||||
cairo_pen_t *pen = &gstate->pen_regular;
|
||||
|
||||
tri[0] = in->pt;
|
||||
if (clockwise) {
|
||||
initial = in->ccw;
|
||||
_cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
|
||||
step = -1;
|
||||
_cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
|
||||
final = out->ccw;
|
||||
} else {
|
||||
initial = in->cw;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
|
||||
step = +1;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
|
||||
final = out->cw;
|
||||
}
|
||||
|
||||
i = start;
|
||||
tri[1] = initial;
|
||||
while (i != stop) {
|
||||
tri[2] = in->pt;
|
||||
_translate_point (&tri[2], &pen->vertex[i].pt);
|
||||
cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
i += step;
|
||||
if (i < 0)
|
||||
i = pen->num_vertices - 1;
|
||||
if (i >= pen->num_vertices)
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tri[2] = final;
|
||||
|
||||
return cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
}
|
||||
case CAIRO_LINE_JOIN_MITER:
|
||||
default: {
|
||||
cairo_polygon_t polygon;
|
||||
XDouble c = (-in->usr_vector.x * out->usr_vector.x)+(-in->usr_vector.y * out->usr_vector.y);
|
||||
XDouble ml = gstate->miter_limit;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
if (2 <= ml * ml * (1 - c)) {
|
||||
XDouble x1, y1, x2, y2;
|
||||
XDouble mx, my;
|
||||
XDouble dx1, dx2, dy1, dy2;
|
||||
XPointFixed outer;
|
||||
|
||||
x1 = XFixedToDouble (inpt->x);
|
||||
y1 = XFixedToDouble (inpt->y);
|
||||
dx1 = in->usr_vector.x;
|
||||
dy1 = in->usr_vector.y;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
|
||||
|
||||
x2 = XFixedToDouble (outpt->x);
|
||||
y2 = XFixedToDouble (outpt->y);
|
||||
dx2 = out->usr_vector.x;
|
||||
dy2 = out->usr_vector.y;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
|
||||
|
||||
my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
|
||||
(dx1 * dy2 - dx2 * dy1));
|
||||
if (dy1)
|
||||
mx = (my - y1) * dx1 / dy1 + x1;
|
||||
else
|
||||
mx = (my - y2) * dx2 / dy2 + x2;
|
||||
|
||||
outer.x = XDoubleToFixed (mx);
|
||||
outer.y = XDoubleToFixed (my);
|
||||
_cairo_polygon_add_edge (&polygon, &in->pt, inpt);
|
||||
_cairo_polygon_add_edge (&polygon, inpt, &outer);
|
||||
_cairo_polygon_add_edge (&polygon, &outer, outpt);
|
||||
_cairo_polygon_add_edge (&polygon, outpt, &in->pt);
|
||||
status = cairo_traps_tessellate_polygon (stroker->traps,
|
||||
&polygon,
|
||||
CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
/* fall through ... */
|
||||
}
|
||||
case CAIRO_LINE_JOIN_BEVEL: {
|
||||
XPointFixed tri[3];
|
||||
tri[0] = in->pt;
|
||||
tri[1] = *inpt;
|
||||
tri[2] = *outpt;
|
||||
|
||||
return cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_cap (cairo_stroker *stroker, cairo_stroke_face_t *f)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
|
||||
if (gstate->line_cap == CAIRO_LINE_CAP_BUTT)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
switch (gstate->line_cap) {
|
||||
case CAIRO_LINE_CAP_ROUND: {
|
||||
int i;
|
||||
int start, stop;
|
||||
cairo_slope_fixed_t slope;
|
||||
XPointFixed tri[3];
|
||||
cairo_pen_t *pen = &gstate->pen_regular;
|
||||
|
||||
slope = f->dev_vector;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
|
||||
slope.dx = -slope.dx;
|
||||
slope.dy = -slope.dy;
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
|
||||
|
||||
tri[0] = f->pt;
|
||||
tri[1] = f->cw;
|
||||
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
|
||||
tri[2] = f->pt;
|
||||
_translate_point (&tri[2], &pen->vertex[i].pt);
|
||||
cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
}
|
||||
tri[2] = f->ccw;
|
||||
|
||||
return cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
}
|
||||
case CAIRO_LINE_CAP_SQUARE: {
|
||||
double dx, dy;
|
||||
cairo_slope_fixed_t fvector;
|
||||
XPointFixed occw, ocw;
|
||||
cairo_polygon_t polygon;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
dx = f->usr_vector.x;
|
||||
dy = f->usr_vector.y;
|
||||
dx *= gstate->line_width / 2.0;
|
||||
dy *= gstate->line_width / 2.0;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
fvector.dx = XDoubleToFixed (dx);
|
||||
fvector.dy = XDoubleToFixed (dy);
|
||||
occw.x = f->ccw.x + fvector.dx;
|
||||
occw.y = f->ccw.y + fvector.dy;
|
||||
ocw.x = f->cw.x + fvector.dx;
|
||||
ocw.y = f->cw.y + fvector.dy;
|
||||
|
||||
_cairo_polygon_add_edge (&polygon, &f->cw, &ocw);
|
||||
_cairo_polygon_add_edge (&polygon, &ocw, &occw);
|
||||
_cairo_polygon_add_edge (&polygon, &occw, &f->ccw);
|
||||
_cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw);
|
||||
|
||||
status = cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
case CAIRO_LINE_CAP_BUTT:
|
||||
default:
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_compute_face (XPointFixed *pt, cairo_slope_fixed_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
|
||||
{
|
||||
double mag, tmp;
|
||||
double dx, dy;
|
||||
XPointDouble usr_vector;
|
||||
XPointFixed offset_ccw, offset_cw;
|
||||
|
||||
dx = XFixedToDouble (slope->dx);
|
||||
dy = XFixedToDouble (slope->dy);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
|
||||
|
||||
mag = sqrt (dx * dx + dy * dy);
|
||||
if (mag == 0) {
|
||||
/* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
|
||||
return;
|
||||
}
|
||||
|
||||
dx /= mag;
|
||||
dy /= mag;
|
||||
|
||||
usr_vector.x = dx;
|
||||
usr_vector.y = dy;
|
||||
|
||||
tmp = dx;
|
||||
dx = - dy * (gstate->line_width / 2.0);
|
||||
dy = tmp * (gstate->line_width / 2.0);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
|
||||
offset_ccw.x = XDoubleToFixed (dx);
|
||||
offset_ccw.y = XDoubleToFixed (dy);
|
||||
offset_cw.x = -offset_ccw.x;
|
||||
offset_cw.y = -offset_ccw.y;
|
||||
|
||||
face->ccw = *pt;
|
||||
_translate_point (&face->ccw, &offset_ccw);
|
||||
|
||||
face->pt = *pt;
|
||||
|
||||
face->cw = *pt;
|
||||
_translate_point (&face->cw, &offset_cw);
|
||||
|
||||
face->usr_vector.x = usr_vector.x;
|
||||
face->usr_vector.y = usr_vector.y;
|
||||
|
||||
face->dev_vector = *slope;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_sub_edge (cairo_stroker *stroker, XPointFixed *p1, XPointFixed *p2,
|
||||
cairo_stroke_face_t *start, cairo_stroke_face_t *end)
|
||||
{
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
XPointFixed quad[4];
|
||||
cairo_slope_fixed_t slope;
|
||||
|
||||
if (p1->x == p2->x && p1->y == p2->y) {
|
||||
/* XXX: Need to rethink how this case should be handled, (both
|
||||
here and in _compute_face). The key behavior is that
|
||||
degenerate paths should draw as much as possible. */
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
_compute_slope (p1, p2, &slope);
|
||||
_compute_face (p1, &slope, gstate, start);
|
||||
|
||||
/* XXX: This could be optimized slightly by not calling
|
||||
_compute_face again but rather translating the relevant
|
||||
fields from start. */
|
||||
_compute_face (p2, &slope, gstate, end);
|
||||
|
||||
quad[0] = start->cw;
|
||||
quad[1] = start->ccw;
|
||||
quad[2] = end->ccw;
|
||||
quad[3] = end->cw;
|
||||
|
||||
return cairo_traps_tessellate_rectangle (stroker->traps, quad);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_stroker *stroker = closure;
|
||||
cairo_stroke_face_t start, end;
|
||||
|
||||
if (p1->x == p2->x && p1->y == p2->y) {
|
||||
/* XXX: Need to rethink how this case should be handled, (both
|
||||
here and in cairo_stroker_add_sub_edge and in _compute_face). The
|
||||
key behavior is that degenerate paths should draw as much
|
||||
as possible. */
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &start, &end);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
stroker->have_prev = 1;
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = start;
|
||||
}
|
||||
}
|
||||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dashed lines. Cap each dash end, join around turns when on
|
||||
*/
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_edge_dashed (void *closure, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_stroker *stroker = closure;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
double mag, remain, tmp;
|
||||
double dx, dy;
|
||||
double dx2, dy2;
|
||||
XPointFixed fd1, fd2;
|
||||
int first = 1;
|
||||
cairo_stroke_face_t sub_start, sub_end;
|
||||
|
||||
dx = XFixedToDouble (p2->x - p1->x);
|
||||
dy = XFixedToDouble (p2->y - p1->y);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
|
||||
|
||||
mag = sqrt (dx *dx + dy * dy);
|
||||
remain = mag;
|
||||
fd1 = *p1;
|
||||
while (remain) {
|
||||
tmp = stroker->dash_remain;
|
||||
if (tmp > remain)
|
||||
tmp = remain;
|
||||
remain -= tmp;
|
||||
dx2 = dx * (mag - remain)/mag;
|
||||
dy2 = dy * (mag - remain)/mag;
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
|
||||
fd2.x = XDoubleToFixed (dx2);
|
||||
fd2.y = XDoubleToFixed (dy2);
|
||||
fd2.x += p1->x;
|
||||
fd2.y += p1->y;
|
||||
/*
|
||||
* XXX simplify this case analysis
|
||||
*/
|
||||
if (stroker->dash_on) {
|
||||
status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &sub_start, &sub_end);
|
||||
if (status)
|
||||
return status;
|
||||
if (!first) {
|
||||
/*
|
||||
* Not first dash in this segment, cap start
|
||||
*/
|
||||
status = _cairo_stroker_cap (stroker, &sub_start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
/*
|
||||
* First in this segment, join to any prev, else
|
||||
* if at start of sub-path, mark position, else
|
||||
* cap
|
||||
*/
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = sub_start;
|
||||
} else {
|
||||
status = _cairo_stroker_cap (stroker, &sub_start);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remain) {
|
||||
/*
|
||||
* Cap if not at end of segment
|
||||
*/
|
||||
status = _cairo_stroker_cap (stroker, &sub_end);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
/*
|
||||
* Mark previous line face and fix up next time
|
||||
* through
|
||||
*/
|
||||
stroker->prev = sub_end;
|
||||
stroker->have_prev = 1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If starting with off dash, check previous face
|
||||
* and cap if necessary
|
||||
*/
|
||||
if (first) {
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_cap (stroker, &stroker->prev);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (!remain)
|
||||
stroker->have_prev = 0;
|
||||
}
|
||||
_cairo_stroker_step_dash (stroker, tmp);
|
||||
fd1 = fd2;
|
||||
first = 0;
|
||||
}
|
||||
stroker->is_first = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_add_spline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_stroker *stroker = closure;
|
||||
cairo_gstate_t *gstate = stroker->gstate;
|
||||
cairo_spline_t spline;
|
||||
cairo_pen_t pen;
|
||||
cairo_stroke_face_t start, end;
|
||||
XPointFixed extra_points[4];
|
||||
|
||||
status = _cairo_spline_init (&spline, a, b, c, d);
|
||||
if (status == cairo_int_status_degenerate)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
status = _cairo_pen_init_copy (&pen, &gstate->pen_regular);
|
||||
if (status)
|
||||
goto CLEANUP_SPLINE;
|
||||
|
||||
_compute_face (a, &spline.initial_slope, gstate, &start);
|
||||
_compute_face (d, &spline.final_slope, gstate, &end);
|
||||
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &start);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
stroker->have_prev = 1;
|
||||
if (stroker->is_first) {
|
||||
stroker->have_first = 1;
|
||||
stroker->first = start;
|
||||
}
|
||||
}
|
||||
stroker->prev = end;
|
||||
stroker->is_first = 0;
|
||||
|
||||
extra_points[0] = start.cw;
|
||||
extra_points[0].x -= start.pt.x;
|
||||
extra_points[0].y -= start.pt.y;
|
||||
extra_points[1] = start.ccw;
|
||||
extra_points[1].x -= start.pt.x;
|
||||
extra_points[1].y -= start.pt.y;
|
||||
extra_points[2] = end.cw;
|
||||
extra_points[2].x -= end.pt.x;
|
||||
extra_points[2].y -= end.pt.y;
|
||||
extra_points[3] = end.ccw;
|
||||
extra_points[3].x -= end.pt.x;
|
||||
extra_points[3].y -= end.pt.y;
|
||||
|
||||
status = _cairo_pen_add_points (&pen, extra_points, 4);
|
||||
if (status)
|
||||
goto CLEANUP_PEN;
|
||||
|
||||
status = _cairo_pen_stroke_spline (&pen, &spline, gstate->tolerance, stroker->traps);
|
||||
if (status)
|
||||
goto CLEANUP_PEN;
|
||||
|
||||
CLEANUP_PEN:
|
||||
_cairo_pen_fini (&pen);
|
||||
CLEANUP_SPLINE:
|
||||
_cairo_spline_fini (&spline);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done done)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_stroker *stroker = closure;
|
||||
|
||||
switch (done) {
|
||||
case cairo_sub_path_done_join:
|
||||
if (stroker->have_first && stroker->have_prev) {
|
||||
status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first);
|
||||
if (status)
|
||||
return status;
|
||||
break;
|
||||
}
|
||||
/* fall through... */
|
||||
case cairo_sub_path_done_cap:
|
||||
if (stroker->have_first) {
|
||||
XPointFixed t;
|
||||
/* The initial cap needs an outward facing vector. Reverse everything */
|
||||
stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
|
||||
stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
|
||||
stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
|
||||
stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
|
||||
t = stroker->first.cw;
|
||||
stroker->first.cw = stroker->first.ccw;
|
||||
stroker->first.ccw = t;
|
||||
status = _cairo_stroker_cap (stroker, &stroker->first);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
if (stroker->have_prev) {
|
||||
status = _cairo_stroker_cap (stroker, &stroker->prev);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stroker->have_prev = 0;
|
||||
stroker->have_first = 0;
|
||||
stroker->is_first = 1;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_stroker_done_path (void *closure)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
|
||||
{
|
||||
static const cairo_path_callbacks_t stroker_solid_cb = {
|
||||
_cairo_stroker_add_edge,
|
||||
_cairo_stroker_add_spline,
|
||||
_cairo_stroker_done_sub_path,
|
||||
_cairo_stroker_done_path
|
||||
};
|
||||
static const cairo_path_callbacks_t stroker_dashed_cb = {
|
||||
_cairo_stroker_add_edge_dashed,
|
||||
_cairo_stroker_add_spline,
|
||||
_cairo_stroker_done_sub_path,
|
||||
_cairo_stroker_done_path
|
||||
};
|
||||
const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
|
||||
|
||||
cairo_status_t status;
|
||||
cairo_stroker stroker;
|
||||
|
||||
_cairo_stroker_init (&stroker, gstate, traps);
|
||||
|
||||
status = _cairo_path_interpret (path,
|
||||
cairo_path_direction_forward,
|
||||
callbacks, &stroker);
|
||||
if (status) {
|
||||
_cairo_stroker_fini (&stroker);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_stroker_fini (&stroker);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
398
src/cairo_pen.c
Normal file
398
src/cairo_pen.c
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix);
|
||||
|
||||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen);
|
||||
|
||||
static int
|
||||
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
|
||||
|
||||
static int
|
||||
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b);
|
||||
|
||||
static int
|
||||
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_pen_stroke_direction_t dir, cairo_polygon_t *polygon);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_empty (cairo_pen_t *pen)
|
||||
{
|
||||
pen->radius = 0;
|
||||
pen->tolerance = 0;
|
||||
pen->vertex = NULL;
|
||||
pen->num_vertices = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
||||
{
|
||||
int i;
|
||||
cairo_pen_vertex *v;
|
||||
double dx, dy;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
/* XXX: It would be nice to notice that the pen is already properly constructed.
|
||||
However, this test would also have to account for possible changes in the transformation
|
||||
matrix.
|
||||
if (pen->radius == radius && pen->tolerance == tolerance)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
*/
|
||||
_cairo_pen_fini (pen);
|
||||
}
|
||||
|
||||
pen->radius = radius;
|
||||
pen->tolerance = gstate->tolerance;
|
||||
|
||||
pen->num_vertices = _cairo_pen_vertices_needed (radius, gstate->tolerance, &gstate->ctm);
|
||||
/* number of vertices must be even */
|
||||
if (pen->num_vertices % 2)
|
||||
pen->num_vertices++;
|
||||
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
if (pen->vertex == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
v = &pen->vertex[i];
|
||||
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
|
||||
dx = radius * cos (v->theta);
|
||||
dy = radius * sin (v->theta);
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
v->pt.x = XDoubleToFixed (dx);
|
||||
v->pt.y = XDoubleToFixed (dy);
|
||||
/* Recompute theta in device space */
|
||||
v->theta = atan2 (v->pt.y, v->pt.x);
|
||||
if (v->theta < 0)
|
||||
v->theta += 2 * M_PI;
|
||||
}
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_pen_fini (cairo_pen_t *pen)
|
||||
{
|
||||
free (pen->vertex);
|
||||
_cairo_pen_init_empty (pen);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
||||
{
|
||||
*pen = *other;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
if (pen->vertex == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy (pen->vertex, other->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_pen_vertex_compare_by_theta (const void *a, const void *b)
|
||||
{
|
||||
double diff;
|
||||
const cairo_pen_vertex *va = a;
|
||||
const cairo_pen_vertex *vb = b;
|
||||
|
||||
diff = va->theta - vb->theta;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
else if (diff > 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_add_points (cairo_pen_t *pen, XPointFixed *pt, int num_pts)
|
||||
{
|
||||
int i, j;
|
||||
cairo_pen_vertex *v, *v_next, *new_vertex;
|
||||
|
||||
pen->num_vertices += num_pts;
|
||||
new_vertex = realloc (pen->vertex, pen->num_vertices * sizeof (cairo_pen_vertex));
|
||||
if (new_vertex == NULL) {
|
||||
pen->num_vertices -= num_pts;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
pen->vertex = new_vertex;
|
||||
|
||||
/* initialize new vertices */
|
||||
for (i=0; i < num_pts; i++) {
|
||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||
v->pt = pt[i];
|
||||
v->theta = atan2 (v->pt.y, v->pt.x);
|
||||
if (v->theta < 0)
|
||||
v->theta += 2 * M_PI;
|
||||
}
|
||||
|
||||
qsort (pen->vertex, pen->num_vertices, sizeof (cairo_pen_vertex), _cairo_pen_vertex_compare_by_theta);
|
||||
|
||||
/* eliminate any duplicate vertices */
|
||||
for (i=0; i < pen->num_vertices - 1; i++ ) {
|
||||
v = &pen->vertex[i];
|
||||
v_next = &pen->vertex[i+1];
|
||||
if (v->pt.x == v_next->pt.x && v->pt.y == v_next->pt.y) {
|
||||
for (j=i+1; j < pen->num_vertices - 1; j++)
|
||||
pen->vertex[j] = pen->vertex[j+1];
|
||||
pen->num_vertices--;
|
||||
/* There may be more of the same duplicate, check again */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_pen_vertices_needed (double radius, double tolerance, cairo_matrix_t *matrix)
|
||||
{
|
||||
double expansion, theta;
|
||||
|
||||
/* The determinant represents the area expansion factor of the
|
||||
transform. In the worst case, this is entirely in one
|
||||
dimension, which is what we assume here. */
|
||||
|
||||
_cairo_matrix_compute_determinant (matrix, &expansion);
|
||||
|
||||
if (tolerance > expansion*radius) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
theta = acos (1 - tolerance/(expansion * radius));
|
||||
return ceil (M_PI / theta);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen)
|
||||
{
|
||||
int i, i_prev;
|
||||
cairo_pen_vertex *prev, *v, *next;
|
||||
|
||||
for (i=0, i_prev = pen->num_vertices - 1;
|
||||
i < pen->num_vertices;
|
||||
i_prev = i++) {
|
||||
prev = &pen->vertex[i_prev];
|
||||
v = &pen->vertex[i];
|
||||
next = &pen->vertex[(i + 1) % pen->num_vertices];
|
||||
|
||||
_compute_slope (&prev->pt, &v->pt, &v->slope_cw);
|
||||
_compute_slope (&v->pt, &next->pt, &v->slope_ccw);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is a clockwise of b?
|
||||
*
|
||||
* NOTE: The strict equality here is not significant in and of itself,
|
||||
* but there are functions up above that are sensitive to it,
|
||||
* (cf. _cairo_pen_find_active_cw_vertex_index).
|
||||
*/
|
||||
static int
|
||||
_slope_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
|
||||
{
|
||||
double a_dx = XFixedToDouble (a->dx);
|
||||
double a_dy = XFixedToDouble (a->dy);
|
||||
double b_dx = XFixedToDouble (b->dx);
|
||||
double b_dy = XFixedToDouble (b->dy);
|
||||
|
||||
return b_dy * a_dx > a_dy * b_dx;
|
||||
}
|
||||
|
||||
static int
|
||||
_slope_counter_clockwise (cairo_slope_fixed_t *a, cairo_slope_fixed_t *b)
|
||||
{
|
||||
return ! _slope_clockwise (a, b);
|
||||
}
|
||||
|
||||
/* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
* the inequality within _slope_clockwise/_slope_counter_clockwise.
|
||||
*
|
||||
* The issue is that the slope_ccw member of one pen vertex will be
|
||||
* equivalent to the slope_cw member of the next pen vertex in a
|
||||
* counterclockwise order. However, for this function, we care
|
||||
* strongly about which vertex is returned.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_fixed_t *slope,
|
||||
int *active)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (_slope_clockwise (slope, &pen->vertex[i].slope_ccw)
|
||||
&& _slope_counter_clockwise (slope, &pen->vertex[i].slope_cw))
|
||||
break;
|
||||
}
|
||||
|
||||
*active = i;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
* the inequality within _slope_clockwise/_slope_counter_clockwise.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_fixed_t *slope,
|
||||
int *active)
|
||||
{
|
||||
int i;
|
||||
cairo_slope_fixed_t slope_reverse;
|
||||
|
||||
slope_reverse = *slope;
|
||||
slope_reverse.dx = -slope_reverse.dx;
|
||||
slope_reverse.dy = -slope_reverse.dy;
|
||||
|
||||
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||
if (_slope_counter_clockwise (&pen->vertex[i].slope_ccw, &slope_reverse)
|
||||
&& _slope_clockwise (&pen->vertex[i].slope_cw, &slope_reverse))
|
||||
break;
|
||||
}
|
||||
|
||||
*active = i;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
cairo_pen_stroke_direction_t dir,
|
||||
cairo_polygon_t *polygon)
|
||||
{
|
||||
int i;
|
||||
cairo_status_t status;
|
||||
int start, stop, step;
|
||||
int active = 0;
|
||||
XPointFixed hull_pt;
|
||||
cairo_slope_fixed_t slope, initial_slope, final_slope;
|
||||
XPointFixed *pt = spline->pts;
|
||||
int num_pts = spline->num_pts;
|
||||
|
||||
if (dir == cairo_pen_stroke_direction_forward) {
|
||||
start = 0;
|
||||
stop = num_pts;
|
||||
step = 1;
|
||||
initial_slope = spline->initial_slope;
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_pts - 1;
|
||||
stop = -1;
|
||||
step = -1;
|
||||
initial_slope = spline->final_slope;
|
||||
initial_slope.dx = -initial_slope.dx;
|
||||
initial_slope.dy = -initial_slope.dy;
|
||||
final_slope = spline->initial_slope;
|
||||
final_slope.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
_cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);
|
||||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_pt.x = pt[i].x + pen->vertex[active].pt.x;
|
||||
hull_pt.y = pt[i].y + pen->vertex[active].pt.y;
|
||||
status = _cairo_polygon_add_point (polygon, &hull_pt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (i + step == stop)
|
||||
slope = final_slope;
|
||||
else
|
||||
_compute_slope (&pt[i], &pt[i+step], &slope);
|
||||
if (_slope_counter_clockwise (&slope, &pen->vertex[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
} else if (_slope_clockwise (&slope, &pen->vertex[active].slope_cw)) {
|
||||
if (--active == -1)
|
||||
active = pen->num_vertices - 1;
|
||||
} else {
|
||||
i += step;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Compute outline of a given spline using the pen.
|
||||
The trapezoids needed to fill that outline will be added to traps
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_stroke_spline (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_polygon_t polygon;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
|
||||
status = _cairo_spline_decompose (spline, tolerance);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_forward, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_pen_stroke_spline_half (pen, spline, cairo_pen_stroke_direction_reverse, &polygon);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_polygon_close (&polygon);
|
||||
cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
175
src/cairo_polygon.c
Normal file
175
src/cairo_polygon.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "cairoint.h"
|
||||
|
||||
#define CAIRO_POLYGON_GROWTH_INC 10
|
||||
|
||||
/* private functions */
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
|
||||
|
||||
static void
|
||||
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt);
|
||||
|
||||
|
||||
void
|
||||
_cairo_polygon_init (cairo_polygon_t *polygon)
|
||||
{
|
||||
polygon->num_edges = 0;
|
||||
|
||||
polygon->edges_size = 0;
|
||||
polygon->edges = NULL;
|
||||
|
||||
polygon->first_pt_defined = 0;
|
||||
polygon->last_pt_defined = 0;
|
||||
|
||||
polygon->closed = 0;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_polygon_fini (cairo_polygon_t *polygon)
|
||||
{
|
||||
if (polygon->edges_size) {
|
||||
free (polygon->edges);
|
||||
polygon->edges = NULL;
|
||||
polygon->edges_size = 0;
|
||||
polygon->num_edges = 0;
|
||||
}
|
||||
|
||||
polygon->first_pt_defined = 0;
|
||||
polygon->last_pt_defined = 0;
|
||||
|
||||
polygon->closed = 0;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
|
||||
{
|
||||
cairo_edge_t *new_edges;
|
||||
int old_size = polygon->edges_size;
|
||||
int new_size = polygon->num_edges + additional;
|
||||
|
||||
if (new_size <= polygon->edges_size) {
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
polygon->edges_size = new_size;
|
||||
new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t));
|
||||
|
||||
if (new_edges == NULL) {
|
||||
polygon->edges_size = old_size;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
polygon->edges = new_edges;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_polygon_set_last_point (cairo_polygon_t *polygon, XPointFixed *pt)
|
||||
{
|
||||
polygon->last_pt = *pt;
|
||||
polygon->last_pt_defined = 1;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_edge (cairo_polygon_t *polygon, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_edge_t *edge;
|
||||
|
||||
if (! polygon->first_pt_defined) {
|
||||
polygon->first_pt = *p1;
|
||||
polygon->first_pt_defined = 1;
|
||||
polygon->closed = 0;
|
||||
}
|
||||
|
||||
/* drop horizontal edges */
|
||||
if (p1->y == p2->y) {
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (polygon->num_edges >= polygon->edges_size) {
|
||||
status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
edge = &polygon->edges[polygon->num_edges];
|
||||
if (p1->y < p2->y) {
|
||||
edge->edge.p1 = *p1;
|
||||
edge->edge.p2 = *p2;
|
||||
edge->clockWise = True;
|
||||
} else {
|
||||
edge->edge.p1 = *p2;
|
||||
edge->edge.p2 = *p1;
|
||||
edge->clockWise = False;
|
||||
}
|
||||
|
||||
polygon->num_edges++;
|
||||
|
||||
DONE:
|
||||
_cairo_polygon_set_last_point (polygon, p2);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_point (cairo_polygon_t *polygon, XPointFixed *pt)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (polygon->last_pt_defined) {
|
||||
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, pt);
|
||||
} else {
|
||||
_cairo_polygon_set_last_point (polygon, pt);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_close (cairo_polygon_t *polygon)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (polygon->closed == 0 && polygon->last_pt_defined) {
|
||||
status = _cairo_polygon_add_edge (polygon, &polygon->last_pt, &polygon->first_pt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
polygon->closed = 1;
|
||||
polygon->first_pt_defined = 0;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
271
src/cairo_spline.c
Normal file
271
src/cairo_spline.c
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_grow_by (cairo_spline_t *spline, int additional);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt);
|
||||
|
||||
static void
|
||||
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result);
|
||||
|
||||
static void
|
||||
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2);
|
||||
|
||||
static double
|
||||
_cairo_spline_error_squared (cairo_spline_t *spline);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
|
||||
|
||||
#define CAIRO_SPLINE_GROWTH_INC 100
|
||||
|
||||
cairo_int_status
|
||||
_cairo_spline_init (cairo_spline_t *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d)
|
||||
{
|
||||
spline->a = *a;
|
||||
spline->b = *b;
|
||||
spline->c = *c;
|
||||
spline->d = *d;
|
||||
|
||||
if (a->x != b->x || a->y != b->y) {
|
||||
_compute_slope (&spline->a, &spline->b, &spline->initial_slope);
|
||||
} else if (a->x != c->x || a->y != c->y) {
|
||||
_compute_slope (&spline->a, &spline->c, &spline->initial_slope);
|
||||
} else if (a->x != d->x || a->y != d->y) {
|
||||
_compute_slope (&spline->a, &spline->d, &spline->initial_slope);
|
||||
} else {
|
||||
return cairo_int_status_degenerate;
|
||||
}
|
||||
|
||||
if (c->x != d->x || c->y != d->y) {
|
||||
_compute_slope (&spline->c, &spline->d, &spline->final_slope);
|
||||
} else if (b->x != d->x || b->y != d->y) {
|
||||
_compute_slope (&spline->b, &spline->d, &spline->final_slope);
|
||||
} else {
|
||||
_compute_slope (&spline->a, &spline->d, &spline->final_slope);
|
||||
}
|
||||
|
||||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
spline->pts = NULL;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_spline_fini (cairo_spline_t *spline)
|
||||
{
|
||||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
free (spline->pts);
|
||||
spline->pts = NULL;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
|
||||
{
|
||||
XPointFixed *new_pts;
|
||||
int old_size = spline->pts_size;
|
||||
int new_size = spline->num_pts + additional;
|
||||
|
||||
if (new_size <= spline->pts_size)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
spline->pts_size = new_size;
|
||||
new_pts = realloc (spline->pts, spline->pts_size * sizeof (XPointFixed));
|
||||
|
||||
if (new_pts == NULL) {
|
||||
spline->pts_size = old_size;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
spline->pts = new_pts;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_add_point (cairo_spline_t *spline, XPointFixed *pt)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (spline->num_pts >= spline->pts_size) {
|
||||
status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
spline->pts[spline->num_pts] = *pt;
|
||||
spline->num_pts++;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_lerp_half (XPointFixed *a, XPointFixed *b, XPointFixed *result)
|
||||
{
|
||||
result->x = a->x + ((b->x - a->x) >> 1);
|
||||
result->y = a->y + ((b->y - a->y) >> 1);
|
||||
}
|
||||
|
||||
static void
|
||||
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2)
|
||||
{
|
||||
XPointFixed ab, bc, cd;
|
||||
XPointFixed abbc, bccd;
|
||||
XPointFixed final;
|
||||
|
||||
_lerp_half (&spline->a, &spline->b, &ab);
|
||||
_lerp_half (&spline->b, &spline->c, &bc);
|
||||
_lerp_half (&spline->c, &spline->d, &cd);
|
||||
_lerp_half (&ab, &bc, &abbc);
|
||||
_lerp_half (&bc, &cd, &bccd);
|
||||
_lerp_half (&abbc, &bccd, &final);
|
||||
|
||||
s1->a = spline->a;
|
||||
s1->b = ab;
|
||||
s1->c = abbc;
|
||||
s1->d = final;
|
||||
|
||||
s2->a = final;
|
||||
s2->b = bccd;
|
||||
s2->c = cd;
|
||||
s2->d = spline->d;
|
||||
}
|
||||
|
||||
static double
|
||||
_PointDistanceSquaredToPoint (XPointFixed *a, XPointFixed *b)
|
||||
{
|
||||
double dx = XFixedToDouble (b->x - a->x);
|
||||
double dy = XFixedToDouble (b->y - a->y);
|
||||
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
static double
|
||||
_PointDistanceSquaredToSegment (XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
double u;
|
||||
double dx, dy;
|
||||
double pdx, pdy;
|
||||
XPointFixed px;
|
||||
|
||||
/* intersection point (px):
|
||||
|
||||
px = p1 + u(p2 - p1)
|
||||
(p - px) . (p2 - p1) = 0
|
||||
|
||||
Thus:
|
||||
|
||||
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
|
||||
*/
|
||||
|
||||
dx = XFixedToDouble (p2->x - p1->x);
|
||||
dy = XFixedToDouble (p2->y - p1->y);
|
||||
|
||||
if (dx == 0 && dy == 0)
|
||||
return _PointDistanceSquaredToPoint (p, p1);
|
||||
|
||||
pdx = XFixedToDouble (p->x - p1->x);
|
||||
pdy = XFixedToDouble (p->y - p1->y);
|
||||
|
||||
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
|
||||
|
||||
if (u <= 0)
|
||||
return _PointDistanceSquaredToPoint (p, p1);
|
||||
else if (u >= 1)
|
||||
return _PointDistanceSquaredToPoint (p, p2);
|
||||
|
||||
px.x = p1->x + u * (p2->x - p1->x);
|
||||
px.y = p1->y + u * (p2->y - p1->y);
|
||||
|
||||
return _PointDistanceSquaredToPoint (p, &px);
|
||||
}
|
||||
|
||||
/* Return an upper bound on the error (squared) that could result from approximating
|
||||
a spline as a line segment connecting the two endpoints */
|
||||
static double
|
||||
_cairo_spline_error_squared (cairo_spline_t *spline)
|
||||
{
|
||||
double berr, cerr;
|
||||
|
||||
berr = _PointDistanceSquaredToSegment (&spline->b, &spline->a, &spline->d);
|
||||
cerr = _PointDistanceSquaredToSegment (&spline->c, &spline->a, &spline->d);
|
||||
|
||||
if (berr > cerr)
|
||||
return berr;
|
||||
else
|
||||
return cerr;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_spline_t s1, s2;
|
||||
|
||||
if (_cairo_spline_error_squared (spline) < tolerance_squared) {
|
||||
return _cairo_spline_add_point (result, &spline->a);
|
||||
}
|
||||
|
||||
_de_casteljau (spline, &s1, &s2);
|
||||
|
||||
status = _cairo_spline_decompose_into (&s1, tolerance_squared, result);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_spline_decompose_into (&s2, tolerance_squared, result);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (spline->pts_size) {
|
||||
_cairo_spline_fini (spline);
|
||||
}
|
||||
|
||||
status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_spline_add_point (spline, &spline->d);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
391
src/cairo_surface.c
Normal file
391
src/cairo_surface.c
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_for_drawable (Display *dpy,
|
||||
Drawable drawable,
|
||||
Visual *visual,
|
||||
cairo_format_t format,
|
||||
Colormap colormap)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
surface = malloc (sizeof (cairo_surface_t));
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
surface->dpy = dpy;
|
||||
surface->image_data = NULL;
|
||||
|
||||
surface->xc_surface = XcSurfaceCreateForDrawable (dpy, drawable, visual, format, colormap);
|
||||
if (surface->xc_surface == NULL) {
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* XXX: We should really get this value from somewhere like Xft.dpy */
|
||||
surface->ppm = 3780;
|
||||
|
||||
surface->ref_count = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/* XXX: These definitions are 100% bogus. The problem that needs to be
|
||||
fixed is that Ic needs to export a real API for passing in
|
||||
formats. */
|
||||
#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
|
||||
((type) << 16) | \
|
||||
((a) << 12) | \
|
||||
((r) << 8) | \
|
||||
((g) << 4) | \
|
||||
((b)))
|
||||
|
||||
/*
|
||||
* gray/color formats use a visual index instead of argb
|
||||
*/
|
||||
#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \
|
||||
((type) << 16) | \
|
||||
((vi)))
|
||||
|
||||
#define PICT_TYPE_A 1
|
||||
#define PICT_TYPE_ARGB 2
|
||||
|
||||
#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2)
|
||||
|
||||
/* 32bpp formats */
|
||||
|
||||
#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8)
|
||||
#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8)
|
||||
#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0)
|
||||
#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0)
|
||||
|
||||
static int
|
||||
cairo_format_bpp (cairo_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_A1:
|
||||
return 1;
|
||||
break;
|
||||
case CAIRO_FORMAT_A8:
|
||||
return 8;
|
||||
break;
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
default:
|
||||
return 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_for_image (char *data,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
IcFormat icformat;
|
||||
IcImage *image;
|
||||
int bpp;
|
||||
|
||||
/* XXX: This all needs to change, (but IcFormatInit interface needs to change first) */
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
IcFormatInit (&icformat, PICT_a8r8g8b8);
|
||||
bpp = 32;
|
||||
break;
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
IcFormatInit (&icformat, PICT_x8r8g8b8);
|
||||
bpp = 32;
|
||||
break;
|
||||
case CAIRO_FORMAT_A8:
|
||||
IcFormatInit (&icformat, PICT_a8);
|
||||
bpp = 8;
|
||||
break;
|
||||
case CAIRO_FORMAT_A1:
|
||||
IcFormatInit (&icformat, PICT_a1);
|
||||
bpp = 1;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface = malloc (sizeof (cairo_surface_t));
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
surface->dpy = NULL;
|
||||
surface->image_data = NULL;
|
||||
image = IcImageCreateForData ((IcBits *) data, &icformat, width, height, cairo_format_bpp (format), stride);
|
||||
if (image == NULL) {
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface->xc_surface = XcSurfaceCreateForIcImage (image);
|
||||
if (surface->xc_surface == NULL) {
|
||||
IcImageDestroy (image);
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assume a default until the user lets us know otherwise */
|
||||
surface->ppm = 3780;
|
||||
|
||||
surface->ref_count = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_similar (cairo_surface_t *other,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_A1:
|
||||
return 1;
|
||||
case CAIRO_FORMAT_A8:
|
||||
return 8;
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
return 24;
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
default:
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_surface_create_similar_solid (cairo_surface_t *other,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha)
|
||||
{
|
||||
cairo_surface_t *surface = NULL;
|
||||
cairo_color_t color;
|
||||
|
||||
/* XXX: create_similar should perhaps move down to Xc, (then we
|
||||
could drop xrsurface->dpy as well) */
|
||||
if (other->dpy) {
|
||||
Display *dpy = other->dpy;
|
||||
int scr = DefaultScreen (dpy);
|
||||
|
||||
Pixmap pix = XCreatePixmap (dpy,
|
||||
DefaultRootWindow (dpy),
|
||||
width, height,
|
||||
_CAIRO_FORMAT_DEPTH (format));
|
||||
|
||||
surface = cairo_surface_create_for_drawable (dpy, pix,
|
||||
NULL,
|
||||
format,
|
||||
DefaultColormap (dpy, scr));
|
||||
/* XXX: huh? This should be fine since we already created a picture
|
||||
from the pixmap, right?? (Somehow, it seems to be causing some
|
||||
breakage).
|
||||
XFreePixmap (surface->dpy, pix);
|
||||
*/
|
||||
} else {
|
||||
char *data;
|
||||
int stride;
|
||||
|
||||
stride = ((width * cairo_format_bpp (format)) + 7) >> 3;
|
||||
data = malloc (stride * height);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
surface = cairo_surface_create_for_image (data, format,
|
||||
width, height, stride);
|
||||
|
||||
/* lodge data in the surface structure to be freed with the surface */
|
||||
surface->image_data = data;
|
||||
}
|
||||
|
||||
/* XXX: Initializing the color in this way assumes
|
||||
non-pre-multiplied alpha. I'm not sure that that's what I want
|
||||
to do or not. */
|
||||
_cairo_color_init (&color);
|
||||
_cairo_color_set_rgb (&color, red, green, blue);
|
||||
_cairo_color_set_alpha (&color, alpha);
|
||||
_cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SRC, &color, 0, 0, width, height);
|
||||
return surface;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_surface_reference (cairo_surface_t *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
surface->ref_count++;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_surface_destroy (cairo_surface_t *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
surface->ref_count--;
|
||||
if (surface->ref_count)
|
||||
return;
|
||||
|
||||
surface->dpy = 0;
|
||||
|
||||
XcSurfaceDestroy (surface->xc_surface);
|
||||
surface->xc_surface = NULL;
|
||||
|
||||
if (surface->image_data)
|
||||
free (surface->image_data);
|
||||
surface->image_data = NULL;
|
||||
|
||||
free (surface);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_put_image (cairo_surface_t *surface,
|
||||
char *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
XcSurfacePutImage (surface->xc_surface, data,
|
||||
width, height, stride);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: Symmetry demands an cairo_surface_get_image as well */
|
||||
|
||||
/* XXX: We may want to move to projective matrices at some point. If
|
||||
nothing else, that would eliminate the two different transform data
|
||||
structures we have here. */
|
||||
cairo_status_t
|
||||
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
|
||||
{
|
||||
XTransform xtransform;
|
||||
|
||||
xtransform.matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
|
||||
xtransform.matrix[0][1] = XDoubleToFixed (matrix->m[1][0]);
|
||||
xtransform.matrix[0][2] = XDoubleToFixed (matrix->m[2][0]);
|
||||
|
||||
xtransform.matrix[1][0] = XDoubleToFixed (matrix->m[0][1]);
|
||||
xtransform.matrix[1][1] = XDoubleToFixed (matrix->m[1][1]);
|
||||
xtransform.matrix[1][2] = XDoubleToFixed (matrix->m[2][1]);
|
||||
|
||||
xtransform.matrix[2][0] = 0;
|
||||
xtransform.matrix[2][1] = 0;
|
||||
xtransform.matrix[2][2] = XDoubleToFixed (1);
|
||||
|
||||
XcSurfaceSetTransform (surface->xc_surface,
|
||||
&xtransform);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
|
||||
{
|
||||
XTransform xtransform;
|
||||
|
||||
XcSurfaceGetTransform (surface->xc_surface, &xtransform);
|
||||
|
||||
matrix->m[0][0] = XFixedToDouble (xtransform.matrix[0][0]);
|
||||
matrix->m[1][0] = XFixedToDouble (xtransform.matrix[0][1]);
|
||||
matrix->m[2][0] = XFixedToDouble (xtransform.matrix[0][2]);
|
||||
|
||||
matrix->m[0][1] = XFixedToDouble (xtransform.matrix[1][0]);
|
||||
matrix->m[1][1] = XFixedToDouble (xtransform.matrix[1][1]);
|
||||
matrix->m[2][1] = XFixedToDouble (xtransform.matrix[1][2]);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
|
||||
{
|
||||
XcSurfaceSetFilter (surface->xc_surface, filter);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: The Xc version of this function isn't quite working yet
|
||||
cairo_status_t
|
||||
cairo_surface_set_clip_region (cairo_surface_t *surface, Region region)
|
||||
{
|
||||
XcSurfaceSetClipRegion (surface->xc_surface, region);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
cairo_status_t
|
||||
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
|
||||
{
|
||||
XcSurfaceSetRepeat (surface->xc_surface, repeat);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* XXX: This function is going away, right? */
|
||||
Picture
|
||||
_cairo_surface_get_picture (cairo_surface_t *surface)
|
||||
{
|
||||
return XcSurfaceGetPicture (surface->xc_surface);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
|
||||
cairo_operator_t operator,
|
||||
cairo_color_t *color,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
XcFillRectangle (operator,
|
||||
surface->xc_surface,
|
||||
&color->xc_color,
|
||||
x, y,
|
||||
width, height);
|
||||
}
|
||||
|
||||
593
src/cairo_traps.c
Normal file
593
src/cairo_traps.c
Normal file
|
|
@ -0,0 +1,593 @@
|
|||
/*
|
||||
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Keith Packard not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Keith Packard makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
#define CAIRO_TRAPS_GROWTH_INC 10
|
||||
|
||||
/* private functions */
|
||||
|
||||
static cairo_status_t
|
||||
cairo_traps_grow_by (cairo_traps_t *traps, int additional);
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XLineFixed left, XLineFixed right);
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XPointFixed left_p1, XPointFixed left_p2,
|
||||
XPointFixed right_p1, XPointFixed right_p2);
|
||||
|
||||
static int
|
||||
_compare_point_fixed_by_y (const void *av, const void *bv);
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_top (const void *av, const void *bv);
|
||||
|
||||
static XFixed
|
||||
_compute_x (XLineFixed *line, XFixed y);
|
||||
|
||||
static double
|
||||
_compute_inverse_slope (XLineFixed *l);
|
||||
|
||||
static double
|
||||
_compute_x_intercept (XLineFixed *l, double inverse_slope);
|
||||
|
||||
static XFixed
|
||||
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *intersection);
|
||||
|
||||
void
|
||||
cairo_traps_init (cairo_traps_t *traps)
|
||||
{
|
||||
traps->num_xtraps = 0;
|
||||
|
||||
traps->xtraps_size = 0;
|
||||
traps->xtraps = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_traps_fini (cairo_traps_t *traps)
|
||||
{
|
||||
if (traps->xtraps_size) {
|
||||
free (traps->xtraps);
|
||||
traps->xtraps = NULL;
|
||||
traps->xtraps_size = 0;
|
||||
traps->num_xtraps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XLineFixed left, XLineFixed right)
|
||||
{
|
||||
cairo_status_t status;
|
||||
XTrapezoid *trap;
|
||||
|
||||
if (top == bottom) {
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (traps->num_xtraps >= traps->xtraps_size) {
|
||||
status = cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
trap = &traps->xtraps[traps->num_xtraps];
|
||||
trap->top = top;
|
||||
trap->bottom = bottom;
|
||||
trap->left = left;
|
||||
trap->right = right;
|
||||
|
||||
traps->num_xtraps++;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_add_trap_from_points (cairo_traps_t *traps, XFixed top, XFixed bottom,
|
||||
XPointFixed left_p1, XPointFixed left_p2,
|
||||
XPointFixed right_p1, XPointFixed right_p2)
|
||||
{
|
||||
XLineFixed left;
|
||||
XLineFixed right;
|
||||
|
||||
left.p1 = left_p1;
|
||||
left.p2 = left_p2;
|
||||
|
||||
right.p1 = right_p1;
|
||||
right.p2 = right_p2;
|
||||
|
||||
return cairo_traps_add_trap (traps, top, bottom, left, right);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
cairo_traps_grow_by (cairo_traps_t *traps, int additional)
|
||||
{
|
||||
XTrapezoid *new_xtraps;
|
||||
int old_size = traps->xtraps_size;
|
||||
int new_size = traps->num_xtraps + additional;
|
||||
|
||||
if (new_size <= traps->xtraps_size) {
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
traps->xtraps_size = new_size;
|
||||
new_xtraps = realloc (traps->xtraps, traps->xtraps_size * sizeof (XTrapezoid));
|
||||
|
||||
if (new_xtraps == NULL) {
|
||||
traps->xtraps_size = old_size;
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
traps->xtraps = new_xtraps;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_point_fixed_by_y (const void *av, const void *bv)
|
||||
{
|
||||
const XPointFixed *a = av, *b = bv;
|
||||
|
||||
int ret = a->y - b->y;
|
||||
if (ret == 0) {
|
||||
ret = a->x - b->x;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_triangle (cairo_traps_t *traps, XPointFixed t[3])
|
||||
{
|
||||
cairo_status_t status;
|
||||
XLineFixed line;
|
||||
double intersect;
|
||||
XPointFixed tsort[3];
|
||||
|
||||
memcpy (tsort, t, 3 * sizeof (XPointFixed));
|
||||
qsort (tsort, 3, sizeof (XPointFixed), _compare_point_fixed_by_y);
|
||||
|
||||
/* horizontal top edge requires special handling */
|
||||
if (tsort[0].y == tsort[1].y) {
|
||||
if (tsort[0].x < tsort[1].x)
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
else
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
return status;
|
||||
}
|
||||
|
||||
line.p1 = tsort[0];
|
||||
line.p2 = tsort[1];
|
||||
|
||||
intersect = _compute_x (&line, tsort[2].y);
|
||||
|
||||
if (intersect < tsort[2].x) {
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[0].y, tsort[1].y,
|
||||
tsort[0], tsort[1],
|
||||
tsort[0], tsort[2]);
|
||||
if (status)
|
||||
return status;
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[1], tsort[2],
|
||||
tsort[0], tsort[2]);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[0].y, tsort[1].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[0], tsort[1]);
|
||||
if (status)
|
||||
return status;
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
tsort[1].y, tsort[2].y,
|
||||
tsort[0], tsort[2],
|
||||
tsort[1], tsort[2]);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Warning: This function reorders the elements of the array provided. */
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_rectangle (cairo_traps_t *traps, XPointFixed q[4])
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
qsort (q, 4, sizeof (XPointFixed), _compare_point_fixed_by_y);
|
||||
|
||||
if (q[1].x > q[2].x) {
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
|
||||
if (status)
|
||||
return status;
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
|
||||
if (status)
|
||||
return status;
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
|
||||
if (status)
|
||||
return status;
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
|
||||
if (status)
|
||||
return status;
|
||||
status = cairo_traps_add_trap_from_points (traps,
|
||||
q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_top (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
int ret;
|
||||
|
||||
ret = a->edge.p1.y - b->edge.p1.y;
|
||||
if (ret == 0)
|
||||
ret = a->edge.p1.x - b->edge.p1.x;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return value is:
|
||||
> 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
|
||||
== 0 if slope (a) == slope (b)
|
||||
< 0 if a is "counter-clockwise" from b
|
||||
*/
|
||||
static int
|
||||
_compare_cairo_edge_by_slope (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
|
||||
double a_dx = XFixedToDouble (a->edge.p2.x - a->edge.p1.x);
|
||||
double a_dy = XFixedToDouble (a->edge.p2.y - a->edge.p1.y);
|
||||
double b_dx = XFixedToDouble (b->edge.p2.x - b->edge.p1.x);
|
||||
double b_dy = XFixedToDouble (b->edge.p2.y - b->edge.p1.y);
|
||||
|
||||
return b_dy * a_dx - a_dy * b_dx;
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_cairo_edge_by_current_xthen_slope (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_edge_t *a = av, *b = bv;
|
||||
int ret;
|
||||
|
||||
ret = a->current_x - b->current_x;
|
||||
if (ret == 0)
|
||||
ret = _compare_cairo_edge_by_slope (a, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
|
||||
for horizontal lines. Now, we "know" that when we are tessellating
|
||||
polygons that the polygon data structure discards all horizontal
|
||||
edges, but there's nothing here to guarantee that. I suggest the
|
||||
following:
|
||||
|
||||
A) Move all of the polygon tessellation code out of xrtraps.c and
|
||||
into xrpoly.c, (in order to be in the same module as the code
|
||||
discarding horizontal lines).
|
||||
|
||||
OR
|
||||
|
||||
B) Re-implement the line intersection in a way that avoids all
|
||||
division by zero. Here's one approach. The only disadvantage
|
||||
might be that that there are not meaningful names for all of the
|
||||
sub-computations -- just a bunch of determinants. I haven't
|
||||
looked at complexity, (both are probably similar and it probably
|
||||
doesn't matter much anyway).
|
||||
|
||||
static double
|
||||
_det (double a, double b, double c, double d)
|
||||
{
|
||||
return a * d - b * c;
|
||||
}
|
||||
|
||||
static int
|
||||
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
||||
{
|
||||
double dx1 = XFixedToDouble (l1->p1.x - l1->p2.x);
|
||||
double dy1 = XFixedToDouble (l1->p1.y - l1->p2.y);
|
||||
|
||||
double dx2 = XFixedToDouble (l2->p1.x - l2->p2.x);
|
||||
double dy2 = XFixedToDouble (l2->p1.y - l2->p2.y);
|
||||
|
||||
double l1_det, l2_det;
|
||||
|
||||
double den_det = _det (dx1, dy1, dx2, dy2);
|
||||
|
||||
if (den_det == 0)
|
||||
return 0;
|
||||
|
||||
l1_det = _det (l1->p1.x, l1->p1.y,
|
||||
l1->p2.x, l1->p2.y);
|
||||
l2_det = _det (l2->p1.x, l2->p1.y,
|
||||
l2->p2.x, l2->p2.y);
|
||||
|
||||
*y_intersection = _det (l1_det, dy1,
|
||||
l2_det, dy2) / den_det;
|
||||
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
static XFixed
|
||||
_compute_x (XLineFixed *line, XFixed y)
|
||||
{
|
||||
XFixed dx = line->p2.x - line->p1.x;
|
||||
double ex = (double) (y - line->p1.y) * (double) dx;
|
||||
XFixed dy = line->p2.y - line->p1.y;
|
||||
|
||||
return line->p1.x + (ex / dy);
|
||||
}
|
||||
|
||||
static double
|
||||
_compute_inverse_slope (XLineFixed *l)
|
||||
{
|
||||
return (XFixedToDouble (l->p2.x - l->p1.x) /
|
||||
XFixedToDouble (l->p2.y - l->p1.y));
|
||||
}
|
||||
|
||||
static double
|
||||
_compute_x_intercept (XLineFixed *l, double inverse_slope)
|
||||
{
|
||||
return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y);
|
||||
}
|
||||
|
||||
static int
|
||||
_lines_intersect (XLineFixed *l1, XLineFixed *l2, XFixed *y_intersection)
|
||||
{
|
||||
/*
|
||||
* x = m1y + b1
|
||||
* x = m2y + b2
|
||||
* m1y + b1 = m2y + b2
|
||||
* y * (m1 - m2) = b2 - b1
|
||||
* y = (b2 - b1) / (m1 - m2)
|
||||
*/
|
||||
double m1 = _compute_inverse_slope (l1);
|
||||
double b1 = _compute_x_intercept (l1, m1);
|
||||
double m2 = _compute_inverse_slope (l2);
|
||||
double b2 = _compute_x_intercept (l2, m2);
|
||||
|
||||
if (m1 == m2)
|
||||
return 0;
|
||||
|
||||
*y_intersection = XDoubleToFixed ((b2 - b1) / (m1 - m2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_SortEdgeList (cairo_edge_t **active)
|
||||
{
|
||||
cairo_edge_t *e, *en, *next;
|
||||
|
||||
/* sort active list */
|
||||
for (e = *active; e; e = next)
|
||||
{
|
||||
next = e->next;
|
||||
/*
|
||||
* Find one later in the list that belongs before the
|
||||
* current one
|
||||
*/
|
||||
for (en = next; en; en = en->next)
|
||||
{
|
||||
if (_compare_cairo_edge_by_current_xthen_slope (e, en) > 0)
|
||||
{
|
||||
/*
|
||||
* insert en before e
|
||||
*
|
||||
* extract en
|
||||
*/
|
||||
en->prev->next = en->next;
|
||||
if (en->next)
|
||||
en->next->prev = en->prev;
|
||||
/*
|
||||
* insert en
|
||||
*/
|
||||
if (e->prev)
|
||||
e->prev->next = en;
|
||||
else
|
||||
*active = en;
|
||||
en->prev = e->prev;
|
||||
e->prev = en;
|
||||
en->next = e;
|
||||
/*
|
||||
* start over at en
|
||||
*/
|
||||
next = en;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The algorithm here is pretty simple:
|
||||
|
||||
inactive = [edges]
|
||||
y = min_p1_y (inactive)
|
||||
|
||||
while (num_active || num_inactive) {
|
||||
active = all edges containing y
|
||||
|
||||
next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )
|
||||
|
||||
fill_traps (active, y, next_y, fill_rule)
|
||||
|
||||
y = next_y
|
||||
}
|
||||
|
||||
The invariants that hold during fill_traps are:
|
||||
|
||||
All edges in active contain both y and next_y
|
||||
No edges in active intersect within y and next_y
|
||||
|
||||
These invariants mean that fill_traps is as simple as sorting the
|
||||
active edges, forming a trapezoid between each adjacent pair. Then,
|
||||
either the even-odd or winding rule is used to determine whether to
|
||||
emit each of these trapezoids.
|
||||
|
||||
Warning: This function reorders the edges of the polygon provided.
|
||||
*/
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_polygon (cairo_traps_t *traps,
|
||||
cairo_polygon_t *poly,
|
||||
cairo_fill_rule_t fill_rule)
|
||||
{
|
||||
cairo_status_t status;
|
||||
int inactive;
|
||||
cairo_edge_t *active;
|
||||
cairo_edge_t *e, *en, *next;
|
||||
XFixed y, next_y, intersect;
|
||||
int in_out, num_edges = poly->num_edges;
|
||||
cairo_edge_t *edges = poly->edges;
|
||||
|
||||
if (num_edges == 0)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
|
||||
|
||||
y = edges[0].edge.p1.y;
|
||||
active = 0;
|
||||
inactive = 0;
|
||||
while (active || inactive < num_edges)
|
||||
{
|
||||
for (e = active; e; e = e->next) {
|
||||
e->current_x = _compute_x (&e->edge, y);
|
||||
}
|
||||
|
||||
/* insert new active edges into list */
|
||||
while (inactive < num_edges)
|
||||
{
|
||||
e = &edges[inactive];
|
||||
if (e->edge.p1.y > y)
|
||||
break;
|
||||
/* move this edge into the active list */
|
||||
inactive++;
|
||||
e->current_x = _compute_x (&e->edge, y);
|
||||
|
||||
/* insert e at head of list */
|
||||
e->next = active;
|
||||
e->prev = NULL;
|
||||
if (active)
|
||||
active->prev = e;
|
||||
active = e;
|
||||
}
|
||||
|
||||
_SortEdgeList (&active);
|
||||
|
||||
/* find next inflection point */
|
||||
if (active)
|
||||
next_y = active->edge.p2.y;
|
||||
else
|
||||
next_y = edges[inactive].edge.p1.y;
|
||||
for (e = active; e; e = en)
|
||||
{
|
||||
en = e->next;
|
||||
|
||||
if (e->edge.p2.y < next_y)
|
||||
next_y = e->edge.p2.y;
|
||||
/* check intersect */
|
||||
if (en && e->current_x != en->current_x)
|
||||
{
|
||||
if (_lines_intersect (&e->edge, &en->edge, &intersect))
|
||||
if (intersect > y) {
|
||||
/* Need to guarantee that we get all the way past
|
||||
the intersection point so that the edges sort
|
||||
properly next time through the loop. */
|
||||
if (_compute_x (&e->edge, intersect) < _compute_x (&en->edge, intersect))
|
||||
intersect++;
|
||||
if (intersect < next_y)
|
||||
next_y = intersect;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* check next inactive point */
|
||||
if (inactive < num_edges && edges[inactive].edge.p1.y < next_y)
|
||||
next_y = edges[inactive].edge.p1.y;
|
||||
|
||||
/* walk the list generating trapezoids */
|
||||
in_out = 0;
|
||||
for (e = active; e && (en = e->next); e = e->next)
|
||||
{
|
||||
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
|
||||
if (e->clockWise) {
|
||||
in_out++;
|
||||
} else {
|
||||
in_out--;
|
||||
}
|
||||
if (in_out == 0) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
in_out++;
|
||||
if (in_out % 2 == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
status = cairo_traps_add_trap (traps, y, next_y, e->edge, en->edge);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* delete inactive edges from list */
|
||||
for (e = active; e; e = next)
|
||||
{
|
||||
next = e->next;
|
||||
if (e->edge.p2.y <= next_y)
|
||||
{
|
||||
if (e->prev)
|
||||
e->prev->next = e->next;
|
||||
else
|
||||
active = e->next;
|
||||
if (e->next)
|
||||
e->next->prev = e->prev;
|
||||
}
|
||||
}
|
||||
|
||||
y = next_y;
|
||||
}
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
710
src/cairoint.h
Normal file
710
src/cairoint.h
Normal file
|
|
@ -0,0 +1,710 @@
|
|||
/*
|
||||
* Copyright © 2002 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* These definitions are solely for use by the implementation of Cairo
|
||||
* and constitute no kind of standard. If you need any of these
|
||||
* functions, please drop me a note. Either the library needs new
|
||||
* functionality, or there's a way to do what you need using the
|
||||
* existing published interfaces. cworth@isi.edu
|
||||
*/
|
||||
|
||||
#ifndef _CAIROINT_H_
|
||||
#define _CAIROINT_H_
|
||||
|
||||
#include <math.h>
|
||||
#include <X11/Xlibint.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include "cairo.h"
|
||||
|
||||
#ifndef __GCC__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
/* Sure wish C had a real enum type so that this would be distinct
|
||||
from cairo_status_t. Oh well, without that, I'll use this bogus 1000
|
||||
offset */
|
||||
typedef enum _cairo_int_status {
|
||||
cairo_int_status_degenerate = 1000
|
||||
} cairo_int_status;
|
||||
|
||||
typedef enum _cairo_path_op {
|
||||
cairo_path_op_move_to = 0,
|
||||
cairo_path_op_line_to = 1,
|
||||
cairo_path_op_curve_to = 2,
|
||||
cairo_path_op_close_path = 3
|
||||
} __attribute__ ((packed)) cairo_path_op; /* Don't want 32 bits if we can avoid it. */
|
||||
|
||||
typedef enum _cairo_path_direction {
|
||||
cairo_path_direction_forward,
|
||||
cairo_path_direction_reverse
|
||||
} cairo_path_direction;
|
||||
|
||||
typedef enum _cairo_sub_path_done {
|
||||
cairo_sub_path_done_cap,
|
||||
cairo_sub_path_done_join
|
||||
} cairo_sub_path_done;
|
||||
|
||||
typedef struct cairo_path_callbacks {
|
||||
cairo_status_t (*AddEdge) (void *closure, XPointFixed *p1, XPointFixed *p2);
|
||||
cairo_status_t (*AddSpline) (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d);
|
||||
cairo_status_t (*DoneSubPath) (void *closure, cairo_sub_path_done done);
|
||||
cairo_status_t (*DonePath) (void *closure);
|
||||
} cairo_path_callbacks_t;
|
||||
|
||||
#define CAIRO_PATH_BUF_SZ 64
|
||||
|
||||
typedef struct cairo_path_op_buf {
|
||||
int num_ops;
|
||||
cairo_path_op op[CAIRO_PATH_BUF_SZ];
|
||||
|
||||
struct cairo_path_op_buf *next, *prev;
|
||||
} cairo_path_op_buf_t;
|
||||
|
||||
typedef struct cairo_path_arg_buf {
|
||||
int num_pts;
|
||||
XPointFixed pt[CAIRO_PATH_BUF_SZ];
|
||||
|
||||
struct cairo_path_arg_buf *next, *prev;
|
||||
} cairo_path_arg_buf_t;
|
||||
|
||||
typedef struct cairo_path {
|
||||
cairo_path_op_buf_t *op_head;
|
||||
cairo_path_op_buf_t *op_tail;
|
||||
|
||||
cairo_path_arg_buf_t *arg_head;
|
||||
cairo_path_arg_buf_t *arg_tail;
|
||||
} cairo_path_t;
|
||||
|
||||
typedef struct cairo_edge {
|
||||
XLineFixed edge;
|
||||
Bool clockWise;
|
||||
|
||||
XFixed current_x;
|
||||
struct cairo_edge *next, *prev;
|
||||
} cairo_edge_t;
|
||||
|
||||
typedef struct cairo_polygon {
|
||||
int num_edges;
|
||||
int edges_size;
|
||||
cairo_edge_t *edges;
|
||||
|
||||
XPointFixed first_pt;
|
||||
int first_pt_defined;
|
||||
XPointFixed last_pt;
|
||||
int last_pt_defined;
|
||||
|
||||
int closed;
|
||||
} cairo_polygon_t;
|
||||
|
||||
typedef struct cairo_slope_fixed
|
||||
{
|
||||
XFixed dx;
|
||||
XFixed dy;
|
||||
} cairo_slope_fixed_t;
|
||||
|
||||
typedef struct cairo_spline {
|
||||
XPointFixed a, b, c, d;
|
||||
|
||||
cairo_slope_fixed_t initial_slope;
|
||||
cairo_slope_fixed_t final_slope;
|
||||
|
||||
int num_pts;
|
||||
int pts_size;
|
||||
XPointFixed *pts;
|
||||
} cairo_spline_t;
|
||||
|
||||
/* XXX: This can go away once incremental spline tessellation is working */
|
||||
typedef enum cairo_pen_stroke_direction {
|
||||
cairo_pen_stroke_direction_forward,
|
||||
cairo_pen_stroke_direction_reverse
|
||||
} cairo_pen_stroke_direction_t;
|
||||
|
||||
typedef struct _cairo_pen_vertex {
|
||||
XPointFixed pt;
|
||||
|
||||
double theta;
|
||||
cairo_slope_fixed_t slope_ccw;
|
||||
cairo_slope_fixed_t slope_cw;
|
||||
} cairo_pen_vertex;
|
||||
|
||||
typedef struct cairo_pen {
|
||||
double radius;
|
||||
double tolerance;
|
||||
|
||||
int num_vertices;
|
||||
cairo_pen_vertex *vertex;
|
||||
} cairo_pen_t;
|
||||
|
||||
struct cairo_surface_t {
|
||||
Display *dpy;
|
||||
char *image_data;
|
||||
|
||||
XcSurface *xc_surface;
|
||||
|
||||
double ppm;
|
||||
|
||||
unsigned int ref_count;
|
||||
};
|
||||
|
||||
typedef struct cairo_color {
|
||||
double red;
|
||||
double green;
|
||||
double blue;
|
||||
double alpha;
|
||||
|
||||
XcColor xc_color;
|
||||
} cairo_color_t;
|
||||
|
||||
struct cairo_matrix_t {
|
||||
double m[3][2];
|
||||
};
|
||||
|
||||
typedef struct cairo_traps {
|
||||
int num_xtraps;
|
||||
int xtraps_size;
|
||||
XTrapezoid *xtraps;
|
||||
} cairo_traps_t;
|
||||
|
||||
#define CAIRO_FONT_KEY_DEFAULT "serif"
|
||||
|
||||
typedef struct cairo_font {
|
||||
unsigned char *key;
|
||||
|
||||
double scale;
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
Display *dpy;
|
||||
XftFont *xft_font;
|
||||
} cairo_font_t;
|
||||
|
||||
|
||||
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
|
||||
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
|
||||
#define CAIRO_GSTATE_FILL_RULE_DEFAULT CAIRO_FILL_RULE_WINDING
|
||||
#define CAIRO_GSTATE_LINE_WIDTH_DEFAULT 2.0
|
||||
#define CAIRO_GSTATE_LINE_CAP_DEFAULT CAIRO_LINE_CAP_BUTT
|
||||
#define CAIRO_GSTATE_LINE_JOIN_DEFAULT CAIRO_LINE_JOIN_MITER
|
||||
#define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0
|
||||
|
||||
/* Need a name distinct from the cairo_clip function */
|
||||
typedef struct cairo_clip_rec {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
cairo_surface_t *surface;
|
||||
} cairo_clip_rec_t;
|
||||
|
||||
typedef struct cairo_gstate {
|
||||
cairo_operator_t operator;
|
||||
|
||||
double tolerance;
|
||||
|
||||
/* stroke style */
|
||||
double line_width;
|
||||
cairo_line_cap_t line_cap;
|
||||
cairo_line_join_t line_join;
|
||||
double miter_limit;
|
||||
|
||||
cairo_fill_rule_t fill_rule;
|
||||
|
||||
double *dash;
|
||||
int num_dashes;
|
||||
double dash_offset;
|
||||
|
||||
cairo_font_t font;
|
||||
|
||||
cairo_surface_t *surface;
|
||||
cairo_surface_t *solid;
|
||||
cairo_surface_t *pattern;
|
||||
XPointDouble pattern_offset;
|
||||
|
||||
cairo_clip_rec_t clip;
|
||||
|
||||
double alpha;
|
||||
cairo_color_t color;
|
||||
|
||||
double ppm;
|
||||
cairo_matrix_t ctm;
|
||||
cairo_matrix_t ctm_inverse;
|
||||
|
||||
cairo_path_t path;
|
||||
|
||||
XPointDouble last_move_pt;
|
||||
XPointDouble current_pt;
|
||||
int has_current_pt;
|
||||
|
||||
cairo_pen_t pen_regular;
|
||||
|
||||
struct cairo_gstate *next;
|
||||
} cairo_gstate_t;
|
||||
|
||||
struct cairo {
|
||||
cairo_gstate_t *gstate;
|
||||
cairo_status_t status;
|
||||
};
|
||||
|
||||
typedef struct cairo_stroke_face {
|
||||
XPointFixed ccw;
|
||||
XPointFixed pt;
|
||||
XPointFixed cw;
|
||||
cairo_slope_fixed_t dev_vector;
|
||||
XPointDouble usr_vector;
|
||||
} cairo_stroke_face_t;
|
||||
|
||||
/* cairo_gstate_t.c */
|
||||
cairo_gstate_t *
|
||||
_cairo_gstate_create (void);
|
||||
|
||||
void
|
||||
_cairo_gstate_init (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
|
||||
|
||||
void
|
||||
_cairo_gstate_fini (cairo_gstate_t *gstate);
|
||||
|
||||
void
|
||||
_cairo_gstate_destroy (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_gstate_t *
|
||||
_cairo_gstate_clone (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_begin_group (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_end_group (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_drawable (cairo_gstate_t *gstate, Drawable drawable);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_visual (cairo_gstate_t *gstate, Visual *visual);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_format (cairo_gstate_t *gstate, cairo_format_t format);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface);
|
||||
|
||||
cairo_surface_t *
|
||||
_cairo_gstate_get_target_surface (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator);
|
||||
|
||||
cairo_operator_t
|
||||
_cairo_gstate_get_operator (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_get_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
|
||||
|
||||
double
|
||||
_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha);
|
||||
|
||||
double
|
||||
_cairo_gstate_get_alpha (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
|
||||
|
||||
double
|
||||
_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
|
||||
|
||||
cairo_line_cap_t
|
||||
_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
|
||||
|
||||
cairo_line_join_t
|
||||
_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
|
||||
|
||||
double
|
||||
_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_default_matrix (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
cairo_gstateransform_point (cairo_gstate_t *gstate, double *x, double *y);
|
||||
|
||||
cairo_status_t
|
||||
cairo_gstateransform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_new_path (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_curve_to (cairo_gstate_t *gstate,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
double dx3, double dy3);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_close_path (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_get_current_point (cairo_gstate_t *gstate, double *x, double *y);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_stroke (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_fill (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_clip (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_select_font (cairo_gstate_t *gstate, const char *key);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale);
|
||||
|
||||
cairo_status_t
|
||||
cairo_gstateransform_font (cairo_gstate_t *gstate,
|
||||
double a, double b,
|
||||
double c, double d);
|
||||
|
||||
cairo_status_t
|
||||
cairo_gstateext_extents (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8,
|
||||
double *x, double *y,
|
||||
double *width, double *height,
|
||||
double *dx, double *dy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
|
||||
cairo_surface_t *surface,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* cairo_color_t.c */
|
||||
void
|
||||
_cairo_color_init (cairo_color_t *color);
|
||||
|
||||
void
|
||||
_cairo_color_fini (cairo_color_t *color);
|
||||
|
||||
void
|
||||
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
|
||||
|
||||
void
|
||||
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue);
|
||||
|
||||
void
|
||||
_cairo_color_set_alpha (cairo_color_t *color, double alpha);
|
||||
|
||||
/* cairo_font_t.c */
|
||||
|
||||
void
|
||||
_cairo_font_init (cairo_font_t *font);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other);
|
||||
|
||||
void
|
||||
_cairo_font_fini (cairo_font_t *font);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_select (cairo_font_t *font, const char *key);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_scale (cairo_font_t *font, double scale);
|
||||
|
||||
cairo_status_t
|
||||
cairo_font_transform (cairo_font_t *font,
|
||||
double a, double b,
|
||||
double c, double d);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font);
|
||||
|
||||
/* cairo_path_t.c */
|
||||
void
|
||||
_cairo_path_init (cairo_path_t *path);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other);
|
||||
|
||||
void
|
||||
_cairo_path_fini (cairo_path_t *path);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_move_to (cairo_path_t *path, double x, double y);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_line_to (cairo_path_t *path, double x, double y);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_curve_to (cairo_path_t *path,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_close_path (cairo_path_t *path);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_interpret (cairo_path_t *path,
|
||||
cairo_path_direction dir,
|
||||
const cairo_path_callbacks_t *cb,
|
||||
void *closure);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
|
||||
|
||||
/* cairo_path_tfill.c */
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
|
||||
|
||||
/* cairo_path_tstroke.c */
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
|
||||
|
||||
/* cairo_surface_t.c */
|
||||
|
||||
void
|
||||
_cairo_surface_reference (cairo_surface_t *surface);
|
||||
|
||||
XcSurface *
|
||||
_cairo_surface_get_xc_surface (cairo_surface_t *surface);
|
||||
|
||||
/* XXX: This function is going away, right? */
|
||||
Picture
|
||||
_cairo_surface_get_picture (cairo_surface_t *surface);
|
||||
|
||||
void
|
||||
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
|
||||
cairo_operator_t operator,
|
||||
cairo_color_t *color,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* cairo_pen_t.c */
|
||||
cairo_status_t
|
||||
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_empty (cairo_pen_t *pen);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other);
|
||||
|
||||
void
|
||||
_cairo_pen_fini (cairo_pen_t *pen);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_add_points (cairo_pen_t *pen, XPointFixed *pt, int num_pts);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_add_points_for_slopes (cairo_pen_t *pen,
|
||||
XPointFixed *a,
|
||||
XPointFixed *b,
|
||||
XPointFixed *c,
|
||||
XPointFixed *d);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_fixed_t *slope,
|
||||
int *active);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
|
||||
cairo_slope_fixed_t *slope,
|
||||
int *active);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_pen_stroke_spline (cairo_pen_t *pen,
|
||||
cairo_spline_t *spline,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
/* cairo_polygon_t.c */
|
||||
void
|
||||
_cairo_polygon_init (cairo_polygon_t *polygon);
|
||||
|
||||
void
|
||||
_cairo_polygon_fini (cairo_polygon_t *polygon);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_edge (cairo_polygon_t *polygon, XPointFixed *p1, XPointFixed *p2);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_point (cairo_polygon_t *polygon, XPointFixed *pt);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_close (cairo_polygon_t *polygon);
|
||||
|
||||
/* cairo_spline_t.c */
|
||||
cairo_int_status
|
||||
_cairo_spline_init (cairo_spline_t *spline,
|
||||
XPointFixed *a,
|
||||
XPointFixed *b,
|
||||
XPointFixed *c,
|
||||
XPointFixed *d);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
|
||||
|
||||
void
|
||||
_cairo_spline_fini (cairo_spline_t *spline);
|
||||
|
||||
/* cairo_matrix_t.c */
|
||||
void
|
||||
_cairo_matrix_init (cairo_matrix_t *matrix);
|
||||
|
||||
void
|
||||
_cairo_matrix_fini (cairo_matrix_t *matrix);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
|
||||
double tx, double ty);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
|
||||
double sx, double sy);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
|
||||
double angle);
|
||||
|
||||
cairo_status_t
|
||||
cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
|
||||
double *x, double *y,
|
||||
double *width, double *height);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
|
||||
|
||||
/* cairo_traps.c */
|
||||
void
|
||||
cairo_traps_init (cairo_traps_t *traps);
|
||||
|
||||
void
|
||||
cairo_traps_fini (cairo_traps_t *traps);
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_triangle (cairo_traps_t *traps, XPointFixed t[3]);
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_rectangle (cairo_traps_t *traps, XPointFixed q[4]);
|
||||
|
||||
cairo_status_t
|
||||
cairo_traps_tessellate_polygon (cairo_traps_t *traps,
|
||||
cairo_polygon_t *poly,
|
||||
cairo_fill_rule_t fill_rule);
|
||||
|
||||
/* cairo_misc.c */
|
||||
|
||||
void
|
||||
_compute_slope (XPointFixed *a, XPointFixed *b, cairo_slope_fixed_t *slope);
|
||||
|
||||
#endif
|
||||
654
src/xr.c
654
src/xr.c
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
103
src/xrfiller.c
103
src/xrfiller.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
169
src/xrfont.c
169
src/xrfont.c
|
|
@ -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;
|
||||
}
|
||||
1120
src/xrgstate.c
1120
src/xrgstate.c
File diff suppressed because it is too large
Load diff
708
src/xrint.h
708
src/xrint.h
|
|
@ -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
|
||||
378
src/xrmatrix.c
378
src/xrmatrix.c
|
|
@ -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;
|
||||
}
|
||||
34
src/xrmisc.c
34
src/xrmisc.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
434
src/xrpath.c
434
src/xrpath.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
156
src/xrpathfill.c
156
src/xrpathfill.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
389
src/xrpen.c
389
src/xrpen.c
|
|
@ -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;
|
||||
}
|
||||
173
src/xrpolygon.c
173
src/xrpolygon.c
|
|
@ -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;
|
||||
}
|
||||
269
src/xrspline.c
269
src/xrspline.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
108
src/xrstate.c
108
src/xrstate.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
643
src/xrstroker.c
643
src/xrstroker.c
|
|
@ -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;
|
||||
}
|
||||
386
src/xrsurface.c
386
src/xrsurface.c
|
|
@ -1,386 +0,0 @@
|
|||
/*
|
||||
* $XFree86: $
|
||||
*
|
||||
* Copyright © 2002 Carl D. Worth
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of Carl
|
||||
* D. Worth not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Carl D. Worth makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xrint.h"
|
||||
|
||||
XrSurface *
|
||||
XrSurfaceCreateForDrawable (Display *dpy,
|
||||
Drawable drawable,
|
||||
Visual *visual,
|
||||
XrFormat format,
|
||||
Colormap colormap)
|
||||
{
|
||||
XrSurface *surface;
|
||||
|
||||
surface = malloc(sizeof(XrSurface));
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
surface->dpy = dpy;
|
||||
surface->image_data = NULL;
|
||||
|
||||
surface->xc_surface = XcSurfaceCreateForDrawable (dpy, drawable, visual, format, colormap);
|
||||
if (surface->xc_surface == NULL) {
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* XXX: We should really get this value from somewhere like Xft.dpy */
|
||||
surface->ppm = 3780;
|
||||
|
||||
surface->ref_count = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/* XXX: These definitions are 100% bogus. The problem that needs to be
|
||||
fixed is that Ic needs to export a real API for passing in
|
||||
formats. */
|
||||
#define PICT_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \
|
||||
((type) << 16) | \
|
||||
((a) << 12) | \
|
||||
((r) << 8) | \
|
||||
((g) << 4) | \
|
||||
((b)))
|
||||
|
||||
/*
|
||||
* gray/color formats use a visual index instead of argb
|
||||
*/
|
||||
#define PICT_VISFORMAT(bpp,type,vi) (((bpp) << 24) | \
|
||||
((type) << 16) | \
|
||||
((vi)))
|
||||
|
||||
#define PICT_TYPE_A 1
|
||||
#define PICT_TYPE_ARGB 2
|
||||
|
||||
#define PICT_FORMAT_COLOR(f) (PICT_FORMAT_TYPE(f) & 2)
|
||||
|
||||
/* 32bpp formats */
|
||||
|
||||
#define PICT_a8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,8,8,8,8)
|
||||
#define PICT_x8r8g8b8 PICT_FORMAT(32,PICT_TYPE_ARGB,0,8,8,8)
|
||||
#define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0)
|
||||
#define PICT_a1 PICT_FORMAT(1,PICT_TYPE_A,1,0,0,0)
|
||||
|
||||
static int
|
||||
_XrFormatBPP (XrFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case XrFormatA1:
|
||||
return 1;
|
||||
break;
|
||||
case XrFormatA8:
|
||||
return 8;
|
||||
break;
|
||||
case XrFormatRGB24:
|
||||
case XrFormatARGB32:
|
||||
default:
|
||||
return 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XrSurface *
|
||||
XrSurfaceCreateForImage (char *data,
|
||||
XrFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
XrSurface *surface;
|
||||
IcFormat icformat;
|
||||
IcImage *image;
|
||||
int bpp;
|
||||
|
||||
/* XXX: This all needs to change, (but IcFormatInit interface needs to change first) */
|
||||
switch (format) {
|
||||
case XrFormatARGB32:
|
||||
IcFormatInit (&icformat, PICT_a8r8g8b8);
|
||||
bpp = 32;
|
||||
break;
|
||||
case XrFormatRGB24:
|
||||
IcFormatInit (&icformat, PICT_x8r8g8b8);
|
||||
bpp = 32;
|
||||
break;
|
||||
case XrFormatA8:
|
||||
IcFormatInit (&icformat, PICT_a8);
|
||||
bpp = 8;
|
||||
break;
|
||||
case XrFormatA1:
|
||||
IcFormatInit (&icformat, PICT_a1);
|
||||
bpp = 1;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface = malloc(sizeof(XrSurface));
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
surface->dpy = NULL;
|
||||
surface->image_data = NULL;
|
||||
image = IcImageCreateForData ((IcBits *) data, &icformat, width, height, _XrFormatBPP (format), stride);
|
||||
if (image == NULL) {
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface->xc_surface = XcSurfaceCreateForIcImage (image);
|
||||
if (surface->xc_surface == NULL) {
|
||||
IcImageDestroy (image);
|
||||
free (surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assume a default until the user lets us know otherwise */
|
||||
surface->ppm = 3780;
|
||||
|
||||
surface->ref_count = 1;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
XrSurface *
|
||||
XrSurfaceCreateNextTo (XrSurface *neighbor, XrFormat format, int width, int height)
|
||||
{
|
||||
return XrSurfaceCreateNextToSolid (neighbor, format, width, height, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
_XrFormatDepth (XrFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case XrFormatA1:
|
||||
return 1;
|
||||
case XrFormatA8:
|
||||
return 8;
|
||||
case XrFormatRGB24:
|
||||
return 24;
|
||||
case XrFormatARGB32:
|
||||
default:
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
XrSurface *
|
||||
XrSurfaceCreateNextToSolid (XrSurface *neighbor,
|
||||
XrFormat format,
|
||||
int width,
|
||||
int height,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha)
|
||||
{
|
||||
XrSurface *surface = NULL;
|
||||
XrColor color;
|
||||
|
||||
/* XXX: CreateNextTo should perhaps move down to Xc, (then we
|
||||
could drop xrsurface->dpy as well) */
|
||||
if (neighbor->dpy) {
|
||||
Display *dpy = neighbor->dpy;
|
||||
int scr = DefaultScreen (dpy);
|
||||
|
||||
Pixmap pix = XCreatePixmap(dpy,
|
||||
DefaultRootWindow (dpy),
|
||||
width, height,
|
||||
_XrFormatDepth (format));
|
||||
|
||||
surface = XrSurfaceCreateForDrawable (dpy, pix,
|
||||
NULL,
|
||||
format,
|
||||
DefaultColormap (dpy, scr));
|
||||
/* XXX: huh? This should be fine since we already created a picture
|
||||
from the pixmap, right?? (Somehow, it seems to be causing some
|
||||
breakage).
|
||||
XFreePixmap(surface->dpy, pix);
|
||||
*/
|
||||
} else {
|
||||
char *data;
|
||||
int stride;
|
||||
|
||||
stride = ((width * _XrFormatBPP (format)) + 7) >> 3;
|
||||
data = malloc (stride * height);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
surface = XrSurfaceCreateForImage (data, format,
|
||||
width, height, stride);
|
||||
|
||||
/* lodge data in the surface structure to be freed with the surface */
|
||||
surface->image_data = data;
|
||||
}
|
||||
|
||||
/* XXX: Initializing the color in this way assumes
|
||||
non-pre-multiplied alpha. I'm not sure that that's what I want
|
||||
to do or not. */
|
||||
_XrColorInit (&color);
|
||||
_XrColorSetRGB (&color, red, green, blue);
|
||||
_XrColorSetAlpha (&color, alpha);
|
||||
_XrSurfaceFillRectangle (surface, XrOperatorSrc, &color, 0, 0, width, height);
|
||||
return surface;
|
||||
}
|
||||
|
||||
void
|
||||
_XrSurfaceReference(XrSurface *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
surface->ref_count++;
|
||||
}
|
||||
|
||||
void
|
||||
XrSurfaceDestroy(XrSurface *surface)
|
||||
{
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
surface->ref_count--;
|
||||
if (surface->ref_count)
|
||||
return;
|
||||
|
||||
surface->dpy = 0;
|
||||
|
||||
XcSurfaceDestroy (surface->xc_surface);
|
||||
surface->xc_surface = NULL;
|
||||
|
||||
if (surface->image_data)
|
||||
free(surface->image_data);
|
||||
surface->image_data = NULL;
|
||||
|
||||
free(surface);
|
||||
}
|
||||
|
||||
XrStatus
|
||||
XrSurfacePutImage (XrSurface *surface,
|
||||
char *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
XcSurfacePutImage (surface->xc_surface, data,
|
||||
width, height, stride);
|
||||
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
|
||||
/* XXX: Symmetry demands an XrSurfaceGetImage as well */
|
||||
|
||||
/* XXX: We may want to move to projective matrices at some point. If
|
||||
nothing else, that would eliminate the two different transform data
|
||||
structures we have here. */
|
||||
XrStatus
|
||||
XrSurfaceSetMatrix(XrSurface *surface, XrMatrix *matrix)
|
||||
{
|
||||
XTransform xtransform;
|
||||
|
||||
xtransform.matrix[0][0] = XDoubleToFixed(matrix->m[0][0]);
|
||||
xtransform.matrix[0][1] = XDoubleToFixed(matrix->m[1][0]);
|
||||
xtransform.matrix[0][2] = XDoubleToFixed(matrix->m[2][0]);
|
||||
|
||||
xtransform.matrix[1][0] = XDoubleToFixed(matrix->m[0][1]);
|
||||
xtransform.matrix[1][1] = XDoubleToFixed(matrix->m[1][1]);
|
||||
xtransform.matrix[1][2] = XDoubleToFixed(matrix->m[2][1]);
|
||||
|
||||
xtransform.matrix[2][0] = 0;
|
||||
xtransform.matrix[2][1] = 0;
|
||||
xtransform.matrix[2][2] = XDoubleToFixed(1);
|
||||
|
||||
XcSurfaceSetTransform(surface->xc_surface,
|
||||
&xtransform);
|
||||
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
|
||||
XrStatus
|
||||
XrSurfaceGetMatrix (XrSurface *surface, XrMatrix *matrix)
|
||||
{
|
||||
XTransform xtransform;
|
||||
|
||||
XcSurfaceGetTransform (surface->xc_surface, &xtransform);
|
||||
|
||||
matrix->m[0][0] = XFixedToDouble (xtransform.matrix[0][0]);
|
||||
matrix->m[1][0] = XFixedToDouble (xtransform.matrix[0][1]);
|
||||
matrix->m[2][0] = XFixedToDouble (xtransform.matrix[0][2]);
|
||||
|
||||
matrix->m[0][1] = XFixedToDouble (xtransform.matrix[1][0]);
|
||||
matrix->m[1][1] = XFixedToDouble (xtransform.matrix[1][1]);
|
||||
matrix->m[2][1] = XFixedToDouble (xtransform.matrix[1][2]);
|
||||
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
|
||||
XrStatus
|
||||
XrSurfaceSetFilter(XrSurface *surface, XrFilter filter)
|
||||
{
|
||||
XcSurfaceSetFilter(surface->xc_surface, filter);
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
|
||||
/* XXX: The Xc version of this function isn't quite working yet
|
||||
XrStatus
|
||||
XrSurfaceSetClipRegion (XrSurface *surface, Region region)
|
||||
{
|
||||
XcSurfaceSetClipRegion (surface->xc_surface, region);
|
||||
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
*/
|
||||
|
||||
XrStatus
|
||||
XrSurfaceSetRepeat (XrSurface *surface, int repeat)
|
||||
{
|
||||
XcSurfaceSetRepeat (surface->xc_surface, repeat);
|
||||
|
||||
return XrStatusSuccess;
|
||||
}
|
||||
|
||||
/* XXX: This function is going away, right? */
|
||||
Picture
|
||||
_XrSurfaceGetPicture(XrSurface *surface)
|
||||
{
|
||||
return XcSurfaceGetPicture(surface->xc_surface);
|
||||
}
|
||||
|
||||
void
|
||||
_XrSurfaceFillRectangle (XrSurface *surface,
|
||||
XrOperator operator,
|
||||
XrColor *color,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
XcFillRectangle (operator,
|
||||
surface->xc_surface,
|
||||
&color->xc_color,
|
||||
x, y,
|
||||
width, height);
|
||||
}
|
||||
|
||||
49
util/xr2cairo
Executable file
49
util/xr2cairo
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
argv0=`basename $0`
|
||||
echo "$argv0: Convert source code written for Xr to use Cairo instead." >&2
|
||||
echo "" >&2
|
||||
echo "Usage: $argv0 file [...]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xr2cairo() {
|
||||
file=$1
|
||||
backup=$file.xr
|
||||
|
||||
if [ -e $backup ]; then
|
||||
echo "Warning: Backup file $backup already exists --- not backing up this time." >&2
|
||||
else
|
||||
cp $file $backup
|
||||
fi
|
||||
sed -e '
|
||||
s/\(Xr[a-zA-Z]*\)RGB/\1Rgb/g
|
||||
s/\(Xr[a-zA-Z]*\)NextTo/\1Similar/g
|
||||
|
||||
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3_\4_\5\E/g
|
||||
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3_\4\E/g
|
||||
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3\E/g
|
||||
s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z0-9]\+\)/\Lcairo_\1_\2\E/g
|
||||
s/Xr\([A-Z]\+[a-z]\+\)/\Lcairo_\1\E/g
|
||||
|
||||
s/\(cairo_\(operator\|status\|fill_rule\|line_cap\|line_join\|filter\|format\)_[a-z0-9_]\{2,\}\)/\U\1/g
|
||||
|
||||
s/cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)$/cairo_\1_t/g
|
||||
s/cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)\([^_]\)/cairo_\1_t\2/g
|
||||
s/_cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)_t/cairo_\1/g
|
||||
s/cairo_state/cairo_t/g
|
||||
s/_cairo_t/cairo/g
|
||||
|
||||
s/Xr\.h/cairo.h/g
|
||||
|
||||
' $backup > $file
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
file=$1
|
||||
shift
|
||||
xr2cairo $file
|
||||
done
|
||||
|
||||
Loading…
Add table
Reference in a new issue